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
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
40
#if defined(XDMCP) && !defined(STREAMSCONN)
43
#include "dm_socket.h"
46
#include <arpa/inet.h>
48
static int currentRequestPort;
51
createListeningSocket(struct sockaddr *sock_addr, int salen)
54
#if defined(IPv6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
57
const char *addrstring = "unknown";
58
#if defined(IPv6) && defined(AF_INET6)
59
char addrbuf[INET6_ADDRSTRLEN];
65
if (debugLevel & DEBUG_CORE) {
66
#if defined(IPv6) && defined(AF_INET6)
68
if (sock_addr->sa_family == AF_INET6)
69
ipaddr = & ((struct sockaddr_in6 *)sock_addr)->sin6_addr;
71
ipaddr = & ((struct sockaddr_in *)sock_addr)->sin_addr;
73
inet_ntop(sock_addr->sa_family, ipaddr, addrbuf, sizeof(addrbuf));
76
addrstring = inet_ntoa(((struct sockaddr_in *)sock_addr)->sin_addr);
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);
87
#if defined(IPv6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
88
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
91
if (bind(fd, sock_addr, salen) == -1) {
92
logError("error %d binding socket address %d\n", errno, requestPort);
97
registerCloseOnFork(fd);
103
struct socklist *next;
104
struct socklist *mcastgroups;
105
struct sockaddr *addr;
109
int ref; /* referenced bit - see updateListenSockets */
112
static struct socklist *listensocks;
115
destroyListeningSocket(struct socklist *s)
117
struct socklist *g, *n;
120
closeNclearCloseOnFork(s->fd);
121
unregisterInput(s->fd);
126
for (g = s->mcastgroups; g; g = n) {
134
static struct socklist*
135
findInList(struct socklist *list, ARRAY8Ptr addr)
139
for (s = list; s; s = s->next) {
140
if (s->addrlen == addr->length) {
143
switch (s->addr->sa_family) {
146
&(((struct sockaddr_in *)s->addr)->sin_addr.s_addr);
148
#if defined(IPv6) && defined(AF_INET6)
151
&(((struct sockaddr_in6 *)s->addr)->sin6_addr.s6_addr);
155
/* Unrecognized address family */
158
if (!memcmp(addrdata, addr->data, addr->length))
165
static struct socklist *
166
createSocklistEntry(ARRAY8Ptr addr)
170
if (!(s = Calloc(1, sizeof(struct socklist))))
173
if (addr->length == 4) { /* IPv4 */
174
struct sockaddr_in *sin4;
175
sin4 = Calloc(1, sizeof(struct sockaddr_in));
176
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
177
sin4->sin_len = sizeof(struct sockaddr_in);
179
s->addr = (struct sockaddr *)sin4;
180
s->salen = sizeof(struct sockaddr_in);
181
s->addrlen = sizeof(struct in_addr);
182
sin4->sin_family = AF_INET;
183
sin4->sin_port = htons((short)requestPort);
184
memcpy(&sin4->sin_addr, addr->data, addr->length);
185
#if defined(IPv6) && defined(AF_INET6)
186
} else if (addr->length == 16) { /* IPv6 */
187
struct sockaddr_in6 *sin6;
188
sin6 = Calloc(1, sizeof(struct sockaddr_in6));
189
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
190
sin6->sin6_len = sizeof(struct sockaddr_in6);
192
s->addr = (struct sockaddr *)sin6;
193
s->salen = sizeof(struct sockaddr_in6);
194
s->addrlen = sizeof(struct in6_addr);
195
sin6->sin6_family = AF_INET6;
196
sin6->sin6_port = htons((short)requestPort);
197
memcpy(&sin6->sin6_addr, addr->data, addr->length);
200
/* Unknown address type */
208
updateListener(ARRAY8Ptr addr, void **closure)
217
#if defined(IPv6) && defined(AF_INET6)
218
struct in6_addr in6 = in6addr_any;
219
tmpaddr.length = sizeof(in6);
220
tmpaddr.data = (CARD8Ptr) &in6;
221
updateListener(&tmpaddr, closure);
225
in.s_addr = htonl(INADDR_ANY);
226
tmpaddr.length = sizeof(in);
227
tmpaddr.data = (CARD8Ptr) ∈
228
updateListener(&tmpaddr, closure);
232
if (currentRequestPort == requestPort &&
233
(s = findInList(listensocks, addr)))
235
*closure = (void *)s;
240
if (!(s = createSocklistEntry(addr)))
243
if ((s->fd = createListeningSocket(s->addr, s->salen)) < 0) {
249
s->next = listensocks;
251
*closure = (void *)s;
254
#define JOIN_MCAST_GROUP 0
255
#define LEAVE_MCAST_GROUP 1
258
changeMcastMembership(struct socklist *s, struct socklist *g, int op)
262
switch (s->addr->sa_family) {
265
memcpy(&mreq.imr_multiaddr,
266
&((struct sockaddr_in *)g->addr)->sin_addr,
267
sizeof(struct in_addr));
268
memcpy(&mreq.imr_interface,
269
&((struct sockaddr_in *)s->addr)->sin_addr,
270
sizeof(struct in_addr));
271
if (op == JOIN_MCAST_GROUP)
272
sockopt = IP_ADD_MEMBERSHIP;
274
sockopt = IP_DROP_MEMBERSHIP;
275
if (setsockopt(s->fd, IPPROTO_IP, sockopt,
276
&mreq, sizeof(mreq)) < 0)
278
logError("XDMCP socket multicast %s to %s failed, errno %d\n",
279
(op == JOIN_MCAST_GROUP) ? "join" : "drop",
280
inet_ntoa(((struct sockaddr_in *)g->addr)->sin_addr),
282
} else if (debugLevel & DEBUG_CORE) {
283
debug("XDMCP socket multicast %s to %s succeeded\n",
284
(op == JOIN_MCAST_GROUP) ? "join" : "drop",
285
inet_ntoa(((struct sockaddr_in *)g->addr)->sin_addr));
288
#if defined(IPv6) && defined(AF_INET6)
289
# ifndef IPV6_JOIN_GROUP
290
# define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
292
# ifndef IPV6_LEAVE_GROUP
293
# define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
296
struct ipv6_mreq mreq6;
297
memcpy(&mreq6.ipv6mr_multiaddr,
298
&((struct sockaddr_in6 *)g->addr)->sin6_addr,
299
sizeof(struct in6_addr));
300
mreq6.ipv6mr_interface = 0; /* TODO: fix this */
301
if (op == JOIN_MCAST_GROUP)
302
sockopt = IPV6_JOIN_GROUP;
304
sockopt = IPV6_LEAVE_GROUP;
305
if (setsockopt(s->fd, IPPROTO_IPV6, sockopt,
306
&mreq6, sizeof(mreq6)) < 0)
309
char addrbuf[INET6_ADDRSTRLEN];
311
inet_ntop(s->addr->sa_family,
312
&((struct sockaddr_in6 *)g->addr)->sin6_addr,
313
addrbuf, sizeof(addrbuf));
315
logError("XDMCP socket multicast %s to %s failed, errno %d\n",
316
(op == JOIN_MCAST_GROUP) ? "join" : "drop", addrbuf,
318
} else if (debugLevel & DEBUG_CORE) {
319
char addrbuf[INET6_ADDRSTRLEN];
321
inet_ntop(s->addr->sa_family,
322
&((struct sockaddr_in6 *)g->addr)->sin6_addr,
323
addrbuf, sizeof(addrbuf));
325
debug("XDMCP socket multicast %s to %s succeeded\n",
326
(op == JOIN_MCAST_GROUP) ? "join" : "drop", addrbuf);
334
updateMcastGroup(ARRAY8Ptr addr, void **closure)
336
struct socklist *s = (struct socklist *)*closure;
342
/* Already in the group, mark & continue */
343
if ((g = findInList(s->mcastgroups, addr))) {
348
/* Need to join the group */
349
if (!(g = createSocklistEntry(addr)))
352
changeMcastMembership(s, g, JOIN_MCAST_GROUP);
356
/* Open or close listening sockets to match the current settings read in
357
from the access database. */
359
updateListenSockets(void)
361
struct socklist *s, *g, **ls, **lg;
364
/* Clear Ref bits - any not marked by UpdateCallback will be closed */
365
for (s = listensocks; s; s = s->next) {
367
for (g = s->mcastgroups; g; g = g->next)
370
forEachListenAddr(updateListener, updateMcastGroup, &tmpPtr);
371
currentRequestPort = requestPort;
372
for (ls = &listensocks; (s = *ls);)
374
destroyListeningSocket(s);
379
for (lg = &s->mcastgroups; (g = *lg);)
381
changeMcastMembership(s, g, LEAVE_MCAST_GROUP);
391
anyListenSockets(void)
393
return listensocks != 0;
397
processListenSockets(fd_set *reads)
402
for (s = listensocks; s; s = s->next)
403
if (FD_ISSET(s->fd, reads)) {
404
processRequestSocket(s->fd);
410
#endif /* !STREAMSCONN && XDMCP */