~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/lib/socket_wrapper.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
2
 
   Socket wrapper library. Passes all socket communication over 
3
 
   unix domain sockets if the environment variable SOCKET_WRAPPER_DIR 
4
 
   is set.
5
 
   Copyright (C) Jelmer Vernooij 2005
6
 
   
7
 
   This program is free software; you can redistribute it and/or modify
8
 
   it under the terms of the GNU General Public License as published by
9
 
   the Free Software Foundation; either version 2 of the License, or
10
 
   (at your option) any later version.
11
 
   
12
 
   This program is distributed in the hope that it will be useful,
13
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
   GNU General Public License for more details.
16
 
   
17
 
   You should have received a copy of the GNU General Public License
18
 
   along with this program; if not, write to the Free Software
19
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
 
*/
21
 
 
22
 
#include "includes.h"
23
 
 
24
 
#ifdef _PUBLIC_
25
 
#undef _PUBLIC_
26
 
#endif
27
 
#define _PUBLIC_
28
 
 
29
 
#ifdef SOCKET_WRAPPER_REPLACE
30
 
#undef accept
31
 
#undef connect
32
 
#undef bind
33
 
#undef getpeername
34
 
#undef getsockname
35
 
#undef getsockopt
36
 
#undef setsockopt
37
 
#undef recvfrom
38
 
#undef sendto
39
 
#undef socket
40
 
#undef close
41
 
#endif
42
 
 
43
 
/* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
44
 
 * for now */
45
 
#define REWRITE_CALLS 
46
 
 
47
 
#ifdef REWRITE_CALLS
48
 
#define real_accept accept
49
 
#define real_connect connect
50
 
#define real_bind bind
51
 
#define real_getpeername getpeername
52
 
#define real_getsockname getsockname
53
 
#define real_getsockopt getsockopt
54
 
#define real_setsockopt setsockopt
55
 
#define real_recvfrom recvfrom
56
 
#define real_sendto sendto
57
 
#define real_socket socket
58
 
#define real_close close
59
 
#endif
60
 
 
61
 
#undef malloc
62
 
#undef calloc
63
 
#undef strdup
64
 
/* we need to use a very terse format here as IRIX 6.4 silently
65
 
   truncates names to 16 chars, so if we use a longer name then we
66
 
   can't tell which port a packet came from with recvfrom() 
67
 
   
68
 
   with this format we have 8 chars left for the directory name
69
 
*/
70
 
#define SOCKET_FORMAT "%c%02X%04X"
71
 
#define SOCKET_TYPE_CHAR_TCP            'T'
72
 
#define SOCKET_TYPE_CHAR_UDP            'U'
73
 
 
74
 
static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
75
 
{
76
 
        struct sockaddr *ret = (struct sockaddr *)malloc(len);
77
 
        memcpy(ret, data, len);
78
 
        return ret;
79
 
}
80
 
 
81
 
struct socket_info
82
 
{
83
 
        int fd;
84
 
 
85
 
        int domain;
86
 
        int type;
87
 
        int protocol;
88
 
        int bound;
89
 
        int bcast;
90
 
 
91
 
        char *path;
92
 
        char *tmp_path;
93
 
 
94
 
        struct sockaddr *myname;
95
 
        socklen_t myname_len;
96
 
 
97
 
        struct sockaddr *peername;
98
 
        socklen_t peername_len;
99
 
 
100
 
        struct socket_info *prev, *next;
101
 
};
102
 
 
103
 
static struct socket_info *sockets = NULL;
104
 
 
105
 
 
106
 
static const char *socket_wrapper_dir(void)
107
 
{
108
 
        const char *s = getenv("SOCKET_WRAPPER_DIR");
109
 
        if (s == NULL) {
110
 
                return NULL;
111
 
        }
112
 
        if (strncmp(s, "./", 2) == 0) {
113
 
                s += 2;
114
 
        }
115
 
        return s;
116
 
}
117
 
 
118
 
static unsigned int socket_wrapper_default_iface(void)
119
 
