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