add more spacing
[personal-kdebase.git] / workspace / kdm / backend / socket.c
blob1439a2ab2d3d3f88db2176d85077f8d625c1ac9a
1 /*
3 Copyright 1988, 1998 The Open Group
4 Copyright 2002 Sun Microsystems, Inc. All rights reserved.
5 Copyright 2002,2004 Oswald Buddenhagen <ossi@kde.org>
7 Permission to use, copy, modify, distribute, and sell this software and its
8 documentation for any purpose is hereby granted without fee, provided that
9 the above copyright notice appear in all copies and that both that
10 copyright notice and this permission notice appear in supporting
11 documentation.
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
24 Except as contained in this notice, the name of a copyright holder shall
25 not be used in advertising or otherwise to promote the sale, use or
26 other dealings in this Software without prior written authorization
27 from the copyright holder.
32 * xdm - display manager daemon
33 * Author: Keith Packard, MIT X Consortium
35 * socket.c - Support for BSD sockets
38 #include "dm.h"
40 #if defined(XDMCP) && !defined(STREAMSCONN)
42 #include "dm_error.h"
43 #include "dm_socket.h"
45 #include <netdb.h>
46 #include <arpa/inet.h>
48 static int currentRequestPort;
50 static int
51 createListeningSocket( struct sockaddr *sock_addr, int salen )
53 int fd;
54 #if defined(IPv6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
55 int on = 0;
56 #endif
57 const char *addrstring = "unknown";
58 #if defined(IPv6) && defined(AF_INET6)
59 char addrbuf[INET6_ADDRSTRLEN];
60 #endif
62 if (!requestPort)
63 return -1;
65 if (debugLevel & DEBUG_CORE) {
66 #if defined(IPv6) && defined(AF_INET6)
67 void *ipaddr;
68 if (sock_addr->sa_family == AF_INET6)
69 ipaddr = & ((struct sockaddr_in6 *)sock_addr)->sin6_addr;
70 else
71 ipaddr = & ((struct sockaddr_in *)sock_addr)->sin_addr;
72 addrstring =
73 inet_ntop( sock_addr->sa_family, ipaddr, addrbuf, sizeof(addrbuf) );
75 #else
76 addrstring = inet_ntoa( ((struct sockaddr_in *)sock_addr)->sin_addr );
77 #endif
79 debug( "creating socket to listen on port %d of address %s\n",
80 requestPort, addrstring );
83 if ((fd = socket( sock_addr->sa_family, SOCK_DGRAM, 0 )) == -1) {
84 logError( "XDMCP socket creation failed, errno %d\n", errno );
85 return -1;
87 #if defined(IPv6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
88 setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on) );
89 #endif
91 if (bind( fd, sock_addr, salen ) == -1) {
92 logError( "error %d binding socket address %d\n", errno, requestPort );
93 close( fd );
94 return -1;
97 registerCloseOnFork( fd );
98 registerInput( fd );
99 return fd;
102 struct socklist {
103 struct socklist *next;
104 struct socklist *mcastgroups;
105 struct sockaddr *addr;
106 int salen;
107 int addrlen;
108 int fd;
109 int ref; /* referenced bit - see updateListenSockets */
112 static struct socklist *listensocks;
114 static void
115 destroyListeningSocket( struct socklist *s )
117 struct socklist *g, *n;
119 if (s->fd >= 0) {
120 closeNclearCloseOnFork( s->fd );
121 unregisterInput( s->fd );
122 s->fd = -1;
124 if (s->addr) {
125 free( s->addr );
126 s->addr = NULL;
128 for (g = s->mcastgroups; g; g = n) {
129 n = g->next;
130 if (g->addr)
131 free( g->addr );
132 free( g );
134 s->mcastgroups = NULL;
137 static struct socklist*
138 findInList( struct socklist *list, ARRAY8Ptr addr )
140 struct socklist *s;
142 for (s = list; s; s = s->next) {
143 if (s->addrlen == addr->length) {
144 char *addrdata;
146 switch (s->addr->sa_family) {
147 case AF_INET:
148 addrdata = (char *)
149 &(((struct sockaddr_in *)s->addr)->sin_addr.s_addr);
150 break;
151 #if defined(IPv6) && defined(AF_INET6)
152 case AF_INET6:
153 addrdata = (char *)
154 &(((struct sockaddr_in6 *)s->addr)->sin6_addr.s6_addr);
155 break;
156 #endif
157 default:
158 /* Unrecognized address family */
159 continue;
161 if (!memcmp( addrdata, addr->data, addr->length ))
162 return s;
165 return NULL;
168 static struct socklist *
169 createSocklistEntry( ARRAY8Ptr addr )
171 struct socklist *s;
173 if (!(s = Calloc( 1, sizeof(struct socklist) )))
174 return NULL;
176 if (addr->length == 4) { /* IPv4 */
177 struct sockaddr_in *sin4;
178 sin4 = Calloc( 1, sizeof(struct sockaddr_in) );
179 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
180 sin4->sin_len = sizeof(struct sockaddr_in);
181 #endif
182 s->addr = (struct sockaddr *)sin4;
183 s->salen = sizeof(struct sockaddr_in);
184 s->addrlen = sizeof(struct in_addr);
185 sin4->sin_family = AF_INET;
186 sin4->sin_port = htons( (short)requestPort );
187 memcpy( &sin4->sin_addr, addr->data, addr->length );
189 #if defined(IPv6) && defined(AF_INET6)
190 else if (addr->length == 16) { /* IPv6 */
191 struct sockaddr_in6 *sin6;
192 sin6 = Calloc( 1, sizeof(struct sockaddr_in6) );
193 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
194 sin6->sin6_len = sizeof(struct sockaddr_in6);
195 #endif
196 s->addr = (struct sockaddr *)sin6;
197 s->salen = sizeof(struct sockaddr_in6);
198 s->addrlen = sizeof(struct in6_addr);
199 sin6->sin6_family = AF_INET6;
200 sin6->sin6_port = htons( (short)requestPort );
201 memcpy( &sin6->sin6_addr, addr->data, addr->length );
203 #endif
204 else {
205 /* Unknown address type */
206 free( s );
207 s = NULL;
209 return s;
212 static void
213 updateListener( ARRAY8Ptr addr, void **closure )
215 struct socklist *s;
217 *closure = NULL;
219 if (addr == NULL) {
220 ARRAY8 tmpaddr;
221 struct in_addr in;
222 #if defined(IPv6) && defined(AF_INET6)
223 struct in6_addr in6 = in6addr_any;
224 tmpaddr.length = sizeof(in6);
225 tmpaddr.data = (CARD8Ptr) &in6;
226 updateListener( &tmpaddr, closure );
227 if (*closure)
228 return;
229 #endif
230 in.s_addr = htonl( INADDR_ANY );
231 tmpaddr.length = sizeof(in);
232 tmpaddr.data = (CARD8Ptr) &in;
233 updateListener( &tmpaddr, closure );
234 return;
237 if (currentRequestPort == requestPort &&
238 (s = findInList( listensocks, addr )))
240 *closure = (void *)s;
241 s->ref = True;
242 return;
245 if (!(s = createSocklistEntry( addr )))
246 return;
248 if ((s->fd = createListeningSocket( s->addr, s->salen )) < 0) {
249 free( s->addr );
250 free( s );
251 return;
253 s->ref = True;
254 s->next = listensocks;
255 listensocks = s;
256 *closure = (void *)s;
259 #define JOIN_MCAST_GROUP 0
260 #define LEAVE_MCAST_GROUP 1
262 static void
263 changeMcastMembership( struct socklist *s, struct socklist *g, int op )
265 int sockopt;
267 switch (s->addr->sa_family)
269 case AF_INET:
271 struct ip_mreq mreq;
272 memcpy( &mreq.imr_multiaddr,
273 &((struct sockaddr_in *)g->addr)->sin_addr,
274 sizeof(struct in_addr) );
275 memcpy( &mreq.imr_interface,
276 &((struct sockaddr_in *)s->addr)->sin_addr,
277 sizeof(struct in_addr) );
278 if (op == JOIN_MCAST_GROUP)
279 sockopt = IP_ADD_MEMBERSHIP;
280 else
281 sockopt = IP_DROP_MEMBERSHIP;
282 if (setsockopt( s->fd, IPPROTO_IP, sockopt,
283 &mreq, sizeof(mreq) ) < 0) {
284 logError( "XDMCP socket multicast %s to %s failed, errno %d\n",
285 (op == JOIN_MCAST_GROUP) ? "join" : "drop",
286 inet_ntoa( ((struct sockaddr_in *)g->addr)->sin_addr ),
287 errno );
288 } else if (debugLevel & DEBUG_CORE) {
289 debug( "XDMCP socket multicast %s to %s succeeded\n",
290 (op == JOIN_MCAST_GROUP) ? "join" : "drop",
291 inet_ntoa( ((struct sockaddr_in *)g->addr)->sin_addr ) );
293 return;
295 #if defined(IPv6) && defined(AF_INET6)
296 # ifndef IPV6_JOIN_GROUP
297 # define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
298 # endif
299 # ifndef IPV6_LEAVE_GROUP
300 # define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
301 # endif
302 case AF_INET6:
304 struct ipv6_mreq mreq6;
305 memcpy( &mreq6.ipv6mr_multiaddr,
306 &((struct sockaddr_in6 *)g->addr)->sin6_addr,
307 sizeof(struct in6_addr) );
308 mreq6.ipv6mr_interface = 0; /* TODO: fix this */
309 if (op == JOIN_MCAST_GROUP)
310 sockopt = IPV6_JOIN_GROUP;
311 else
312 sockopt = IPV6_LEAVE_GROUP;
313 if (setsockopt( s->fd, IPPROTO_IPV6, sockopt,
314 &mreq6, sizeof(mreq6) ) < 0)
316 int saveerr = errno;
317 char addrbuf[INET6_ADDRSTRLEN];
319 inet_ntop( s->addr->sa_family,
320 &((struct sockaddr_in6 *)g->addr)->sin6_addr,
321 addrbuf, sizeof(addrbuf) );
323 logError( "XDMCP socket multicast %s to %s failed, errno %d\n",
324 (op == JOIN_MCAST_GROUP) ? "join" : "drop", addrbuf,
325 saveerr );
326 } else if (debugLevel & DEBUG_CORE) {
327 char addrbuf[INET6_ADDRSTRLEN];
329 inet_ntop( s->addr->sa_family,
330 &((struct sockaddr_in6 *)g->addr)->sin6_addr,
331 addrbuf, sizeof(addrbuf) );
333 debug( "XDMCP socket multicast %s to %s succeeded\n",
334 (op == JOIN_MCAST_GROUP) ? "join" : "drop", addrbuf );
336 return;
338 #endif
342 static void
343 updateMcastGroup( ARRAY8Ptr addr, void **closure )
345 struct socklist *s = (struct socklist *)*closure;
346 struct socklist *g;
348 if (!s)
349 return;
351 /* Already in the group, mark & continue */
352 if ((g = findInList( s->mcastgroups, addr ))) {
353 g->ref = True;
354 return;
357 /* Need to join the group */
358 if (!(g = createSocklistEntry( addr )))
359 return;
361 changeMcastMembership( s, g, JOIN_MCAST_GROUP );
362 free( g );
365 /* Open or close listening sockets to match the current settings read in
366 from the access database. */
367 void
368 updateListenSockets( void )
370 struct socklist *s, *g, **ls, **lg;
371 void *tmpPtr = NULL;
373 /* Clear Ref bits - any not marked by UpdateCallback will be closed */
374 for (s = listensocks; s; s = s->next) {
375 s->ref = False;
376 for (g = s->mcastgroups; g; g = g->next)
377 g->ref = False;
379 forEachListenAddr( updateListener, updateMcastGroup, &tmpPtr );
380 currentRequestPort = requestPort;
381 for (ls = &listensocks; (s = *ls); )
382 if (!s->ref) {
383 destroyListeningSocket( s );
384 *ls = s->next;
385 free( s );
386 } else {
387 ls = &s->next;
388 for (lg = &s->mcastgroups; (g = *lg); )
389 if (!g->ref) {
390 changeMcastMembership( s, g, LEAVE_MCAST_GROUP );
391 *lg = g->next;
392 free( g );
393 } else
394 lg = &g->next;
399 anyListenSockets( void )
401 return listensocks != NULL;
405 processListenSockets( fd_set *reads )
407 struct socklist *s;
408 int ret = False;
410 for (s = listensocks; s; s = s->next)
411 if (FD_ISSET( s->fd, reads )) {
412 processRequestSocket( s->fd );
413 ret = True;
415 return ret;
418 #endif /* !STREAMSCONN && XDMCP */