rendezvous.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2010 by Alexander Barton (alex@barton.de)
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * Please read the file COPYING, README and AUTHORS for more information.
  10. *
  11. * Rendezvous service registration.
  12. *
  13. * Supported APIs are:
  14. * - Apple Mac OS X
  15. * - Howl
  16. */
  17. #include "portab.h"
  18. #ifdef ZEROCONF
  19. #include "imp.h"
  20. #include <assert.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #ifdef HAVE_MACH_PORT_H
  24. #include "mach/port.h"
  25. #include "mach/message.h"
  26. #endif
  27. #ifdef HAVE_DNSSERVICEDISCOVERY_DNSSERVICEDISCOVERY_H
  28. #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
  29. #endif
  30. #ifdef HAVE_RENDEZVOUS_RENDEZVOUS_H
  31. #include <rendezvous/rendezvous.h>
  32. #endif
  33. #include "defines.h"
  34. #include "conn.h"
  35. #include "conf.h"
  36. #include "log.h"
  37. #include "exp.h"
  38. #include "rendezvous.h"
  39. #if defined(HAVE_DNSSERVICEREGISTRATIONCREATE)
  40. # define APPLE
  41. #elif defined(HAVE_SW_DISCOVERY_INIT)
  42. # define HOWL
  43. #else
  44. # error "Can't detect Rendezvous API!?"
  45. #endif
  46. #define MAX_RENDEZVOUS 1000
  47. typedef struct _service
  48. {
  49. char Desc[CLIENT_ID_LEN];
  50. #ifdef APPLE
  51. dns_service_discovery_ref Discovery_Ref;
  52. mach_port_t Mach_Port;
  53. #endif
  54. #ifdef HOWL
  55. sw_discovery_oid Id;
  56. #endif
  57. } SERVICE;
  58. static SERVICE My_Rendezvous[MAX_RENDEZVOUS];
  59. static void Unregister( int Idx );
  60. /* -- Apple API -- */
  61. #ifdef APPLE
  62. #define MAX_MACH_MSG_SIZE 512
  63. static void Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, void *Context );
  64. #endif /* Apple */
  65. /* -- Howl API -- */
  66. #ifdef HOWL
  67. static sw_discovery My_Discovery_Session = NULL;
  68. static sw_salt My_Salt;
  69. static sw_result HOWL_API Registration_Reply_Handler( sw_discovery Session, sw_discovery_publish_status Status, sw_discovery_oid Id, sw_opaque Extra );
  70. #endif /* Howl */
  71. GLOBAL void Rendezvous_Init( void )
  72. {
  73. /* Initialize structures */
  74. int i;
  75. #ifdef HOWL
  76. if( sw_discovery_init( &My_Discovery_Session ) != SW_OKAY )
  77. {
  78. Log( LOG_EMERG, "Can't initialize Rendezvous (Howl): sw_discovery_init() failed!" );
  79. Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
  80. exit( 1 );
  81. }
  82. if( sw_discovery_salt( My_Discovery_Session, &My_Salt ) != SW_OKAY )
  83. {
  84. Log( LOG_EMERG, "Can't initialize Rendezvous (Howl): sw_discovery_salt() failed!" );
  85. Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
  86. exit( 1 );
  87. }
  88. #endif
  89. for( i = 0; i < MAX_RENDEZVOUS; i++ ) My_Rendezvous[i].Desc[0] = '\0';
  90. } /* Rendezvous_Init */
  91. GLOBAL void Rendezvous_Exit( void )
  92. {
  93. /* Clean up & exit module */
  94. int i;
  95. for( i = 0; i < MAX_RENDEZVOUS; i++ )
  96. {
  97. if( My_Rendezvous[i].Desc[0] ) Unregister( i );
  98. }
  99. #ifdef HOWL
  100. sw_discovery_fina( My_Discovery_Session );
  101. #endif
  102. } /* Rendezvous_Exit */
  103. /**
  104. * Register ZeroConf service
  105. */
  106. GLOBAL bool Rendezvous_Register( char *Name, char *Type, UINT16 Port )
  107. {
  108. int i;
  109. if (Conf_NoZeroConf)
  110. return true;
  111. /* Search free port structure */
  112. for( i = 0; i < MAX_RENDEZVOUS; i++ ) if( ! My_Rendezvous[i].Desc[0] ) break;
  113. if( i >= MAX_RENDEZVOUS )
  114. {
  115. Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: limit (%d) reached!", Name, MAX_RENDEZVOUS );
  116. return false;
  117. }
  118. strlcpy( My_Rendezvous[i].Desc, Name, sizeof( My_Rendezvous[i].Desc ));
  119. #ifdef APPLE
  120. /* Register new service */
  121. My_Rendezvous[i].Discovery_Ref = DNSServiceRegistrationCreate( Name, Type, "", htonl( Port ), "", Registration_Reply_Handler, &My_Rendezvous[i] );
  122. if( ! My_Rendezvous[i].Discovery_Ref )
  123. {
  124. Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: can't register service!", My_Rendezvous[i].Desc );
  125. My_Rendezvous[i].Desc[0] = '\0';
  126. return false;
  127. }
  128. /* Get and save the corresponding Mach Port */
  129. My_Rendezvous[i].Mach_Port = DNSServiceDiscoveryMachPort( My_Rendezvous[i].Discovery_Ref );
  130. if( ! My_Rendezvous[i].Mach_Port )
  131. {
  132. Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: got no Mach Port!", My_Rendezvous[i].Desc );
  133. /* Here we actually leek a descriptor :-( */
  134. My_Rendezvous[i].Discovery_Ref = 0;
  135. My_Rendezvous[i].Desc[0] = '\0';
  136. return false;
  137. }
  138. #endif /* Apple */
  139. #ifdef HOWL
  140. if( sw_discovery_publish( My_Discovery_Session, 0, Name, Type, NULL, NULL, Port, NULL, 0, Registration_Reply_Handler, &My_Rendezvous[i], &My_Rendezvous[i].Id ) != SW_OKAY )
  141. {
  142. Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: can't register service!", My_Rendezvous[i].Desc );
  143. My_Rendezvous[i].Desc[0] = '\0';
  144. return false;
  145. }
  146. #endif /* Howl */
  147. Log( LOG_DEBUG, "Rendezvous: Registering \"%s\" ...", My_Rendezvous[i].Desc );
  148. return true;
  149. } /* Rendezvous_Register */
  150. GLOBAL bool Rendezvous_Unregister( char *Name )
  151. {
  152. /* Unregister service from rendezvous */
  153. int i;
  154. bool ok;
  155. ok = false;
  156. for( i = 0; i < MAX_RENDEZVOUS; i++ )
  157. {
  158. if( strcmp( Name, My_Rendezvous[i].Desc ) == 0 )
  159. {
  160. Unregister( i );
  161. ok = true;
  162. }
  163. }
  164. return ok;
  165. } /* Rendezvous_Unregister */
  166. GLOBAL void Rendezvous_UnregisterListeners( void )
  167. {
  168. /* Unregister all our listening sockets from Rendezvous */
  169. int i;
  170. for( i = 0; i < MAX_RENDEZVOUS; i++ )
  171. {
  172. if( My_Rendezvous[i].Desc[0] ) Unregister( i );
  173. }
  174. } /* Rendezvous_UnregisterListeners */
  175. GLOBAL void Rendezvous_Handler( void )
  176. {
  177. /* Handle all Rendezvous stuff; this function must be called
  178. * periodically from the run loop of the main program */
  179. #ifdef APPLE
  180. int i;
  181. char buffer[MAX_MACH_MSG_SIZE];
  182. mach_msg_return_t result;
  183. mach_msg_header_t *msg;
  184. for( i = 0; i < MAX_RENDEZVOUS; i++ )
  185. {
  186. if( ! My_Rendezvous[i].Discovery_Ref ) continue;
  187. /* Read message from Mach Port */
  188. msg = (mach_msg_header_t *)buffer;
  189. result = mach_msg( msg, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, MAX_MACH_MSG_SIZE, My_Rendezvous[i].Mach_Port, 1, 0 );
  190. /* Handle message */
  191. if( result == MACH_MSG_SUCCESS ) DNSServiceDiscovery_handleReply( msg );
  192. #ifdef DEBUG
  193. else if( result != MACH_RCV_TIMED_OUT ) Log( LOG_DEBUG, "mach_msg(): %ld", (long)result );
  194. #endif /* Debug */
  195. }
  196. #endif /* Apple */
  197. #ifdef HOWL
  198. sw_ulong msecs = 10;
  199. sw_salt_step( My_Salt, &msecs );
  200. #endif
  201. } /* Rendezvous_Handler */
  202. static void Unregister( int Idx )
  203. {
  204. /* Unregister service */
  205. #ifdef APPLE
  206. DNSServiceDiscoveryDeallocate( My_Rendezvous[Idx].Discovery_Ref );
  207. #endif /* Apple */
  208. #ifdef HOWL
  209. if( sw_discovery_cancel( My_Discovery_Session, My_Rendezvous[Idx].Id ) != SW_OKAY )
  210. {
  211. Log( LOG_ERR, "Rendezvous: Failed to unregister \"%s\"!", My_Rendezvous[Idx].Desc );
  212. return;
  213. }
  214. #endif /* Howl */
  215. Log( LOG_INFO, "Unregistered \"%s\" from Rendezvous.", My_Rendezvous[Idx].Desc );
  216. My_Rendezvous[Idx].Desc[0] = '\0';
  217. } /* Unregister */
  218. /* -- Apple API -- */
  219. #ifdef APPLE
  220. static void Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, void *Context )
  221. {
  222. SERVICE *s = (SERVICE *)Context;
  223. char txt[50];
  224. if( ErrCode == kDNSServiceDiscoveryNoError )
  225. {
  226. /* Success! */
  227. Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
  228. return;
  229. }
  230. switch( ErrCode )
  231. {
  232. case kDNSServiceDiscoveryAlreadyRegistered:
  233. strcpy( txt, "name already registered!" );
  234. break;
  235. case kDNSServiceDiscoveryNameConflict:
  236. strcpy( txt, "name conflict!" );
  237. break;
  238. default:
  239. snprintf(txt, sizeof txt, "error code %ld!",
  240. (long)ErrCode);
  241. }
  242. Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
  243. s->Desc[0] = '\0';
  244. } /* Registration_Reply_Handler */
  245. #endif /* Apple */
  246. /* -- Howl API -- */
  247. #ifdef HOWL
  248. static sw_result HOWL_API Registration_Reply_Handler( sw_discovery Session, sw_discovery_publish_status Status, UNUSED sw_discovery_oid Id, sw_opaque Extra )
  249. {
  250. SERVICE *s = (SERVICE *)Extra;
  251. char txt[50];
  252. assert( Session == My_Discovery_Session );
  253. assert( Extra != NULL );
  254. if( Status == SW_DISCOVERY_PUBLISH_STARTED || Status == SW_DISCOVERY_PUBLISH_STOPPED )
  255. {
  256. /* Success! */
  257. Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
  258. return SW_OKAY;
  259. }
  260. switch( Status )
  261. {
  262. case SW_DISCOVERY_PUBLISH_NAME_COLLISION:
  263. strcpy( txt, "name conflict!" );
  264. break;
  265. default:
  266. snprintf(txt, sizeof txt, "error code %ld!",
  267. (long)Status);
  268. }
  269. Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
  270. s->Desc[0] = '\0';
  271. return SW_OKAY;
  272. } /* Registration_Reply_Handler */
  273. #endif /* Howl */
  274. #endif /* ZEROCONF */
  275. /* -eof- */