{
120
 
        const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
121
 
        if (s) {
122
 
                unsigned int iface;
123
 
                if (sscanf(s, "%u", &iface) == 1) {
124
 
                        if (iface >= 1 && iface <= 0xFF) {
125
 
                                return iface;
126
 
                        }
127
 
                }
128
 
        }
129
 
 
130
 
        return 1;/* 127.0.0.1 */
131
 
}
132
 
 
133
 
static int convert_un_in(const struct sockaddr_un *un, struct sockaddr_in *in, socklen_t *len)
134
 
{
135
 
        unsigned int iface;
136
 
        unsigned int prt;
137
 
        const char *p;
138
 
        char type;
139
 
 
140
 
        if ((*len) < sizeof(struct sockaddr_in)) {
141
 
                return 0;
142
 
        }
143
 
 
144
 
        p = strrchr(un->sun_path, '/');
145
 
        if (p) p++; else p = un->sun_path;
146
 
 
147
 
        if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
148
 
                errno = EINVAL;
149
 
                return -1;
150
 
        }
151
 
 
152
 
        if (type != SOCKET_TYPE_CHAR_TCP && type != SOCKET_TYPE_CHAR_UDP) {
153
 
                errno = EINVAL;
154
 
                return -1;
155
 
        }
156
 
 
157
 
        if (iface == 0 || iface > 0xFF) {
158
 
                errno = EINVAL;
159
 
                return -1;
160
 
        }
161
 
 
162
 
        if (prt > 0xFFFF) {
163
 
                errno = EINVAL;
164
 
                return -1;
165
 
        }
166
 
 
167
 
        in->sin_family = AF_INET;
168
 
        in->sin_addr.s_addr = htonl((127<<24) | iface);
169
 
        in->sin_port = htons(prt);
170
 
 
171
 
        *len = sizeof(struct sockaddr_in);
172
 
        return 0;
173
 
}
174
 
 
175
 
static int convert_in_un_remote(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un,
176
 
                                int *bcast)
177
 
{
178
 
        char u_type = '\0';
179
 
        char b_type = '\0';
180
 
        char a_type = '\0';
181
 
        char type = '\0';
182
 
        unsigned int addr= ntohl(in->sin_addr.s_addr);
183
 
        unsigned int prt = ntohs(in->sin_port);
184
 
        unsigned int iface;
185
 
        int is_bcast = 0;
186
 
 
187
 
        if (bcast) *bcast = 0;
188
 
 
189
 
        if (prt == 0) {
190
 
                errno = EINVAL;
191
 
                return -1;
192
 
        }
193
 
 
194
 
        switch (si->type) {
195
 
        case SOCK_STREAM:
196
 
                u_type = SOCKET_TYPE_CHAR_TCP;
197
 
                break;
198
 
        case SOCK_DGRAM:
199
 
                u_type = SOCKET_TYPE_CHAR_UDP;
200
 
                a_type = SOCKET_TYPE_CHAR_UDP;
201
 
                b_type = SOCKET_TYPE_CHAR_UDP;
202
 
                break;
203
 
        }
204
 
 
205
 
        if (a_type && addr == 0xFFFFFFFF) {
206
 
                /* 255.255.255.255 only udp */
207
 
                is_bcast = 2;
208
 
                type = a_type;
209
 
                iface = socket_wrapper_default_iface();
210
 
        } else if (b_type && addr == 0x7FFFFFFF) {
211
 
                /* 127.255.255.255 only udp */
212
 
                is_bcast = 1;
213
 
                type = b_type;
214
 
                iface = socket_wrapper_default_iface();
215
 
        } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
216
 
                /* 127.0.0.X */
217
 
                is_bcast = 0;
218
 
                type = u_type;
219
 
                iface = (addr & 0x000000FF);
220
 
        } else {
221
 
                errno = ENETUNREACH;
222
 
                return -1;
223
 
        }
224
 
 
225
 
        if (bcast) *bcast = is_bcast;
226
 
 
227
 
        if (is_bcast) {
228
 
                snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL", 
229
 
                         socket_wrapper_dir());
230
 
                /* the caller need to do more processing */
231
 
                return 0;
232
 
        }
233
 
 
234
 
        snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
235
 
                 socket_wrapper_dir(), type, iface, prt);
236
 
 
237
 
        return 0;
238
 
}
239
 
 
240
 
