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