00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
00047
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
00174
00175
00176
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