~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kdm/backend/socket.c

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
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>
 
6
 
 
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.
 
12
 
 
13
The above copyright notice and this permission notice shall be included
 
14
in all copies or substantial portions of the Software.
 
15
 
 
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.
 
23
 
 
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.
 
28
 
 
29
*/
 
30
 
 
31
/*
 
32
 * xdm - display manager daemon
 
33
 * Author: Keith Packard, MIT X Consortium
 
34
 *
 
35
 * socket.c - Support for BSD sockets
 
36
 */
 
37
 
 
38
#include "dm.h"
 
39
 
 
40
#if defined(XDMCP) && !defined(STREAMSCONN)
 
41
 
 
42
#include "dm_error.h"
 
43
#include "dm_socket.h"
 
44
 
 
45
#include <netdb.h>
 
46
#include <arpa/inet.h>
 
47
 
 
48
static int currentRequestPort;
 
49
 
 
50
static int
 
51
createListeningSocket(struct sockaddr *sock_addr, int salen)
 
52
{
 
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
 
61
 
 
62
    if (!requestPort)
 
63
        return -1;
 
64
 
 
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));
 
74
 
 
75
#else
 
76
        addrstring = inet_ntoa(((struct sockaddr_in *)sock_addr)->sin_addr);
 
77
#endif
 
78
 
 
79
        debug("creating socket to listen on port %d of address %s\n",
 
80
              requestPort, addrstring);
 
81
    }
 
82
 
 
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;
 
86
    }
 
87
#if defined(IPv6) && defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
 
88
    setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
 
89
#endif
 
90
 
 
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;
 
95
    }
 
96
 
 
97
    registerCloseOnFork(fd);
 
98
    registerInput(fd);
 
99
    return fd;
 
100
}
 
101
 
 
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 */
 
110
};
 
111
 
 
112
static struct socklist *listensocks;
 
113
 
 
114
static void
 
115
destroyListeningSocket(struct socklist *s)
 
116
{
 
117
    struct socklist *g, *n;
 
118
 
 
119
    if (s->fd >= 0) {
 
120
        closeNclearCloseOnFork(s->fd);
 
121
        unregisterInput(s->fd);
 
122
        s->fd = -1;
 
123
    }
 
124
    free(s->addr);
 
125
    s->addr = 0;
 
126
    for (g = s->mcastgroups; g; g = n) {
 
127
        n = g->next;
 
128
        free(g->addr);
 
129
        free(g);
 
130
    }
 
131
    s->mcastgroups = 0;
 
132
}
 
133
 
 
134
static struct socklist*
 
135
findInList(struct socklist *list, ARRAY8Ptr addr)
 
136
{
 
137
    struct socklist *s;
 
138
 
 
139
    for (s = list; s; s = s->next) {
 
140
        if (s->addrlen == addr->length) {
 
141
            char *addrdata;
 
142
 
 
143
            switch (s->addr->sa_family) {
 
144
            case AF_INET:
 
145
                addrdata = (char *)
 
146
                  &(((struct sockaddr_in *)s->addr)->sin_addr.s_addr);
 
147
                break;
 
148
#if defined(IPv6) && defined(AF_INET6)
 
149
            case AF_INET6:
 
150
                addrdata = (char *)
 
151
                  &(((struct sockaddr_in6 *)s->addr)->sin6_addr.s6_addr);
 
152
                break;
 
153
#endif
 
154
            default:
 
155
                /* Unrecognized address family */
 
156
                continue;
 
157
            }
 
158
            if (!memcmp(addrdata, addr->data, addr->length))
 
159
                return s;
 
160
        }
 
161
    }
 
162
    return 0;
 
163
}
 
164
 
 
165
static struct socklist *
 
166
createSocklistEntry(ARRAY8Ptr addr)
 
167
{
 
168
    struct socklist *s;
 
169
 
 
170
    if (!(s = Calloc(1, sizeof(struct socklist))))
 
171
        return 0;
 
172
 
 
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);
 
178
#endif
 
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);
 
191
#endif
 
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);
 
198
#endif
 
199
    } else {
 
200
        /* Unknown address type */
 
201
        free(s);
 
202
        s = 0;
 
203
    }
 
204
    return s;
 
205
}
 
206
 
 
207
static void
 
208
updateListener(ARRAY8Ptr addr, void **closure)
 
209
{
 
210
    struct socklist *s;
 
211
 
 
212
    *closure = 0;
 
213
 
 
214
    if (!addr) {
 
215
        ARRAY8 tmpaddr;
 
216
        struct in_addr in;
 
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);
 
222
        if (*closure)
 
223
            return;
 
224
#endif
 
225
        in.s_addr = htonl(INADDR_ANY);
 
226
        tmpaddr.length = sizeof(in);
 
227
        tmpaddr.data = (CARD8Ptr) &in;
 
228
        updateListener(&tmpaddr, closure);
 
229
        return;
 
230
    }
 
231
 
 
232
    if (currentRequestPort == requestPort &&
 
233
        (s = findInList(listensocks, addr)))
 
234
    {
 
235
        *closure = (void *)s;
 
236
        s->ref = True;
 
237
        return;
 
238
    }
 
239
 
 
240
    if (!(s = createSocklistEntry(addr)))
 
241
        return;
 
242
 
 
243
    if ((s->fd = createListeningSocket(s->addr, s->salen)) < 0) {
 
244
        free(s->addr);
 
245
        free(s);
 
246
        return;
 
247
    }
 
248
    s->ref = True;
 