static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un,
241
 
                               int *bcast)
242
 
{
243
 
        char u_type = '\0';
244
 
        char d_type = '\0';
245
 
        char b_type = '\0';
246
 
        char a_type = '\0';
247
 
        char type = '\0';
248
 
        unsigned int addr= ntohl(in->sin_addr.s_addr);
249
 
        unsigned int prt = ntohs(in->sin_port);
250
 
        unsigned int iface;
251
 
        struct stat st;
252
 
        int is_bcast = 0;
253
 
 
254
 
        if (bcast) *bcast = 0;
255
 
 
256
 
        switch (si->type) {
257
 
        case SOCK_STREAM:
258
 
                u_type = SOCKET_TYPE_CHAR_TCP;
259
 
                d_type = SOCKET_TYPE_CHAR_TCP;
260
 
                break;
261
 
        case SOCK_DGRAM:
262
 
                u_type = SOCKET_TYPE_CHAR_UDP;
263
 
                d_type = SOCKET_TYPE_CHAR_UDP;
264
 
                a_type = SOCKET_TYPE_CHAR_UDP;
265
 
                b_type = SOCKET_TYPE_CHAR_UDP;
266
 
                break;
267
 
        }
268
 
 
269
 
        if (addr == 0) {
270
 
                /* 0.0.0.0 */
271
 
                is_bcast = 0;
272
 
                type = d_type;
273
 
                iface = socket_wrapper_default_iface();
274
 
        } else if (a_type && addr == 0xFFFFFFFF) {
275
 
                /* 255.255.255.255 only udp */
276
 
                is_bcast = 2;
277
 
                type = a_type;
278
 
                iface = socket_wrapper_default_iface();
279
 
        } else if (b_type && addr == 0x7FFFFFFF) {
280
 
                /* 127.255.255.255 only udp */
281
 
                is_bcast = 1;
282
 
                type = b_type;
283
 
                iface = socket_wrapper_default_iface();
284
 
        } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
285
 
                /* 127.0.0.X */
286
 
                is_bcast = 0;
287
 
                type = u_type;
288
 
                iface = (addr & 0x000000FF);
289
 
        } else {
290
 
                errno = EADDRNOTAVAIL;
291
 
                return -1;
292
 
        }
293
 
 
294
 
        if (bcast) *bcast = is_bcast;
295
 
 
296
 
        if (prt == 0) {
297
 
                /* handle auto-allocation of ephemeral ports */
298
 
                for (prt = 5001; prt < 10000; prt++) {
299
 
                        snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
300
 
                                 socket_wrapper_dir(), type, iface, prt);
301
 
                        if (stat(un->sun_path, &st) == 0) continue;
302
 
 
303
 
                        ((struct sockaddr_in *)si->myname)->sin_port = htons(prt);
304
 
                        return 0;
305
 
                }
306
 
                errno = ENFILE;
307
 
                return -1;
308
 
        }
309
 
 
310
 
        snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
311
 
                 socket_wrapper_dir(), type, iface, prt);
312
 
        return 0;
313
 
}
314
 
 
315
 
static struct socket_info *find_socket_info(int fd)
316
 
{
317
 
        struct socket_info *i;
318
 
        for (i = sockets; i; i = i->next) {
319
 
                if (i->fd == fd) 
320
 
                        return i;
321
 
        }
322
 
 
323
 
        return NULL;
324
 
}
325
 
 
326
 
static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len, 
327
 
                                  struct sockaddr_un *out_addr, int alloc_sock, int *bcast)
328
 
{
329
 
        if (!out_addr)
330
 
                return 0;
331
 
 
332
 
        out_addr->sun_family = AF_UNIX;
333
 
 
334
 
        switch (in_addr->sa_family) {
335
 
        case AF_INET:
336
 
                switch (si->type) {
337
 
                case SOCK_STREAM:
338
 
                case SOCK_DGRAM:
339
 
                        break;
340
 
                default:
341
 
                        errno = ESOCKTNOSUPPORT;
342
 
                        return -1;
343
 
                }
344
 
                if (alloc_sock) {
345
 
                        return convert_in_un_alloc(si, (const struct sockaddr_in *)in_addr, out_addr, bcast);
346
 
                } else {
347
 
                        return convert_in_un_remote(si, (const struct sockaddr_in *)in_addr, out_addr, bcast);
348
 
                }
349
 
        case AF_UNIX:
350
 
                memcpy(out_addr, in_addr, sizeof(*out_addr));
351
 
                return 0;
352
 
        default:
353
 
                break;
354
 
        }
355
 
        
356
 
        errno = EAFNOSUPPORT;
357
 
        return -1;
358
 
}
359
 
 
360
 
