]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/rendezvous.c
Added support for the Howl (http://www.porchdogsoft.com/products/howl/)
[ngircd-alex.git] / src / ngircd / rendezvous.c
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  */
17
18
19 #include "portab.h"
20
21 #ifdef RENDEZVOUS
22
23
24 static char UNUSED id[] = "$Id: rendezvous.c,v 1.3 2004/12/26 00:14:33 alex Exp $";
25
26 #include "imp.h"
27 #include <assert.h>
28
29 #include <stdio.h>
30 #include <string.h>
31
32 #ifdef HAVE_MACH_PORT_H
33 #include "mach/port.h"
34 #include "mach/message.h"
35 #endif
36
37 #ifdef HAVE_DNSSERVICEDISCOVERY_DNSSERVICEDISCOVERY_H
38 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
39 #endif
40
41 #ifdef HAVE_RENDEZVOUS_RENDEZVOUS_H
42 #include <rendezvous/rendezvous.h>
43 #endif
44
45 #include "defines.h"
46 #include "log.h"
47
48 #include "exp.h"
49 #include "rendezvous.h"
50
51
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
59
60
61 #define MAX_RENDEZVOUS 1000
62
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;
74
75 LOCAL SERVICE My_Rendezvous[MAX_RENDEZVOUS];
76
77
78 LOCAL VOID Unregister( INT Idx );
79
80
81 /* -- Apple API -- */
82
83 #ifdef APPLE
84
85 #define MAX_MACH_MSG_SIZE 512
86
87 LOCAL VOID Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, VOID *Context );
88
89 #endif /* Apple */
90
91
92 /* -- Howl API -- */
93
94 #ifdef HOWL
95
96 #include <pthread.h>
97
98 LOCAL sw_discovery My_Discovery_Session = NULL;
99 LOCAL pthread_t My_Howl_Thread;
100 LOCAL BOOLEAN My_Howl_Thread_Created = FALSE;
101
102 LOCAL sw_result HOWL_API Registration_Reply_Handler( sw_discovery Session, sw_discovery_publish_status Status, sw_discovery_oid Id, sw_opaque Extra );
103
104 LOCAL VOID* Howl_Thread( VOID *x );
105
106 #endif /* Howl */
107
108
109 GLOBAL VOID Rendezvous_Init( VOID )
110 {
111         /* Initialize structures */
112
113         INT i;
114
115 #ifdef HOWL
116         if( sw_discovery_init( &My_Discovery_Session ) != SW_OKAY )
117         {
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 );
120                 exit( 1 );
121         }
122 #endif
123
124         for( i = 0; i < MAX_RENDEZVOUS; i++ ) My_Rendezvous[i].Desc[0] = '\0';
125 } /* Rendezvous_Init */
126
127
128 GLOBAL VOID Rendezvous_Exit( VOID )
129 {
130         /* Clean up & exit module */
131
132         INT i;
133
134         for( i = 0; i < MAX_RENDEZVOUS; i++ )
135         {
136                 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
137         }
138
139 #ifdef HOWL
140         if( My_Howl_Thread_Created )
141         {
142                 Log( LOG_DEBUG, "Rendezvous: Canceling management thread ..." );
143                 pthread_cancel( My_Howl_Thread );
144         }
145
146         sw_discovery_fina( My_Discovery_Session );
147 #endif
148 } /* Rendezvous_Exit */
149
150
151 GLOBAL BOOLEAN Rendezvous_Register( CHAR *Name, CHAR *Type, UINT Port )
152 {
153         /* Register new service */
154
155         INT i;
156
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 )
160         {
161                 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: limit (%d) reached!", Name, MAX_RENDEZVOUS );
162                 return FALSE;
163         }
164         strlcpy( My_Rendezvous[i].Desc, Name, sizeof( My_Rendezvous[i].Desc ));
165         
166 #ifdef APPLE
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 )
170         {
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';
173                 return FALSE;
174         }
175         
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 )
179         {
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';
184                 return FALSE;
185         }
186 #endif /* Apple */
187
188 #ifdef HOWL
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 )
190         {
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';
193                 return FALSE;
194         }
195 #endif /* Howl */
196
197         Log( LOG_DEBUG, "Rendezvous: Registering \"%s\" ...", My_Rendezvous[i].Desc );
198         return TRUE;
199 } /* Rendezvous_Register */
200
201
202 GLOBAL BOOLEAN Rendezvous_Unregister( CHAR *Name )
203 {
204         /* Unregister service from rendezvous */
205
206         INT i;
207         BOOLEAN ok;
208
209         ok = FALSE;
210         for( i = 0; i < MAX_RENDEZVOUS; i++ )
211         {
212                 if( strcmp( Name, My_Rendezvous[i].Desc ) == 0 )
213                 {
214                         Unregister( i );
215                         ok = TRUE;
216                 }
217         }
218
219         return ok;
220 } /* Rendezvous_Unregister */
221
222
223 GLOBAL VOID Rendezvous_UnregisterListeners( VOID )
224 {
225         /* Unregister all our listening sockets from Rendezvous */
226
227         INT i;
228
229         for( i = 0; i < MAX_RENDEZVOUS; i++ )
230         {
231                 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
232         }
233 } /* Rendezvous_UnregisterListeners */
234
235
236 GLOBAL VOID Rendezvous_Handler( VOID )
237 {
238         /* Handle all Rendezvous stuff; this function must be called
239          * periodically from the run loop of the main program */
240
241 #ifdef APPLE
242         INT i;
243         CHAR buffer[MAX_MACH_MSG_SIZE];
244         mach_msg_return_t result;
245         mach_msg_header_t *msg;
246
247         for( i = 0; i < MAX_RENDEZVOUS; i++ )
248         {
249                 if( ! My_Rendezvous[i].Discovery_Ref ) continue;
250
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 );
254
255                 /* Handle message */
256                 if( result == MACH_MSG_SUCCESS ) DNSServiceDiscovery_handleReply( msg );
257 #ifdef DEBUG
258                 else if( result != MACH_RCV_TIMED_OUT ) Log( LOG_DEBUG, "mach_msg(): %ld", (LONG)result );
259 #endif /* Debug */
260         }
261 #endif /* Apple */
262
263 #ifdef HOWL
264         if( My_Discovery_Session != NULL && My_Howl_Thread_Created == FALSE )
265         {
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;
270         }
271 #endif
272 } /* Rendezvous_Handler */
273
274
275 LOCAL VOID Unregister( INT Idx )
276 {
277         /* Unregister service */
278
279 #ifdef APPLE
280         DNSServiceDiscoveryDeallocate( My_Rendezvous[Idx].Discovery_Ref );
281 #endif /* Apple */
282
283 #ifdef HOWL
284         if( sw_discovery_cancel( My_Discovery_Session, My_Rendezvous[Idx].Id ) != SW_OKAY )
285         {
286                 Log( LOG_ERR, "Rendezvous: Failed to unregister \"%s\"!", My_Rendezvous[Idx].Desc );
287                 return;
288         }
289 #endif /* Howl */
290         
291         Log( LOG_INFO, "Unregistered \"%s\" from Rendezvous.", My_Rendezvous[Idx].Desc );
292         My_Rendezvous[Idx].Desc[0] = '\0';
293 } /* Unregister */
294
295
296 /* -- Apple API -- */
297
298 #ifdef APPLE
299
300
301 LOCAL VOID Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, VOID *Context )
302 {
303         SERVICE *s = (SERVICE *)Context;
304         CHAR txt[50];
305
306         if( ErrCode == kDNSServiceDiscoveryNoError )
307         {
308                 /* Success! */
309                 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
310                 return;
311         }
312
313         switch( ErrCode )
314         {
315                 case kDNSServiceDiscoveryAlreadyRegistered:
316                         strcpy( txt, "name already registered!" );
317                         break;
318                 case kDNSServiceDiscoveryNameConflict:
319                         strcpy( txt, "name conflict!" );
320                         break;
321                 default:
322                         sprintf( txt, "error code %ld!", (LONG)ErrCode );
323         }
324
325         Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
326         s->Desc[0] = '\0';
327 } /* Registration_Reply_Handler */
328
329
330 #endif /* Apple */
331
332
333 /* -- Howl API -- */
334
335 #ifdef HOWL
336
337
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 )
339 {
340         SERVICE *s = (SERVICE *)Extra;
341         CHAR txt[50];
342
343         assert( Session == My_Discovery_Session );
344         assert( Extra != NULL );
345
346         if( Status == SW_DISCOVERY_PUBLISH_STARTED || Status == SW_DISCOVERY_PUBLISH_STOPPED )
347         {
348                 /* Success! */
349                 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
350                 return SW_OKAY;
351         }
352                 
353         switch( Status )
354         {
355                 case SW_DISCOVERY_PUBLISH_NAME_COLLISION:
356                         strcpy( txt, "name conflict!" );
357                         break;
358                 default:
359                         sprintf( txt, "error code %ld!", (LONG)Status );
360         }
361
362         Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
363         s->Desc[0] = '\0';
364
365         return SW_OKAY;
366 } /* Registration_Reply_Handler */
367
368
369 LOCAL VOID *Howl_Thread( VOID *x )
370 {
371         assert( x == NULL );
372         sw_discovery_run( My_Discovery_Session );
373         pthread_exit( NULL );
374 } /* Howl_Thread */
375
376
377 #endif /* Howl */
378
379
380 #endif  /* RENDEZVOUS */
381
382
383 /* -eof- */