Blob


1 /*
2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2004 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 */
19 #include "portab.h"
21 #ifdef RENDEZVOUS
24 static char UNUSED id[] = "$Id: rendezvous.c,v 1.5 2005/03/19 18:43:49 fw Exp $";
26 #include "imp.h"
27 #include <assert.h>
29 #include <stdio.h>
30 #include <string.h>
32 #ifdef HAVE_MACH_PORT_H
33 #include "mach/port.h"
34 #include "mach/message.h"
35 #endif
37 #ifdef HAVE_DNSSERVICEDISCOVERY_DNSSERVICEDISCOVERY_H
38 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
39 #endif
41 #ifdef HAVE_RENDEZVOUS_RENDEZVOUS_H
42 #include <rendezvous/rendezvous.h>
43 #endif
45 #include "defines.h"
46 #include "log.h"
48 #include "exp.h"
49 #include "rendezvous.h"
52 #if defined(HAVE_DNSSERVICEREGISTRATIONCREATE)
53 # define APPLE
54 #elif defined(HAVE_SW_DISCOVERY_INIT)
55 # define HOWL
56 #else
57 # error "Can't detect Rendezvous API!?"
58 #endif
61 #define MAX_RENDEZVOUS 1000
63 typedef struct _service
64 {
65 char Desc[CLIENT_ID_LEN];
66 #ifdef APPLE
67 dns_service_discovery_ref Discovery_Ref;
68 mach_port_t Mach_Port;
69 #endif
70 #ifdef HOWL
71 sw_discovery_oid Id;
72 #endif
73 } SERVICE;
75 LOCAL SERVICE My_Rendezvous[MAX_RENDEZVOUS];
78 LOCAL void Unregister( int Idx );
81 /* -- Apple API -- */
83 #ifdef APPLE
85 #define MAX_MACH_MSG_SIZE 512
87 LOCAL void Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, void *Context );
89 #endif /* Apple */
92 /* -- Howl API -- */
94 #ifdef HOWL
96 LOCAL sw_discovery My_Discovery_Session = NULL;
97 LOCAL sw_salt My_Salt;
99 LOCAL sw_result HOWL_API Registration_Reply_Handler( sw_discovery Session, sw_discovery_publish_status Status, sw_discovery_oid Id, sw_opaque Extra );
101 #endif /* Howl */
104 GLOBAL void Rendezvous_Init( void )
106 /* Initialize structures */
108 int i;
110 #ifdef HOWL
111 if( sw_discovery_init( &My_Discovery_Session ) != SW_OKAY )
113 Log( LOG_EMERG, "Can't initialize Rendezvous (Howl): sw_discovery_init() failed!" );
114 Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
115 exit( 1 );
118 if( sw_discovery_salt( My_Discovery_Session, &My_Salt ) != SW_OKAY )
120 Log( LOG_EMERG, "Can't initialize Rendezvous (Howl): sw_discovery_salt() failed!" );
121 Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
122 exit( 1 );
124 #endif
126 for( i = 0; i < MAX_RENDEZVOUS; i++ ) My_Rendezvous[i].Desc[0] = '\0';
127 } /* Rendezvous_Init */
130 GLOBAL void Rendezvous_Exit( void )
132 /* Clean up & exit module */
134 int i;
136 for( i = 0; i < MAX_RENDEZVOUS; i++ )
138 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
141 #ifdef HOWL
142 sw_discovery_fina( My_Discovery_Session );
143 #endif
144 } /* Rendezvous_Exit */
147 GLOBAL bool Rendezvous_Register( char *Name, char *Type, unsigned int Port )
149 /* Register new service */
151 int i;
153 /* Search free port structure */
154 for( i = 0; i < MAX_RENDEZVOUS; i++ ) if( ! My_Rendezvous[i].Desc[0] ) break;
155 if( i >= MAX_RENDEZVOUS )
157 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: limit (%d) reached!", Name, MAX_RENDEZVOUS );
158 return false;
160 strlcpy( My_Rendezvous[i].Desc, Name, sizeof( My_Rendezvous[i].Desc ));
162 #ifdef APPLE
163 /* Register new service */
164 My_Rendezvous[i].Discovery_Ref = DNSServiceRegistrationCreate( Name, Type, "", htonl( Port ), "", Registration_Reply_Handler, &My_Rendezvous[i] );
165 if( ! My_Rendezvous[i].Discovery_Ref )
167 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: can't register service!", My_Rendezvous[i].Desc );
168 My_Rendezvous[i].Desc[0] = '\0';
169 return false;
172 /* Get and save the corresponding Mach Port */
173 My_Rendezvous[i].Mach_Port = DNSServiceDiscoveryMachPort( My_Rendezvous[i].Discovery_Ref );
174 if( ! My_Rendezvous[i].Mach_Port )
176 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: got no Mach Port!", My_Rendezvous[i].Desc );
177 /* Here we actually leek a descriptor :-( */
178 My_Rendezvous[i].Discovery_Ref = 0;
179 My_Rendezvous[i].Desc[0] = '\0';
180 return false;
182 #endif /* Apple */
184 #ifdef HOWL
185 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 )
187 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: can't register service!", My_Rendezvous[i].Desc );
188 My_Rendezvous[i].Desc[0] = '\0';
189 return false;
191 #endif /* Howl */
193 Log( LOG_DEBUG, "Rendezvous: Registering \"%s\" ...", My_Rendezvous[i].Desc );
194 return true;
195 } /* Rendezvous_Register */
198 GLOBAL bool Rendezvous_Unregister( char *Name )
200 /* Unregister service from rendezvous */
202 int i;
203 bool ok;
205 ok = false;
206 for( i = 0; i < MAX_RENDEZVOUS; i++ )
208 if( strcmp( Name, My_Rendezvous[i].Desc ) == 0 )
210 Unregister( i );
211 ok = true;
215 return ok;
216 } /* Rendezvous_Unregister */
219 GLOBAL void Rendezvous_UnregisterListeners( void )
221 /* Unregister all our listening sockets from Rendezvous */
223 int i;
225 for( i = 0; i < MAX_RENDEZVOUS; i++ )
227 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
229 } /* Rendezvous_UnregisterListeners */
232 GLOBAL void Rendezvous_Handler( void )
234 /* Handle all Rendezvous stuff; this function must be called
235 * periodically from the run loop of the main program */
237 #ifdef APPLE
238 int i;
239 char buffer[MAX_MACH_MSG_SIZE];
240 mach_msg_return_t result;
241 mach_msg_header_t *msg;
243 for( i = 0; i < MAX_RENDEZVOUS; i++ )
245 if( ! My_Rendezvous[i].Discovery_Ref ) continue;
247 /* Read message from Mach Port */
248 msg = (mach_msg_header_t *)buffer;
249 result = mach_msg( msg, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, MAX_MACH_MSG_SIZE, My_Rendezvous[i].Mach_Port, 1, 0 );
251 /* Handle message */
252 if( result == MACH_MSG_SUCCESS ) DNSServiceDiscovery_handleReply( msg );
253 #ifdef DEBUG
254 else if( result != MACH_RCV_TIMED_OUT ) Log( LOG_DEBUG, "mach_msg(): %ld", (long)result );
255 #endif /* Debug */
257 #endif /* Apple */
259 #ifdef HOWL
260 sw_ulong msecs = 10;
261 sw_salt_step( My_Salt, &msecs );
262 #endif
263 } /* Rendezvous_Handler */
266 LOCAL void Unregister( int Idx )
268 /* Unregister service */
270 #ifdef APPLE
271 DNSServiceDiscoveryDeallocate( My_Rendezvous[Idx].Discovery_Ref );
272 #endif /* Apple */
274 #ifdef HOWL
275 if( sw_discovery_cancel( My_Discovery_Session, My_Rendezvous[Idx].Id ) != SW_OKAY )
277 Log( LOG_ERR, "Rendezvous: Failed to unregister \"%s\"!", My_Rendezvous[Idx].Desc );
278 return;
280 #endif /* Howl */
282 Log( LOG_INFO, "Unregistered \"%s\" from Rendezvous.", My_Rendezvous[Idx].Desc );
283 My_Rendezvous[Idx].Desc[0] = '\0';
284 } /* Unregister */
287 /* -- Apple API -- */
289 #ifdef APPLE
292 LOCAL void Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, void *Context )
294 SERVICE *s = (SERVICE *)Context;
295 char txt[50];
297 if( ErrCode == kDNSServiceDiscoveryNoError )
299 /* Success! */
300 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
301 return;
304 switch( ErrCode )
306 case kDNSServiceDiscoveryAlreadyRegistered:
307 strcpy( txt, "name already registered!" );
308 break;
309 case kDNSServiceDiscoveryNameConflict:
310 strcpy( txt, "name conflict!" );
311 break;
312 default:
313 sprintf( txt, "error code %ld!", (long)ErrCode );
316 Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
317 s->Desc[0] = '\0';
318 } /* Registration_Reply_Handler */
321 #endif /* Apple */
324 /* -- Howl API -- */
326 #ifdef HOWL
329 LOCAL sw_result HOWL_API Registration_Reply_Handler( sw_discovery Session, sw_discovery_publish_status Status, UNUSED sw_discovery_oid Id, sw_opaque Extra )
331 SERVICE *s = (SERVICE *)Extra;
332 char txt[50];
334 assert( Session == My_Discovery_Session );
335 assert( Extra != NULL );
337 if( Status == SW_DISCOVERY_PUBLISH_STARTED || Status == SW_DISCOVERY_PUBLISH_STOPPED )
339 /* Success! */
340 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
341 return SW_OKAY;
344 switch( Status )
346 case SW_DISCOVERY_PUBLISH_NAME_COLLISION:
347 strcpy( txt, "name conflict!" );
348 break;
349 default:
350 sprintf( txt, "error code %ld!", (long)Status );
353 Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
354 s->Desc[0] = '\0';
356 return SW_OKAY;
357 } /* Registration_Reply_Handler */
360 #endif /* Howl */
363 #endif /* RENDEZVOUS */
366 /* -eof- */