2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2010 by Alexander Barton (alex@barton.de)
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.
11 * Rendezvous service registration.
30 #ifdef HAVE_MACH_PORT_H
31 #include "mach/port.h"
32 #include "mach/message.h"
35 #ifdef HAVE_DNSSERVICEDISCOVERY_DNSSERVICEDISCOVERY_H
36 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
39 #ifdef HAVE_RENDEZVOUS_RENDEZVOUS_H
40 #include <rendezvous/rendezvous.h>
49 #include "rendezvous.h"
52 #if defined(HAVE_DNSSERVICEREGISTRATIONCREATE)
54 #elif defined(HAVE_SW_DISCOVERY_INIT)
57 # error "Can't detect Rendezvous API!?"
61 #define MAX_RENDEZVOUS 1000
63 typedef struct _service
65 char Desc[CLIENT_ID_LEN];
67 dns_service_discovery_ref Discovery_Ref;
68 mach_port_t Mach_Port;
75 static SERVICE My_Rendezvous[MAX_RENDEZVOUS];
78 static void Unregister( int Idx );
85 #define MAX_MACH_MSG_SIZE 512
87 static void Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, void *Context );
96 static sw_discovery My_Discovery_Session = NULL;
97 static sw_salt My_Salt;
99 static sw_result HOWL_API Registration_Reply_Handler( sw_discovery Session, sw_discovery_publish_status Status, sw_discovery_oid Id, sw_opaque Extra );
104 GLOBAL void Rendezvous_Init( void )
106 /* Initialize structures */
110 for (i = 0; i < MAX_RENDEZVOUS; i++)
111 My_Rendezvous[i].Desc[0] = '\0';
117 if( sw_discovery_init( &My_Discovery_Session ) != SW_OKAY )
119 Log( LOG_EMERG, "Can't initialize Rendezvous (Howl): sw_discovery_init() failed!" );
120 Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
124 if( sw_discovery_salt( My_Discovery_Session, &My_Salt ) != SW_OKAY )
126 Log( LOG_EMERG, "Can't initialize Rendezvous (Howl): sw_discovery_salt() failed!" );
127 Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
131 } /* Rendezvous_Init */
134 GLOBAL void Rendezvous_Exit( void )
136 /* Clean up & exit module */
140 for( i = 0; i < MAX_RENDEZVOUS; i++ )
142 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
146 sw_discovery_fina( My_Discovery_Session );
148 } /* Rendezvous_Exit */
152 * Register ZeroConf service
154 GLOBAL bool Rendezvous_Register( char *Name, char *Type, UINT16 Port )
161 /* Search free port structure */
162 for( i = 0; i < MAX_RENDEZVOUS; i++ ) if( ! My_Rendezvous[i].Desc[0] ) break;
163 if( i >= MAX_RENDEZVOUS )
165 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: limit (%d) reached!", Name, MAX_RENDEZVOUS );
168 strlcpy( My_Rendezvous[i].Desc, Name, sizeof( My_Rendezvous[i].Desc ));
171 /* Register new service */
172 My_Rendezvous[i].Discovery_Ref = DNSServiceRegistrationCreate( Name, Type, "", htonl( Port ), "", Registration_Reply_Handler, &My_Rendezvous[i] );
173 if( ! My_Rendezvous[i].Discovery_Ref )
175 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: can't register service!", My_Rendezvous[i].Desc );
176 My_Rendezvous[i].Desc[0] = '\0';
180 /* Get and save the corresponding Mach Port */
181 My_Rendezvous[i].Mach_Port = DNSServiceDiscoveryMachPort( My_Rendezvous[i].Discovery_Ref );
182 if( ! My_Rendezvous[i].Mach_Port )
184 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: got no Mach Port!", My_Rendezvous[i].Desc );
185 /* Here we actually leek a descriptor :-( */
186 My_Rendezvous[i].Discovery_Ref = 0;
187 My_Rendezvous[i].Desc[0] = '\0';
193 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 )
195 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: can't register service!", My_Rendezvous[i].Desc );
196 My_Rendezvous[i].Desc[0] = '\0';
201 Log( LOG_DEBUG, "Rendezvous: Registering \"%s\" ...", My_Rendezvous[i].Desc );
203 } /* Rendezvous_Register */
206 GLOBAL bool Rendezvous_Unregister( char *Name )
208 /* Unregister service from rendezvous */
214 for( i = 0; i < MAX_RENDEZVOUS; i++ )
216 if( strcmp( Name, My_Rendezvous[i].Desc ) == 0 )
224 } /* Rendezvous_Unregister */
227 GLOBAL void Rendezvous_UnregisterListeners( void )
229 /* Unregister all our listening sockets from Rendezvous */
233 for( i = 0; i < MAX_RENDEZVOUS; i++ )
235 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
237 } /* Rendezvous_UnregisterListeners */
240 GLOBAL void Rendezvous_Handler( void )
242 /* Handle all Rendezvous stuff; this function must be called
243 * periodically from the run loop of the main program */
250 char buffer[MAX_MACH_MSG_SIZE];
251 mach_msg_return_t result;
252 mach_msg_header_t *msg;
254 for( i = 0; i < MAX_RENDEZVOUS; i++ )
256 if( ! My_Rendezvous[i].Discovery_Ref ) continue;
258 /* Read message from Mach Port */
259 msg = (mach_msg_header_t *)buffer;
260 result = mach_msg( msg, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, MAX_MACH_MSG_SIZE, My_Rendezvous[i].Mach_Port, 1, 0 );
263 if( result == MACH_MSG_SUCCESS ) DNSServiceDiscovery_handleReply( msg );
265 else if( result != MACH_RCV_TIMED_OUT ) Log( LOG_DEBUG, "mach_msg(): %ld", (long)result );
272 sw_salt_step( My_Salt, &msecs );
274 } /* Rendezvous_Handler */
277 static void Unregister( int Idx )
279 /* Unregister service */
282 DNSServiceDiscoveryDeallocate( My_Rendezvous[Idx].Discovery_Ref );
286 if( sw_discovery_cancel( My_Discovery_Session, My_Rendezvous[Idx].Id ) != SW_OKAY )
288 Log( LOG_ERR, "Rendezvous: Failed to unregister \"%s\"!", My_Rendezvous[Idx].Desc );
293 Log( LOG_INFO, "Unregistered \"%s\" from Rendezvous.", My_Rendezvous[Idx].Desc );
294 My_Rendezvous[Idx].Desc[0] = '\0';
298 /* -- Apple API -- */
303 static void Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, void *Context )
305 SERVICE *s = (SERVICE *)Context;
308 if( ErrCode == kDNSServiceDiscoveryNoError )
311 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
317 case kDNSServiceDiscoveryAlreadyRegistered:
318 strcpy( txt, "name already registered!" );
320 case kDNSServiceDiscoveryNameConflict:
321 strcpy( txt, "name conflict!" );
324 snprintf(txt, sizeof txt, "error code %ld!",
328 Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
330 } /* Registration_Reply_Handler */
341 static sw_result HOWL_API Registration_Reply_Handler( sw_discovery Session, sw_discovery_publish_status Status, UNUSED sw_discovery_oid Id, sw_opaque Extra )
343 SERVICE *s = (SERVICE *)Extra;
346 assert( Session == My_Discovery_Session );
347 assert( Extra != NULL );
349 if( Status == SW_DISCOVERY_PUBLISH_STARTED || Status == SW_DISCOVERY_PUBLISH_STOPPED )
352 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
358 case SW_DISCOVERY_PUBLISH_NAME_COLLISION:
359 strcpy( txt, "name conflict!" );
362 snprintf(txt, sizeof txt, "error code %ld!",
366 Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
370 } /* Registration_Reply_Handler */
376 #endif /* ZEROCONF */