]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/rendezvous.c
TOPIC command: test for channel admin rights correctly
[ngircd-alex.git] / src / ngircd / rendezvous.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2010 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 ZEROCONF
22
23
24 #include "imp.h"
25 #include <assert.h>
26
27 #include <stdio.h>
28 #include <string.h>
29
30 #ifdef HAVE_MACH_PORT_H
31 #include "mach/port.h"
32 #include "mach/message.h"
33 #endif
34
35 #ifdef HAVE_DNSSERVICEDISCOVERY_DNSSERVICEDISCOVERY_H
36 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
37 #endif
38
39 #ifdef HAVE_RENDEZVOUS_RENDEZVOUS_H
40 #include <rendezvous/rendezvous.h>
41 #endif
42
43 #include "defines.h"
44 #include "conn.h"
45 #include "conf.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 static SERVICE My_Rendezvous[MAX_RENDEZVOUS];
76
77
78 static void Unregister( int Idx );
79
80
81 /* -- Apple API -- */
82
83 #ifdef APPLE
84
85 #define MAX_MACH_MSG_SIZE 512
86
87 static void Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, void *Context );
88
89 #endif /* Apple */
90
91
92 /* -- Howl API -- */
93
94 #ifdef HOWL
95
96 static sw_discovery My_Discovery_Session = NULL;
97 static sw_salt My_Salt;
98
99 static 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         for (i = 0; i < MAX_RENDEZVOUS; i++)
111                 My_Rendezvous[i].Desc[0] = '\0';
112
113         if (!Conf_ZeroConf)
114                 return;
115
116 #ifdef HOWL
117         if( sw_discovery_init( &My_Discovery_Session ) != SW_OKAY )
118         {
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 );
121                 exit( 1 );
122         }
123
124         if( sw_discovery_salt( My_Discovery_Session, &My_Salt ) != SW_OKAY )
125         {
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 );
128                 exit( 1 );
129         }
130 #endif
131 } /* Rendezvous_Init */
132
133
134 GLOBAL void Rendezvous_Exit( void )
135 {
136         /* Clean up & exit module */
137
138         int i;
139
140         for( i = 0; i < MAX_RENDEZVOUS; i++ )
141         {
142                 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
143         }
144
145 #ifdef HOWL
146         sw_discovery_fina( My_Discovery_Session );
147 #endif
148 } /* Rendezvous_Exit */
149
150
151 /**
152  * Register ZeroConf service
153  */
154 GLOBAL bool Rendezvous_Register( char *Name, char *Type, UINT16 Port )
155 {
156         int i;
157
158         if (!Conf_ZeroConf)
159                 return true;
160
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 )
164         {
165                 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: limit (%d) reached!", Name, MAX_RENDEZVOUS );
166                 return false;
167         }
168         strlcpy( My_Rendezvous[i].Desc, Name, sizeof( My_Rendezvous[i].Desc ));
169         
170 #ifdef APPLE
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 )
174         {
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';
177                 return false;
178         }
179         
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 )
183         {
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';
188                 return false;
189         }
190 #endif /* Apple */
191
192 #ifdef HOWL
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 )
194         {
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';
197                 return false;
198         }
199 #endif /* Howl */
200
201         Log( LOG_DEBUG, "Rendezvous: Registering \"%s\" ...", My_Rendezvous[i].Desc );
202         return true;
203 } /* Rendezvous_Register */
204
205
206 GLOBAL bool Rendezvous_Unregister( char *Name )
207 {
208         /* Unregister service from rendezvous */
209
210         int i;
211         bool ok;
212
213         ok = false;
214         for( i = 0; i < MAX_RENDEZVOUS; i++ )
215         {
216                 if( strcmp( Name, My_Rendezvous[i].Desc ) == 0 )
217                 {
218                         Unregister( i );
219                         ok = true;
220                 }
221         }
222
223         return ok;
224 } /* Rendezvous_Unregister */
225
226
227 GLOBAL void Rendezvous_UnregisterListeners( void )
228 {
229         /* Unregister all our listening sockets from Rendezvous */
230
231         int i;
232
233         for( i = 0; i < MAX_RENDEZVOUS; i++ )
234         {
235                 if( My_Rendezvous[i].Desc[0] ) Unregister( i );
236         }
237 } /* Rendezvous_UnregisterListeners */
238
239
240 GLOBAL void Rendezvous_Handler( void )
241 {
242         /* Handle all Rendezvous stuff; this function must be called
243          * periodically from the run loop of the main program */
244
245         if (!Conf_ZeroConf)
246                 return;
247
248 #ifdef APPLE
249         int i;
250         char buffer[MAX_MACH_MSG_SIZE];
251         mach_msg_return_t result;
252         mach_msg_header_t *msg;
253
254         for( i = 0; i < MAX_RENDEZVOUS; i++ )
255         {
256                 if( ! My_Rendezvous[i].Discovery_Ref ) continue;
257
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 );
261
262                 /* Handle message */
263                 if( result == MACH_MSG_SUCCESS ) DNSServiceDiscovery_handleReply( msg );
264 #ifdef DEBUG
265                 else if( result != MACH_RCV_TIMED_OUT ) Log( LOG_DEBUG, "mach_msg(): %ld", (long)result );
266 #endif /* Debug */
267         }
268 #endif /* Apple */
269
270 #ifdef HOWL
271         sw_ulong msecs = 10;
272         sw_salt_step( My_Salt, &msecs );
273 #endif
274 } /* Rendezvous_Handler */
275
276
277 static void Unregister( int Idx )
278 {
279         /* Unregister service */
280
281 #ifdef APPLE
282         DNSServiceDiscoveryDeallocate( My_Rendezvous[Idx].Discovery_Ref );
283 #endif /* Apple */
284
285 #ifdef HOWL
286         if( sw_discovery_cancel( My_Discovery_Session, My_Rendezvous[Idx].Id ) != SW_OKAY )
287         {
288                 Log( LOG_ERR, "Rendezvous: Failed to unregister \"%s\"!", My_Rendezvous[Idx].Desc );
289                 return;
290         }
291 #endif /* Howl */
292         
293         Log( LOG_INFO, "Unregistered \"%s\" from Rendezvous.", My_Rendezvous[Idx].Desc );
294         My_Rendezvous[Idx].Desc[0] = '\0';
295 } /* Unregister */
296
297
298 /* -- Apple API -- */
299
300 #ifdef APPLE
301
302
303 static void Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, void *Context )
304 {
305         SERVICE *s = (SERVICE *)Context;
306         char txt[50];
307
308         if( ErrCode == kDNSServiceDiscoveryNoError )
309         {
310                 /* Success! */
311                 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
312                 return;
313         }
314
315         switch( ErrCode )
316         {
317                 case kDNSServiceDiscoveryAlreadyRegistered:
318                         strcpy( txt, "name already registered!" );
319                         break;
320                 case kDNSServiceDiscoveryNameConflict:
321                         strcpy( txt, "name conflict!" );
322                         break;
323                 default:
324                         snprintf(txt, sizeof txt, "error code %ld!",
325                                  (long)ErrCode);
326         }
327
328         Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
329         s->Desc[0] = '\0';
330 } /* Registration_Reply_Handler */
331
332
333 #endif /* Apple */
334
335
336 /* -- Howl API -- */
337
338 #ifdef HOWL
339
340
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 )
342 {
343         SERVICE *s = (SERVICE *)Extra;
344         char txt[50];
345
346         assert( Session == My_Discovery_Session );
347         assert( Extra != NULL );
348
349         if( Status == SW_DISCOVERY_PUBLISH_STARTED || Status == SW_DISCOVERY_PUBLISH_STOPPED )
350         {
351                 /* Success! */
352                 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", s->Desc );
353                 return SW_OKAY;
354         }
355                 
356         switch( Status )
357         {
358                 case SW_DISCOVERY_PUBLISH_NAME_COLLISION:
359                         strcpy( txt, "name conflict!" );
360                         break;
361                 default:
362                         snprintf(txt, sizeof txt, "error code %ld!",
363                                  (long)Status);
364         }
365
366         Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", s->Desc, txt );
367         s->Desc[0] = '\0';
368
369         return SW_OKAY;
370 } /* Registration_Reply_Handler */
371
372
373 #endif /* Howl */
374
375
376 #endif  /* ZEROCONF */
377
378
379 /* -eof- */