249
    s->next = listensocks;
 
250
    listensocks = s;
 
251
    *closure = (void *)s;
 
252
}
 
253
 
 
254
#define JOIN_MCAST_GROUP 0
 
255
#define LEAVE_MCAST_GROUP 1
 
256
 
 
257
static void
 
258
changeMcastMembership(struct socklist *s, struct socklist *g, int op)
 
259
{
 
260
    int sockopt;
 
261
 
 
262
    switch (s->addr->sa_family) {
 
263
    case AF_INET: {
 
264
        struct ip_mreq mreq;
 
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;
 
273
        else
 
274
            sockopt = IP_DROP_MEMBERSHIP;
 
275
        if (setsockopt(s->fd, IPPROTO_IP, sockopt,
 
276
                       &mreq, sizeof(mreq)) < 0)
 
277
        {
 
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),
 
281
                     errno);
 
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));
 
286
        }
 
287
        return; }
 
288
#if defined(IPv6) && defined(AF_INET6)
 
289
# ifndef IPV6_JOIN_GROUP
 
290
#  define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
 
291
# endif
 
292
# ifndef IPV6_LEAVE_GROUP
 
293
#  define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
 
294
# endif
 
295
    case AF_INET6: {
 
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;
 
303
        else
 
304
            sockopt = IPV6_LEAVE_GROUP;
 
305
        if (setsockopt(s->fd, IPPROTO_IPV6, sockopt,
 
306
                       &mreq6, sizeof(mreq6)) < 0)
 
307
        {
 
308
            int saveerr = errno;
 
309
            char addrbuf[INET6_ADDRSTRLEN];
 
310
 
 
311
            inet_ntop(s->addr->sa_family,
 
312
                      &((struct sockaddr_in6 *)g->addr)->sin6_addr,
 
313
                      addrbuf, sizeof(addrbuf));
 
314
 
 
315
            logError("XDMCP socket multicast %s to %s failed, errno %d\n",
 
316
                     (op == JOIN_MCAST_GROUP) ? "join" : "drop", addrbuf,
 
317
                     saveerr);
 
318
        } else if (debugLevel & DEBUG_CORE) {
 
319
            char addrbuf[INET6_ADDRSTRLEN];
 
320
 
 
321
            inet_ntop(s->addr->sa_family,
 
322
                      &((struct sockaddr_in6 *)g->addr)->sin6_addr,
 
323
                      addrbuf, sizeof(addrbuf));
 
324
 
 
325
            debug("XDMCP socket multicast %s to %s succeeded\n",
 
326
                  (op == JOIN_MCAST_GROUP) ? "join" : "drop", addrbuf);
 
327
        }
 
328
        return; }
 
329
#endif
 
330
    }
 
331
}
 
332
 
 
333
static void
 
334
updateMcastGroup(ARRAY8Ptr addr, void **closure)
 
335
{
 
336
    struct socklist *s = (struct socklist *)*closure;
 
337
    struct socklist *g;
 
338
 
 
339
    if (!s)
 
340
        return;
 
341
 
 
342
    /* Already in the group, mark & continue */
 
343
    if ((g = findInList(s->mcastgroups, addr))) {
 
344
        g->ref = True;
 
345
        return;
 
346
    }
 
347
 
 
348
    /* Need to join the group */
 
349
    if (!(g = createSocklistEntry(addr)))
 
350
        return;
 
351
 
 
352
    changeMcastMembership(s, g, JOIN_MCAST_GROUP);
 
353
    free(g);
 
354
}
 
355
 
 
356
/* Open or close listening sockets to match the current settings read in
 
357
   from the access database. */
 
358
void
 
359
updateListenSockets(void)
 
360
{
 
361
    struct socklist *s, *g, **ls, **lg;
 
362
    void *tmpPtr = 0;
 
363
 
 
364
    /* Clear Ref bits - any not marked by UpdateCallback will be closed */
 
365
    for (s = listensocks; s; s = s->next) {
 
366
        s->ref = False;
 
367
        for (g = s->mcastgroups; g; g = g->next)
 
368
            g->ref = False;
 
369
    }
 
370
    forEachListenAddr(updateListener, updateMcastGroup, &tmpPtr);
 
371
    currentRequestPort = requestPort;
 
372
    for (ls = &listensocks; (s = *ls);)
 
373
        if (!s->ref) {
 
374
            destroyListeningSocket(s);
 
375
            *ls = s->next;
 
376
            free(s);
 
377
        } else {
 
378
            ls = &s->next;
 
379
            for (lg = &s->mcastgroups; (g = *lg);)
 
380
                if (!g->ref) {
 
381
                    changeMcastMembership(s, g, LEAVE_MCAST_GROUP);
 
382
                    *lg = g->next;
 
383
                    free(g);
 
384
                } else {
 
385
                    lg = &g->next;
 
386
                }
 
387
        }
 
388
}
 
389
 
 
390
int
 
391
anyListenSockets(void)
 
392
{
 
393
    return listensocks != 0;
 
394
}
 
395
 
 
396
int
 
397
processListenSockets(fd_set *reads)
 
398
{
 
399
    struct socklist *s;
 
400
    int ret = False;
 
401
 
 
402
    for (s = listensocks; s; s = s->next)
 
403
        if (FD_ISSET(s->fd, reads)) {
 
404
            processRequestSocket(s->fd);
 
405
            ret = True;
 
406
        }
 
407
    return ret;
 
408
}
 
409
 
 
410
#endif /* !STREAMSCONN && XDMCP */