- Added new source module "rendezvous".
[ngircd-alex.git] / src / ngircd / rendezvous.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2003 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 (using Mach Ports, e.g. Mac OS X)
12  */
13
14
15 #include "portab.h"
16
17 #ifdef RENDEZVOUS
18
19
20 static char UNUSED id[] = "$Id: rendezvous.c,v 1.1 2003/02/23 12:02:26 alex Exp $";
21
22 #include "imp.h"
23 #include <assert.h>
24
25 #include <stdio.h>
26 #include <string.h>
27
28 #ifdef HAVE_MACH_PORT_H
29 #include "mach/port.h"
30 #include "mach/message.h"
31 #endif
32
33 #ifdef HAVE_DNSSERVICEDISCOVERY_DNSSERVICEDISCOVERY_H
34 #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
35 #endif
36
37 #include "defines.h"
38 #include "log.h"
39
40 #include "exp.h"
41 #include "rendezvous.h"
42
43
44 typedef struct _service
45 {
46         dns_service_discovery_ref Discovery_Ref;
47         mach_port_t Mach_Port;
48         CHAR Desc[CLIENT_ID_LEN];
49 } SERVICE;
50
51
52 LOCAL VOID Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, VOID *Context );
53 LOCAL VOID Unregister( INT Idx );
54
55
56 #define MAX_RENDEZVOUS 1000
57 #define MAX_MACH_MSG_SIZE 512
58
59
60 LOCAL SERVICE My_Rendezvous[MAX_RENDEZVOUS];
61
62
63 GLOBAL VOID Rendezvous_Init( VOID )
64 {
65         /* Initialize structures */
66
67         INT i;
68
69         for( i = 0; i < MAX_RENDEZVOUS; i++ )
70         {
71                 My_Rendezvous[i].Discovery_Ref = 0;
72                 My_Rendezvous[i].Mach_Port = 0;
73         }
74 } /* Rendezvous_Init */
75
76
77 GLOBAL VOID Rendezvous_Exit( VOID )
78 {
79         /* Clean up & exit module */
80
81         INT i;
82
83         for( i = 0; i < MAX_RENDEZVOUS; i++ )
84         {
85                 if( My_Rendezvous[i].Discovery_Ref ) Unregister( i );
86         }
87 } /* Rendezvous_Exit */
88
89
90 GLOBAL BOOLEAN Rendezvous_Register( CHAR *Name, CHAR *Type, UINT Port )
91 {
92         /* Register new service */
93
94         INT i;
95
96         /* Search free port structure */
97         for( i = 0; i < MAX_RENDEZVOUS; i++ ) if( ! My_Rendezvous[i].Discovery_Ref ) break;
98         if( i >= MAX_RENDEZVOUS )
99         {
100                 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: limit (%d) reached!", Name, MAX_RENDEZVOUS );
101                 return FALSE;
102         }
103         strlcpy( My_Rendezvous[i].Desc, Name, sizeof( My_Rendezvous[i].Desc ));
104         
105         /* Register new service */
106         My_Rendezvous[i].Discovery_Ref = DNSServiceRegistrationCreate( Name, Type, "", htonl( Port ), "", Registration_Reply_Handler, My_Rendezvous[i].Desc );
107         if( ! My_Rendezvous[i].Discovery_Ref )
108         {
109                 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: can't register service!", My_Rendezvous[i].Desc );
110                 return FALSE;
111         }
112         
113         /* Get and save the corresponding Mach Port */
114         My_Rendezvous[i].Mach_Port = DNSServiceDiscoveryMachPort( My_Rendezvous[i].Discovery_Ref );
115         if( ! My_Rendezvous[i].Mach_Port )
116         {
117                 Log( LOG_ERR, "Can't register \"%s\" with Rendezvous: got no Mach Port!", My_Rendezvous[i].Desc );
118                 /* Here we actually leek a descriptor :-( */
119                 My_Rendezvous[i].Discovery_Ref = 0;
120                 return FALSE;
121         }
122
123         Log( LOG_DEBUG, "Rendezvous: Registering \"%s\" ...", My_Rendezvous[i].Desc );
124         return TRUE;
125 } /* Rendezvous_Register */
126
127
128 GLOBAL BOOLEAN Rendezvous_Unregister( CHAR *Name )
129 {
130         /* Unregister service from rendezvous */
131
132         INT i;
133         BOOLEAN ok;
134
135         ok = FALSE;
136         for( i = 0; i < MAX_RENDEZVOUS; i++ )
137         {
138                 if( strcmp( Name, My_Rendezvous[i].Desc ) == 0 )
139                 {
140                         Unregister( i );
141                         ok = TRUE;
142                 }
143         }
144
145         return ok;
146 } /* Rendezvous_Unregister */
147
148
149 GLOBAL VOID Rendezvous_UnregisterListeners( VOID )
150 {
151         /* Unregister all our listening sockets from Rendezvous */
152
153         INT i;
154
155         for( i = 0; i < MAX_RENDEZVOUS; i++ )
156         {
157                 if( strchr( My_Rendezvous[i].Desc, '.' )) Unregister( i );
158         }
159 } /* Rendezvous_UnregisterListeners */
160
161
162 GLOBAL VOID Rendezvous_Handler( VOID )
163 {
164         /* Handle all Rendezvous stuff; this function must be called
165          * periodically from the run loop of the main program */
166
167         INT i;
168         CHAR buffer[MAX_MACH_MSG_SIZE];
169         mach_msg_return_t result;
170         mach_msg_header_t *msg;
171
172         for( i = 0; i < MAX_RENDEZVOUS; i++ )
173         {
174                 if( ! My_Rendezvous[i].Discovery_Ref ) continue;
175
176                 /* Read message from Mach Port */
177                 msg = (mach_msg_header_t *)buffer;
178                 result = mach_msg( msg, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, MAX_MACH_MSG_SIZE, My_Rendezvous[i].Mach_Port, 1, 0 );
179
180                 /* Handle message */
181                 if( result == MACH_MSG_SUCCESS ) DNSServiceDiscovery_handleReply( msg );
182 #ifdef DEBUG
183                 else if( result != MACH_RCV_TIMED_OUT ) Log( LOG_DEBUG, "mach_msg(): %ld", (LONG)result );
184 #endif
185         }
186 } /* Rendezvous_Handler */
187
188
189 LOCAL VOID Registration_Reply_Handler( DNSServiceRegistrationReplyErrorType ErrCode, VOID *Context )
190 {
191         CHAR txt[50];
192
193         if( ErrCode == kDNSServiceDiscoveryNoError )
194         {
195                 /* Success! */
196                 Log( LOG_INFO, "Successfully registered \"%s\" with Rendezvous.", Context ? Context : "NULL" );
197                 return;
198         }
199
200         switch( ErrCode )
201         {
202                 case kDNSServiceDiscoveryAlreadyRegistered:
203                         strcpy( txt, "name already registered!" );
204                         break;
205                 case kDNSServiceDiscoveryNameConflict:
206                         strcpy( txt, "name conflict!" );
207                         break;
208                 default:
209                         sprintf( txt, "error code %ld!", (LONG)ErrCode );
210         }
211
212         Log( LOG_INFO, "Can't register \"%s\" with Rendezvous: %s", Context ? Context : "NULL", txt );
213 } /* Registration_Reply_Handler */
214
215
216 LOCAL VOID Unregister( INT Idx )
217 {
218         /* Unregister service */
219
220         DNSServiceDiscoveryDeallocate( My_Rendezvous[Idx].Discovery_Ref );
221         Log( LOG_INFO, "Unregistered \"%s\" from Rendezvous.", My_Rendezvous[Idx].Desc );
222         My_Rendezvous[Idx].Discovery_Ref = 0;
223 } /* Unregister */
224
225
226 #endif  /* RENDEZVOUS */
227
228
229 /* -eof- */