static int sockaddr_convert_from_un(const struct socket_info *si, 
361
 
                                    const struct sockaddr_un *in_addr, 
362
 
                                    socklen_t un_addrlen,
363
 
                                    int family,
364
 
                                    struct sockaddr *out_addr,
365
 
                                    socklen_t *_out_addrlen)
366
 
{
367
 
        socklen_t out_addrlen;
368
 
 
369
 
        if (out_addr == NULL || _out_addrlen == NULL) 
370
 
                return 0;
371
 
 
372
 
        if (un_addrlen == 0) {
373
 
                *_out_addrlen = 0;
374
 
                return 0;
375
 
        }
376
 
 
377
 
        out_addrlen = *_out_addrlen;
378
 
        if (out_addrlen > un_addrlen) {
379
 
                out_addrlen = un_addrlen;
380
 
        }
381
 
 
382
 
        switch (family) {
383
 
        case AF_INET:
384
 
                switch (si->type) {
385
 
                case SOCK_STREAM:
386
 
                case SOCK_DGRAM:
387
 
                        break;
388
 
                default:
389
 
                        errno = ESOCKTNOSUPPORT;
390
 
                        return -1;
391
 
                }
392
 
                return convert_un_in(in_addr, (struct sockaddr_in *)out_addr, _out_addrlen);
393
 
        case AF_UNIX:
394
 
                memcpy(out_addr, in_addr, out_addrlen);
395
 
                *_out_addrlen = out_addrlen;
396
 
                return 0;
397
 
        default:
398
 
                break;
399
 
        }
400
 
 
401
 
        errno = EAFNOSUPPORT;
402
 
        return -1;
403
 
}
404
 
 
405
 
_PUBLIC_ int swrap_socket(int domain, int type, int protocol)
406
 
{
407
 
        struct socket_info *si;
408
 
        int fd;
409
 
 
410
 
        if (!socket_wrapper_dir()) {
411
 
                return real_socket(domain, type, protocol);
412
 
        }
413
 
        
414
 
        si = (struct socket_info *)calloc(1, sizeof(struct socket_info));
415
 
        if (si == NULL) {
416
 
                errno = ENOMEM;
417
 
                return -1;
418
 
        }
419
 
 
420
 
        fd = real_socket(AF_UNIX, type, 0);
421
 
 
422
 
        if (fd == -1) return -1;
423
 
 
424
 
        si->domain = domain;
425
 
        si->type = type;
426
 
        si->protocol = protocol;
427
 
        si->fd = fd;
428
 
 
429
 
        DLIST_ADD(sockets, si);
430
 
 
431
 
        return si->fd;
432
 
}
433
 
 
434
 
_PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
435
 
{
436
 
        struct socket_info *parent_si, *child_si;
437
 
        int fd;
438
 
        struct sockaddr_un un_addr;
439
 
        socklen_t un_addrlen = sizeof(un_addr);
440
 
        struct sockaddr_un un_my_addr;
441
 
        socklen_t un_my_addrlen = sizeof(un_my_addr);
442
 
        struct sockaddr my_addr;
443
 
        socklen_t my_addrlen = sizeof(my_addr);
444
 
        int ret;
445
 
 
446
 
        parent_si = find_socket_info(s);
447
 
        if (!parent_si) {
448
 
                return real_accept(s, addr, addrlen);
449
 
        }
450
 
 
451
 
        memset(&un_addr, 0, sizeof(un_addr));
452
 
        memset(&un_my_addr, 0, sizeof(un_my_addr));
453
 
        memset(&my_addr, 0, sizeof(my_addr));
454
 
 
455
 
        ret = real_accept(s, (struct sockaddr *)&un_addr, &un_addrlen);
456
 
        if (ret == -1) return ret;
457
 
 
458
 
        fd = ret;
459
 
 
460
 
        ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
461
 
                                       parent_si->domain, addr, addrlen);
