zeroconf_howl.cpp

Go to the documentation of this file.
00001 /* libobby - Network text editing library
00002  * Copyright (C) 2005-2006 0x539 dev group
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public
00015  * License along with this program; if not, write to the Free
00016  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 #include <stdexcept>
00020 #include <sstream>
00021 
00022 #include "zeroconf_howl.hpp"
00023 
00024 namespace obby
00025 {
00026 
00027 zeroconf_howl::zeroconf_howl()
00028 {
00029         if (sw_discovery_init(&m_session) != SW_OKAY)
00030                 throw std::runtime_error("sw_discovery_init() failed.");
00031         if (sw_discovery_salt(m_session, &m_salt) != SW_OKAY)
00032                 throw std::runtime_error("sw_discovery_salt() failed.");
00033 }
00034 
00035 zeroconf_howl::~zeroconf_howl()
00036 {
00037         unpublish_all();
00038         sw_discovery_fina(m_session);
00039 }
00040 
00041 void zeroconf_howl::publish(const std::string& name, unsigned int port)
00042 {
00043         sw_discovery_oid oid;
00044         sw_result result;
00045 
00046         /* This publishes a record for other users of this library within the
00047          * default domain (.local) */
00048         if((result = sw_discovery_publish(m_session, 0, name.c_str(),
00049                 "_lobby._tcp.", NULL, NULL, port, NULL, 0,
00050                 &zeroconf_howl::handle_publish_reply,
00051                 static_cast<sw_opaque>(this), &oid)) != SW_OKAY)
00052         {
00053                 std::stringstream stream;
00054                 stream << "sw_discovery_publish(...) failed: " << result;
00055                 throw std::runtime_error(stream.str());
00056         }
00057         else
00058         {
00059                 m_published[name] = oid;
00060         }
00061 }
00062 
00063 void zeroconf_howl::unpublish(const std::string& name)
00064 {
00065         if(!m_published[name])
00066         {
00067                 std::stringstream stream;
00068                 stream << "unpublish not possible for \"" << name << "\"";
00069                 throw std::runtime_error(stream.str());
00070         }
00071         else
00072         {
00073                 sw_discovery_cancel(m_session, m_published[name]);
00074         }
00075         m_published.erase(name);
00076 }
00077 
00078 void zeroconf_howl::unpublish_all()
00079 {
00080         std::map<std::string, sw_discovery_oid>::iterator i;
00081         for(i = m_published.begin(); i != m_published.end(); ++i)
00082                 sw_discovery_cancel(m_session, i->second);
00083         m_published.clear();
00084 }
00085 
00086 void zeroconf_howl::discover()
00087 {
00088         sw_discovery_oid oid;
00089         sw_result result;
00090 
00091         if ((result = sw_discovery_browse(m_session, 0, "_lobby._tcp", NULL,
00092                 &zeroconf_howl::handle_browse_reply,
00093                 static_cast<sw_opaque>(this), &oid)) != SW_OKAY)
00094         {
00095                 std::stringstream stream;
00096                 stream << "discover failed: " << result;
00097                 throw std::runtime_error(stream.str());
00098         }
00099 }
00100 
00101 void zeroconf_howl::select()
00102 {
00103         sw_discovery_run(m_session);
00104 }
00105 
00106 void zeroconf_howl::select(unsigned int msecs)
00107 {
00108         sw_ulong ms = msecs;
00109         sw_salt_step(m_salt, &ms);
00110 }
00111 
00112 sw_result zeroconf_howl::handle_publish_reply(sw_discovery discovery,
00113         sw_discovery_oid oid, sw_discovery_publish_status status,
00114         sw_opaque extra)
00115 {
00116         if (status != SW_OKAY)
00117         {
00118                 std::stringstream stream;
00119                 stream << "publish failed: " << status;
00120                 throw std::runtime_error(stream.str());
00121         }
00122         return SW_OKAY;
00123 }
00124 
00125 sw_result zeroconf_howl::handle_browse_reply(sw_discovery discovery,
00126         sw_discovery_oid oid, sw_discovery_browse_status status,
00127         sw_uint32 interface_index, sw_const_string name, sw_const_string type,
00128         sw_const_string domain, sw_opaque extra)
00129 {
00130         sw_discovery session = static_cast<zeroconf_howl*>(extra)->m_session;
00131 
00132         switch(status)
00133         {
00134                 case SW_DISCOVERY_BROWSE_INVALID:
00135                 {
00136                         throw std::runtime_error(
00137                                 "sw_discovery failed within the callback");
00138                         break;
00139                 }
00140 
00141                 case SW_DISCOVERY_BROWSE_ADD_SERVICE:
00142                 {
00143                         sw_result result;
00144                         if ((result = sw_discovery_resolve(session,
00145                                 interface_index, name, type, domain,
00146                                 &zeroconf_howl::handle_resolve_reply,
00147                                 extra, &oid)) != SW_OKAY)
00148                         {
00149                                 std::stringstream stream;
00150                                 stream << "resolve failed: " << result;
00151                                 throw std::runtime_error(stream.str());
00152                         }
00153                         break;
00154                 }
00155 
00156                 case SW_DISCOVERY_BROWSE_REMOVE_SERVICE:
00157                 {
00158                         static_cast<zeroconf_howl*>(
00159                                 extra)->leave_event().emit(name);
00160                         break;
00161                 }
00162         }
00163 
00164         return SW_OKAY;
00165 }
00166 
00167 sw_result zeroconf_howl::handle_resolve_reply(sw_discovery discovery,
00168         sw_discovery_oid oid, sw_uint32 interface_index, sw_const_string name,
00169         sw_const_string type, sw_const_string domain, sw_ipv4_address address,
00170         sw_port port, sw_octets text_record, sw_ulong text_record_len,
00171         sw_opaque extra)
00172 {
00173         // At least newer revisions of OS X emit 0.0.0.0 as a second pseudo
00174         // entry when discovering the local host as the IPv6 address gets
00175         // parsed as a IPv4 address anywhere within Howl which does not yet
00176         // support service discovery on IPv6.
00177         uint32_t ip(sw_ipv4_address_saddr(address));
00178         if(ip != 0)
00179                 static_cast<zeroconf_howl*>(extra)->discover_event().emit(
00180                         name, net6::ipv4_address::create_from_address(
00181                         ip, port));
00182         return SW_OKAY;
00183 }
00184 
00185 }
00186 

Generated on Fri Jan 11 10:01:32 2008 for obby by  doxygen 1.5.1