2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2004 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.
24 static char UNUSED id[] = "$Id: rendezvous.c,v 1.3 2004/12/26 00:14:33 alex Exp $";
32 #ifdef HAVE_MACH_PORT_H
33 #include "mach/port.h"
34 #include "mach/message.h"
37 #ifdef HAVE_DNSSERVICEDISCOVERY_DNSSERVICEDISCOVERY_H
38 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
41 #ifdef HAVE_RENDEZVOUS_RENDEZVOUS_H
42 #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 LOCAL SERVICE My_Rendezvous[MAX_RENDEZVOUS];
78 LOCAL VOID Unregister( INT Idx );
85 #define MAX_MACH_MSG_SIZE 512
87 LOCAL VOID Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, VOID *Context );
98 LOCAL sw_discovery My_Discovery_Session = NULL;
99 LOCAL pthread_t My_Howl_Thread;
100 LOCAL BOOLEAN My_Howl_Thread_Created = FALSE;
102 LOCAL sw_result HOWL_API Registration_Reply_Handler( sw_discovery Session, sw_discovery_publish_status Status, sw_discovery_oid Id, sw_opaque Extra );
104 LOCAL VOID* Howl_Thread( VOID *x );
109 GLOBAL VOID Rendezvous_Init( VOID )
111 /* Initialize structures */
116 if( sw_discovery_init( &My_Discovery_Session ) != SW_OKAY )
118 Log( LOG_EMERG, "Can't initialize Rendezvous (Howl): sw_discovery_init() failed!" );
119 Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
124 for( i = 0; i < MAX_RENDEZVOUS; i++ ) My_Rendezvous[i].Desc[0] = '\0';
125 } /* Rendezvous_Init */
128 GLOBAL VOID Rendezvous_Exit( VOID )
130 /* Clean up & exit module */
134 for( i = 0; i < MAX_RENDEZVOUS; i++ )
136 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
140 if( My_Howl_Thread_Created )
142 Log( LOG_DEBUG, "Rendezvous: Canceling management thread ..." );
143 pthread_cancel( My_Howl_Thread );
146 sw_discovery_fina( My_Discovery_Session );
148 } /* Rendezvous_Exit */
151 GLOBAL BOOLEAN Rendezvous_Register( CHAR *Name, CHAR *Type, UINT Port )
153 /* Register new service */
157 /* Search free port structure */
158 for( i = 0; i < MAX_RENDEZVOUS; i++ ) if( ! My_Rendezvous[i].Desc[0] ) break;
159 if( i >= MAX_RENDEZVOUS )
161 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: limit (%d) reached!", Name, MAX_RENDEZVOUS );
164 strlcpy( My_Rendezvous[i].Desc, Name, sizeof( My_Rendezvous[i].Desc ));
167 /* Register new service */
168 My_Rendezvous[i].Discovery_Ref = DNSServiceRegistrationCreate( Name, Type, "", htonl( Port ), "", Registration_Reply_Handler, &My_Rendezvous[i] );
169 if( ! My_Rendezvous[i].Discovery_Ref )
171 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: can't register service!", My_Rendezvous[i].Desc );
172 My_Rendezvous[i].Desc[0] = '\0';
176 /* Get and save the corresponding Mach Port */
177 My_Rendezvous[i].Mach_Port = DNSServiceDiscoveryMachPort( My_Rendezvous[i].Discovery_Ref );
178 if( ! My_Rendezvous[i].Mach_Port )
180 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: got no Mach Port!", My_Rendezvous[i].Desc );
181 /* Here we actually leek a descriptor :-( */
182 My_Rendezvous[i].Discovery_Ref = 0;
183 My_Rendezvous[i].Desc[0] = '\0';
189 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 )
191 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: can't register service!", My_Rendezvous[i].Desc );
192 My_Rendezvous[i].Desc[0] = '\0';
197 Log( LOG_DEBUG, "Rendezvous: Registering \"%s\" ...", My_Rendezvous[i].Desc );
199 } /* Rendezvous_Register */
202 GLOBAL BOOLEAN Rendezvous_Unregister( CHAR *Name )
204 /* Unregister service from rendezvous */
210 for( i = 0; i < MAX_RENDEZVOUS; i++ )
212 if( strcmp( Name, My_Rendezvous[i].Desc ) == 0 )
220 } /* Rendezvous_Unregister */
223 GLOBAL VOID Rendezvous_UnregisterListeners( VOID )
225 /* Unregister all our listening sockets from Rendezvous */
229 for( i = 0; i < MAX_RENDEZVOUS; i++ )
231 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
233 } /* Rendezvous_UnregisterListeners */
236 GLOBAL VOID Rendezvous_Handler( VOID )
238 /* Handle all Rendezvous stuff; this function must be called
239 * periodically from the run loop of the main program */
243 CHAR buffer[MAX_MACH_MSG_SIZE];
244 mach_msg_return_t result;
245 mach_msg_header_t *msg;
247 for( i = 0; i < MAX_RENDEZVOUS; i++ )
249 if( ! My_Rendezvous[i].Discovery_Ref ) continue;
251 /* Read message from Mach Port */
252 msg = (mach_msg_header_t *)buffer;
253 result = mach_msg( msg, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, MAX_MACH_MSG_SIZE, My_Rendezvous[i].Mach_Port, 1, 0 );
256 if( result == MACH_MSG_SUCCESS ) DNSServiceDiscovery_handleReply( msg );
258 else if( result != MACH_RCV_TIMED_OUT ) Log( LOG_DEBUG, "mach_msg(): %ld", (LONG)result );
264 if( My_Discovery_Session != NULL && My_Howl_Thread_Created == FALSE )
266 /* Create POSIX thread for sw_discovery_run() */
267 Log( LOG_DEBUG, "Rendezvous: Creating management thread ..." );
268 pthread_create( &My_Howl_Thread, NULL, Howl_Thread, NULL );
269 My_Howl_Thread_Created = TRUE;
272 } /* Rendezvous_Handler */
275 LOCAL VOID Unregister( INT Idx )
277 /* Unregister service */
280 DNSServiceDiscoveryDeallocate( My_Rendezvous[Idx].Discovery_Ref );
284 if( sw_discovery_cancel( My_Discovery_Session, My_Rendezvous[Idx].Id ) != SW_OKAY )
286 Log( LOG_ERR, "Rendezvous: Failed to unregister \"%s\"!", My_Rendezvous[Idx].Desc );
291 Log( LOG_INFO, "Unregistered \"%s\" from Rendezvous.", My_Rendezvous[Idx].Desc );
292 My_Rendezvous[Idx].Desc[0] = '\0';
296 /* -- Apple API -- */
301 LOCAL VOID Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, VOID *Context )
303 SERVICE *s = (SERVICE *)Context;
306 if( ErrCode == kDNSServiceDiscoveryNoError )
309 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
315 case kDNSServiceDiscoveryAlreadyRegistered:
316 strcpy( txt, "name already registered!" );
318 case kDNSServiceDiscoveryNameConflict:
319 strcpy( txt, "name conflict!" );
322 sprintf( txt, "error code %ld!", (LONG)ErrCode );
325 Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
327 } /* Registration_Reply_Handler */
338 LOCAL sw_result HOWL_API Registration_Reply_Handler( sw_discovery Session, sw_discovery_publish_status Status, UNUSED sw_discovery_oid Id, sw_opaque Extra )
340 SERVICE *s = (SERVICE *)Extra;
343 assert( Session == My_Discovery_Session );
344 assert( Extra != NULL );
346 if( Status == SW_DISCOVERY_PUBLISH_STARTED || Status == SW_DISCOVERY_PUBLISH_STOPPED )
349 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
355 case SW_DISCOVERY_PUBLISH_NAME_COLLISION:
356 strcpy( txt, "name conflict!" );
359 sprintf( txt, "error code %ld!", (LONG)Status );
362 Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
366 } /* Registration_Reply_Handler */
369 LOCAL VOID *Howl_Thread( VOID *x )
372 sw_discovery_run( My_Discovery_Session );
373 pthread_exit( NULL );
380 #endif /* RENDEZVOUS */