462
 
        if (ret == -1) return ret;
463
 
 
464
 
        child_si = (struct socket_info *)malloc(sizeof(struct socket_info));
465
 
        if (child_si == NULL) {
466
 
                close(fd);
467
 
                errno = ENOMEM;
468
 
                return -1;
469
 
        }
470
 
        memset(child_si, 0, sizeof(*child_si));
471
 
 
472
 
        child_si->fd = fd;
473
 
        child_si->domain = parent_si->domain;
474
 
        child_si->type = parent_si->type;
475
 
        child_si->protocol = parent_si->protocol;
476
 
        child_si->bound = 1;
477
 
 
478
 
        ret = real_getsockname(fd, (struct sockaddr *)&un_my_addr, &un_my_addrlen);
479
 
        if (ret == -1) return ret;
480
 
 
481
 
        ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
482
 
                                       child_si->domain, &my_addr, &my_addrlen);
483
 
        if (ret == -1) return ret;
484
 
 
485
 
        child_si->myname_len = my_addrlen;
486
 
        child_si->myname = sockaddr_dup(&my_addr, my_addrlen);
487
 
 
488
 
        child_si->peername_len = *addrlen;
489
 
        child_si->peername = sockaddr_dup(addr, *addrlen);
490
 
 
491
 
        DLIST_ADD(sockets, child_si);
492
 
 
493
 
        return fd;
494
 
}
495
 
 
496
 
/* using sendto() or connect() on an unbound socket would give the
497
 
   recipient no way to reply, as unlike UDP and TCP, a unix domain
498
 
   socket can't auto-assign emphemeral port numbers, so we need to
499
 
   assign it here */
500
 
static int swrap_auto_bind(struct socket_info *si)
501
 
{
502
 
        struct sockaddr_un un_addr;
503
 
        struct sockaddr_in in;
504
 
        int i;
505
 
        char type;
506
 
        int ret;
507
 
        struct stat st;
508
 
        
509
 
        un_addr.sun_family = AF_UNIX;
510
 
 
511
 
        switch (si->type) {
512
 
        case SOCK_STREAM:
513
 
                type = SOCKET_TYPE_CHAR_TCP;
514
 
                break;
515
 
        case SOCK_DGRAM:
516
 
                type = SOCKET_TYPE_CHAR_UDP;
517
 
                break;
518
 
        default:
519
 
                errno = ESOCKTNOSUPPORT;
520
 
                return -1;
521
 
        }
522
 
        
523
 
        for (i=0;i<1000;i++) {
524
 
                snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), 
525
 
                         "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
526
 
                         type, socket_wrapper_default_iface(), i + 10000);
527
 
                if (stat(un_addr.sun_path, &st) == 0) continue;
528
 
                
529
 
                ret = real_bind(si->fd, (struct sockaddr *)&un_addr, sizeof(un_addr));
530
 
                if (ret == -1) return ret;
531
 
 
532
 
                si->tmp_path = strdup(un_addr.sun_path);
533
 
                si->bound = 1;
534
 
                break;
535
 
        }
536
 
        if (i == 1000) {
537
 
                errno = ENFILE;
538
 
                return -1;
539
 
        }
540
 
        
541
 
        memset(&in, 0, sizeof(in));
542
 
        in.sin_family = AF_INET;
543
 
        in.sin_port   = htons(i);
544
 
        in.sin_addr.s_addr = htonl(127<<24 | socket_wrapper_default_iface());
545
 
        
546
 
        si->myname_len = sizeof(in);
547
 
        si->myname = sockaddr_dup(&in, si->myname_len);
548
 
        si->bound = 1;
549
 
        return 0;
550
 
}
551
 
 
552
 
 
553
 
_PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
554
 
