]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/rendezvous.c
Don't use a POSIX thread for the Howl "run loop".
[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.4 2004/12/26 16:48:53 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 LOCAL sw_discovery My_Discovery_Session = NULL;
97 LOCAL sw_salt My_Salt;
98
99 LOCAL sw_result HOWL_API Registration_Reply_Handler( sw_discovery Session, sw_discovery_publish_status Status, sw_discovery_oid Id, sw_opaque Extra );
100
101 #endif /* Howl */
102
103
104 GLOBAL VOID Rendezvous_Init( VOID )
105 {
106         /* Initialize structures */
107
108         INT i;
109
110 #ifdef HOWL
111         if( sw_discovery_init( &My_Discovery_Session ) != SW_OKAY )
112         {
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 );
116         }
117
118         if( sw_discovery_salt( My_Discovery_Session, &My_Salt ) != SW_OKAY )
119         {
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 );
123         }
124 #endif
125
126         for( i = 0; i < MAX_RENDEZVOUS; i++ ) My_Rendezvous[i].Desc[0] = '\0';
127 } /* Rendezvous_Init */
128
129
130 GLOBAL VOID Rendezvous_Exit( VOID )
131 {
132         /* Clean up & exit module */
133
134         INT i;
135
136         for( i = 0; i < MAX_RENDEZVOUS; i++ )
137         {
138                 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
139         }
140
141 #ifdef HOWL
142         sw_discovery_fina( My_Discovery_Session );
143 #endif
144 } /* Rendezvous_Exit */
145
146
147 GLOBAL BOOLEAN Rendezvous_Register( CHAR *Name, CHAR *Type, UINT Port )
148 {
149         /* Register new service */
150
151         INT i;
152
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 )
156         {
157                 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: limit (%d) reached!", Name, MAX_RENDEZVOUS );
158                 return FALSE;
159         }
160         strlcpy( My_Rendezvous[i].Desc, Name, sizeof( My_Rendezvous[i].Desc ));
161         
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 )
166         {
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;
170         }
171         
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 )
175         {
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;
181         }
182 #endif /* Apple */
183
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 )
186         {
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;
190         }
191 #endif /* Howl */
192
193         Log( LOG_DEBUG, "Rendezvous: Registering \"%s\" ...", My_Rendezvous[i].Desc );
194         return TRUE;
195 } /* Rendezvous_Register */
196
197
198 GLOBAL BOOLEAN Rendezvous_Unregister( CHAR *Name )
199 {
200         /* Unregister service from rendezvous */
201
202         INT i;
203         BOOLEAN ok;
204
205         ok = FALSE;
206         for( i = 0; i < MAX_RENDEZVOUS; i++ )
207         {
208                 if( strcmp( Name, My_Rendezvous[i].Desc ) == 0 )
209                 {
210                         Unregister( i );
211                         ok = TRUE;
212                 }
213         }
214
215         return ok;
216 } /* Rendezvous_Unregister */
217
218
219 GLOBAL VOID Rendezvous_UnregisterListeners( VOID )
220 {
221         /* Unregister all our listening sockets from Rendezvous */
222
223         INT i;
224
225         for( i = 0; i < MAX_RENDEZVOUS; i++ )
226         {
227                 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
228         }
229 } /* Rendezvous_UnregisterListeners */
230
231
232 GLOBAL VOID Rendezvous_Handler( VOID )
233 {
234         /* Handle all Rendezvous stuff; this function must be called
235          * periodically from the run loop of the main program */
236
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;
242
243         for( i = 0; i < MAX_RENDEZVOUS; i++ )
244         {
245                 if( ! My_Rendezvous[i].Discovery_Ref ) continue;
246
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 );
250
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 */
256         }
257 #endif /* Apple */
258
259 #ifdef HOWL
260         sw_ulong msecs = 10;
261         sw_salt_step( My_Salt, &msecs );
262 #endif
263 } /* Rendezvous_Handler */
264
265
266 LOCAL VOID Unregister( INT Idx )
267 {
268         /* Unregister service */
269
270 #ifdef APPLE
271         DNSServiceDiscoveryDeallocate( My_Rendezvous[Idx].Discovery_Ref );
272 #endif /* Apple */
273
274 #ifdef HOWL
275         if( sw_discovery_cancel( My_Discovery_Session, My_Rendezvous[Idx].Id ) != SW_OKAY )
276         {
277                 Log( LOG_ERR, "Rendezvous: Failed to unregister \"%s\"!", My_Rendezvous[Idx].Desc );
278                 return;
279         }
280 #endif /* Howl */
281         
282         Log( LOG_INFO, "Unregistered \"%s\" from Rendezvous.", My_Rendezvous[Idx].Desc );
283         My_Rendezvous[Idx].Desc[0] = '\0';
284 } /* Unregister */
285
286
287 /* -- Apple API -- */
288
289 #ifdef APPLE
290
291
292 LOCAL VOID Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, VOID *Context )
293 {
294         SERVICE *s = (SERVICE *)Context;
295         CHAR txt[50];
296
297         if( ErrCode == kDNSServiceDiscoveryNoError )
298         {
299                 /* Success! */
300                 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
301                 return;
302         }
303
304         switch( ErrCode )
305         {
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 );
314         }
315
316         Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
317         s->Desc[0] = '\0';
318 } /* Registration_Reply_Handler */
319
320
321 #endif /* Apple */
322
323
324 /* -- Howl API -- */
325
326 #ifdef HOWL
327
328
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 )
330 {
331         SERVICE *s = (SERVICE *)Extra;
332         CHAR txt[50];
333
334         assert( Session == My_Discovery_Session );
335         assert( Extra != NULL );
336
337         if( Status == SW_DISCOVERY_PUBLISH_STARTED || Status == SW_DISCOVERY_PUBLISH_STOPPED )
338         {
339                 /* Success! */
340                 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
341                 return SW_OKAY;
342         }
343                 
344         switch( Status )
345         {
346                 case SW_DISCOVERY_PUBLISH_NAME_COLLISION:
347                         strcpy( txt, "name conflict!" );
348                         break;
349                 default:
350                         sprintf( txt, "error code %ld!", (LONG)Status );
351         }
352
353         Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
354         s->Desc[0] = '\0';
355
356         return SW_OKAY;
357 } /* Registration_Reply_Handler */
358
359
360 #endif /* Howl */
361
362
363 #endif  /* RENDEZVOUS */
364
365
366 /* -eof- */