{
555
 
        int ret;
556
 
        struct sockaddr_un un_addr;
557
 
        struct socket_info *si = find_socket_info(s);
558
 
 
559
 
        if (!si) {
560
 
                return real_connect(s, serv_addr, addrlen);
561
 
        }
562
 
 
563
 
        if (si->bound == 0 && si->domain != AF_UNIX) {
564
 
                ret = swrap_auto_bind(si);
565
 
                if (ret == -1) return -1;
566
 
        }
567
 
 
568
 
        ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr, 0, NULL);
569
 
        if (ret == -1) return -1;
570
 
 
571
 
        ret = real_connect(s, (struct sockaddr *)&un_addr, 
572
 
                           sizeof(struct sockaddr_un));
573
 
 
574
 
        /* to give better errors */
575
 
        if (serv_addr->sa_family == AF_INET) {
576
 
                if (ret == -1 && errno == ENOENT) {
577
 
                        errno = EHOSTUNREACH;
578
 
                }
579
 
        }
580
 
 
581
 
        if (ret == 0) {
582
 
                si->peername_len = addrlen;
583
 
                si->peername = sockaddr_dup(serv_addr, addrlen);
584
 
        }
585
 
 
586
 
        return ret;
587
 
}
588
 
 
589
 
_PUBLIC_ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
590
 
{
591
 
        int ret;
592
 
        struct sockaddr_un un_addr;
593
 
        struct socket_info *si = find_socket_info(s);
594
 
 
595
 
        if (!si) {
596
 
                return real_bind(s, myaddr, addrlen);
597
 
        }
598
 
 
599
 
        si->myname_len = addrlen;
600
 
        si->myname = sockaddr_dup(myaddr, addrlen);
601
 
 
602
 
        ret = sockaddr_convert_to_un(si, (const struct sockaddr *)myaddr, addrlen, &un_addr, 1, &si->bcast);
603
 
        if (ret == -1) return -1;
604
 
 
605
 
        unlink(un_addr.sun_path);
606
 
 
607
 
        ret = real_bind(s, (struct sockaddr *)&un_addr,
608
 
                        sizeof(struct sockaddr_un));
609
 
 
610
 
        if (ret == 0) {
611
 
                si->bound = 1;
612
 
        }
613
 
 
614
 
        return ret;
615
 
}
616
 
 
617
 
_PUBLIC_ int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
618
 
{
619
 
        struct socket_info *si = find_socket_info(s);
620
 
 
621
 
        if (!si) {
622
 
                return real_getpeername(s, name, addrlen);
623
 
        }
624
 
 
625
 
        if (!si->peername) 
626
 
        {
627
 
                errno = ENOTCONN;
628
 
                return -1;
629
 
        }
630
 
 
631
 
        memcpy(name, si->peername, si->peername_len);
632
 
        *addrlen = si->peername_len;
633
 
 
634
 
        return 0;
635
 
}
636
 
 
637
 
_PUBLIC_ int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
638
 
{
639
 
        struct socket_info *si = find_socket_info(s);
640
 
 
641
 
        if (!si) {
642
 
                return real_getsockname(s, name, addrlen);
643
 
        }
644
 
 
645
 
        memcpy(name, si->myname, si->myname_len);
646
 
        *addrlen = si->myname_len;
647
 
 
648
 
        return 0;
649
 
}
650
 
 
651
 
_PUBLIC_ int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
652
 
{
653
 
        struct socket_info *si = find_socket_info(s);
654
 
 
655
 
        if (!si) {
656
 
                return real_getsockopt(s, level, optname, optval, optlen);
657
 
        }
658
 
 
659
 
        if (level == SOL_SOCKET) {
660
 
                return real_getsockopt(s, level, optname, optval, optlen);
661
 
        } 
662
 
 
663
 
        switch (si->domain) {
664
 
        case AF_UNIX:
665
 
                return real_getsockopt(s, level, optname, optval, optlen);
666
 
        default:
667
 
                errno = ENOPROTOOPT;
668
 
                return -1;
669
 
        }
670
 
}
671
 
 
672
 
_PUBLIC_ int swrap_setsockopt(int s, int  level,  int  optname,  const  void  *optval, socklen_t optlen)
673
 
{
674
 
        struct socket_info *si = find_socket_info(s);
675
 
 
676
 
        if (!si) {
677
 
                return real_setsockopt(s, level, optname, optval, optlen);
678
 
        }
679
 
 
680
 
        if (level == SOL_SOCKET) {
681
 
                return real_setsockopt(s, level, optname, optval, optlen);
682
 
        }
683
 
 
684
 
        switch (si->domain) {
685
 
        case AF_UNIX:
686
 
                return real_setsockopt(s, level, optname, optval, optlen);
687
 
        case AF_INET:
688
 
                /* Silence some warnings */
689
 
#ifdef TCP_NODELAY
690
 
                if (optname == TCP_NODELAY) 
691
 
                        return 0;
692
 
#endif
693
 
        default:
694
 
                errno = ENOPROTOOPT;
695
 
                return -1;
696
 
        }
697
 
}
698
 
 
699
 
_PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
700
 
{
701
 
        struct sockaddr_un un_addr;
702
 
        socklen_t un_addrlen = sizeof(un_addr);
703
 
        int ret;
704
 
        struct socket_info *si = find_socket_info(s);
705
 
 
706
 
        if (!si) {
707
 
                return real_recvfrom(s, buf, len, flags, from, fromlen);
708
 
        }
709
 
 
710
 
        /* irix 6.4 forgets to null terminate the sun_path string :-( */
711
 
        memset(&un_addr, 0, sizeof(un_addr));
712
 
        ret = real_recvfrom(s, buf, len, flags, (struct sockaddr *)&un_addr, &un_addrlen);
713
 
        if (ret == -1) 
714
 
                return ret;
715
 
 
716
 
        if (sockaddr_convert_from_un(si, &un_addr, un_addrlen,
717
 
                                     si->domain, from, fromlen) == -1) {
718
 
                return -1;
719
 
        }
720
 
        
721
 
        return ret;
722
 
}
723
 
 
724
 
 
725
 
_PUBLIC_ ssize_t swrap_sendto(int  s,  const  void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
726
 
{
727
 
        struct sockaddr_un un_addr;
728
 
        int ret;
729
 
        struct socket_info *si = find_socket_info(s);
730
 
        int bcast = 0;
731
 
 
732
 
        if (!si) {
733
 
                return real_sendto(s, buf, len, flags, to, tolen);
734
 
        }
735
 
 
736
 
        if (si->bound == 0 && si->domain != AF_UNIX) {
737
 
                ret = swrap_auto_bind(si);
738
 
                if (ret == -1) return -1;
739
 
        }
740
 
 
741
 
        ret = sockaddr_convert_to_un(si, to, tolen, &un_addr, 0, &bcast);
742
 
        if (ret == -1) return -1;
743
 
 
744
 
        if (bcast) {
745
 
                struct stat st;
746
 
                unsigned int iface;
747
 
                unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
748
 
                char type;
749
 
 
750
 
                type = SOCKET_TYPE_CHAR_UDP;
751
 
 
752
 
                for(iface=0; iface <= 0xFF; iface++) {
753
 
                        snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT, 
754
 
                                 socket_wrapper_dir(), type, iface, prt);
755
 
                        if (stat(un_addr.sun_path, &st) != 0) continue;
756
 
 
757
 
                        /* ignore the any errors in broadcast sends */
758
 
                        real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
759
 
                }
760
 
                return len;
761
 
        }
762
 
 
763
 
        ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
764
 
 
765
 
        /* to give better errors */
766
 
        if (to->sa_family == AF_INET) {
767
 
                if (ret == -1 && errno == ENOENT) {
768
 
                        errno = EHOSTUNREACH;
769
 
                }
770
 
        }
771
 
 
772
 
        return ret;
773
 
}
774
 
 
775
 
_PUBLIC_ int swrap_close(int fd)
776
 
{
777
 
        struct socket_info *si = find_socket_info(fd);
778
 
 
779
 
        if (si) {
780
 
                DLIST_REMOVE(sockets, si);
781
 
 
782
 
                free(si->path);
783
 
                free(si->myname);
784
 
                free(si->peername);
785
 
                if (si->tmp_path) {
786
 
                        unlink(si->tmp_path);
787
 
                        free(si->tmp_path);
788
 
                }
789
 
                free(si);
790
 
        }
791
 
 
792
 
        return real_close(fd);
793
 
}