lib/tsocket: fix loop in tdgram_bsd_recvfrom() (bug #9184)
[metze/samba/wip.git] / lib / tsocket / tsocket_bsd.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2009
5
6      ** NOTE! The following LGPL license applies to the tsocket
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 3 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "replace.h"
25 #include "system/filesys.h"
26 #include "system/network.h"
27 #include "tsocket.h"
28 #include "tsocket_internal.h"
29
30 static int tsocket_bsd_error_from_errno(int ret,
31                                         int sys_errno,
32                                         bool *retry)
33 {
34         *retry = false;
35
36         if (ret >= 0) {
37                 return 0;
38         }
39
40         if (ret != -1) {
41                 return EIO;
42         }
43
44         if (sys_errno == 0) {
45                 return EIO;
46         }
47
48         if (sys_errno == EINTR) {
49                 *retry = true;
50                 return sys_errno;
51         }
52
53         if (sys_errno == EINPROGRESS) {
54                 *retry = true;
55                 return sys_errno;
56         }
57
58         if (sys_errno == EAGAIN) {
59                 *retry = true;
60                 return sys_errno;
61         }
62
63 #ifdef EWOULDBLOCK
64         if (sys_errno == EWOULDBLOCK) {
65                 *retry = true;
66                 return sys_errno;
67         }
68 #endif
69
70         return sys_errno;
71 }
72
73 static int tsocket_bsd_common_prepare_fd(int fd, bool high_fd)
74 {
75         int i;
76         int sys_errno = 0;
77         int fds[3];
78         int num_fds = 0;
79
80         int result, flags;
81
82         if (fd == -1) {
83                 return -1;
84         }
85
86         /* first make a fd >= 3 */
87         if (high_fd) {
88                 while (fd < 3) {
89                         fds[num_fds++] = fd;
90                         fd = dup(fd);
91                         if (fd == -1) {
92                                 sys_errno = errno;
93                                 break;
94                         }
95                 }
96                 for (i=0; i<num_fds; i++) {
97                         close(fds[i]);
98                 }
99                 if (fd == -1) {
100                         errno = sys_errno;
101                         return fd;
102                 }
103         }
104
105         /* fd should be nonblocking. */
106
107 #ifdef O_NONBLOCK
108 #define FLAG_TO_SET O_NONBLOCK
109 #else
110 #ifdef SYSV
111 #define FLAG_TO_SET O_NDELAY
112 #else /* BSD */
113 #define FLAG_TO_SET FNDELAY
114 #endif
115 #endif
116
117         if ((flags = fcntl(fd, F_GETFL)) == -1) {
118                 goto fail;
119         }
120
121         flags |= FLAG_TO_SET;
122         if (fcntl(fd, F_SETFL, flags) == -1) {
123                 goto fail;
124         }
125
126 #undef FLAG_TO_SET
127
128         /* fd should be closed on exec() */
129 #ifdef FD_CLOEXEC
130         result = flags = fcntl(fd, F_GETFD, 0);
131         if (flags >= 0) {
132                 flags |= FD_CLOEXEC;
133                 result = fcntl(fd, F_SETFD, flags);
134         }
135         if (result < 0) {
136                 goto fail;
137         }
138 #endif
139         return fd;
140
141  fail:
142         if (fd != -1) {
143                 sys_errno = errno;
144                 close(fd);
145                 errno = sys_errno;
146         }
147         return -1;
148 }
149
150 static ssize_t tsocket_bsd_pending(int fd)
151 {
152         int ret, error;
153         int value = 0;
154         socklen_t len;
155
156         ret = ioctl(fd, FIONREAD, &value);
157         if (ret == -1) {
158                 return ret;
159         }
160
161         if (ret != 0) {
162                 /* this should not be reached */
163                 errno = EIO;
164                 return -1;
165         }
166
167         if (value != 0) {
168                 return value;
169         }
170
171         error = 0;
172         len = sizeof(error);
173
174         /*
175          * if no data is available check if the socket is in error state. For
176          * dgram sockets it's the way to return ICMP error messages of
177          * connected sockets to the caller.
178          */
179         ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
180         if (ret == -1) {
181                 return ret;
182         }
183         if (error != 0) {
184                 errno = error;
185                 return -1;
186         }
187         return 0;
188 }
189
190 static const struct tsocket_address_ops tsocket_address_bsd_ops;
191
192 struct tsocket_address_bsd {
193         socklen_t sa_socklen;
194         union {
195                 struct sockaddr sa;
196                 struct sockaddr_in in;
197 #ifdef HAVE_IPV6
198                 struct sockaddr_in6 in6;
199 #endif
200                 struct sockaddr_un un;
201                 struct sockaddr_storage ss;
202         } u;
203 };
204
205 int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
206                                        struct sockaddr *sa,
207                                        size_t sa_socklen,
208                                        struct tsocket_address **_addr,
209                                        const char *location)
210 {
211         struct tsocket_address *addr;
212         struct tsocket_address_bsd *bsda;
213
214         if (sa_socklen < sizeof(sa->sa_family)) {
215                 errno = EINVAL;
216                 return -1;
217         }
218
219         switch (sa->sa_family) {
220         case AF_UNIX:
221                 if (sa_socklen > sizeof(struct sockaddr_un)) {
222                         sa_socklen = sizeof(struct sockaddr_un);
223                 }
224                 break;
225         case AF_INET:
226                 if (sa_socklen < sizeof(struct sockaddr_in)) {
227                         errno = EINVAL;
228                         return -1;
229                 }
230                 sa_socklen = sizeof(struct sockaddr_in);
231                 break;
232 #ifdef HAVE_IPV6
233         case AF_INET6:
234                 if (sa_socklen < sizeof(struct sockaddr_in6)) {
235                         errno = EINVAL;
236                         return -1;
237                 }
238                 sa_socklen = sizeof(struct sockaddr_in6);
239                 break;
240 #endif
241         default:
242                 errno = EAFNOSUPPORT;
243                 return -1;
244         }
245
246         if (sa_socklen > sizeof(struct sockaddr_storage)) {
247                 errno = EINVAL;
248                 return -1;
249         }
250
251         addr = tsocket_address_create(mem_ctx,
252                                       &tsocket_address_bsd_ops,
253                                       &bsda,
254                                       struct tsocket_address_bsd,
255                                       location);
256         if (!addr) {
257                 errno = ENOMEM;
258                 return -1;
259         }
260
261         ZERO_STRUCTP(bsda);
262
263         memcpy(&bsda->u.ss, sa, sa_socklen);
264
265         bsda->sa_socklen = sa_socklen;
266 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
267         bsda->u.sa.sa_len = bsda->sa_socklen;
268 #endif
269
270         *_addr = addr;
271         return 0;
272 }
273
274 ssize_t tsocket_address_bsd_sockaddr(const struct tsocket_address *addr,
275                                      struct sockaddr *sa,
276                                      size_t sa_socklen)
277 {
278         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
279                                            struct tsocket_address_bsd);
280
281         if (!bsda) {
282                 errno = EINVAL;
283                 return -1;
284         }
285
286         if (sa_socklen < bsda->sa_socklen) {
287                 errno = EINVAL;
288                 return -1;
289         }
290
291         if (sa_socklen > bsda->sa_socklen) {
292                 memset(sa, 0, sa_socklen);
293                 sa_socklen = bsda->sa_socklen;
294         }
295
296         memcpy(sa, &bsda->u.ss, sa_socklen);
297 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
298         sa->sa_len = sa_socklen;
299 #endif
300         return sa_socklen;
301 }
302
303 bool tsocket_address_is_inet(const struct tsocket_address *addr, const char *fam)
304 {
305         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
306                                            struct tsocket_address_bsd);
307
308         if (!bsda) {
309                 return false;
310         }
311
312         switch (bsda->u.sa.sa_family) {
313         case AF_INET:
314                 if (strcasecmp(fam, "ip") == 0) {
315                         return true;
316                 }
317
318                 if (strcasecmp(fam, "ipv4") == 0) {
319                         return true;
320                 }
321
322                 return false;
323 #ifdef HAVE_IPV6
324         case AF_INET6:
325                 if (strcasecmp(fam, "ip") == 0) {
326                         return true;
327                 }
328
329                 if (strcasecmp(fam, "ipv6") == 0) {
330                         return true;
331                 }
332
333                 return false;
334 #endif
335         }
336
337         return false;
338 }
339
340 int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
341                                        const char *fam,
342                                        const char *addr,
343                                        uint16_t port,
344                                        struct tsocket_address **_addr,
345                                        const char *location)
346 {
347         struct addrinfo hints;
348         struct addrinfo *result = NULL;
349         char port_str[6];
350         int ret;
351
352         ZERO_STRUCT(hints);
353         /*
354          * we use SOCKET_STREAM here to get just one result
355          * back from getaddrinfo().
356          */
357         hints.ai_socktype = SOCK_STREAM;
358         hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
359
360         if (strcasecmp(fam, "ip") == 0) {
361                 hints.ai_family = AF_UNSPEC;
362                 if (!addr) {
363 #ifdef HAVE_IPV6
364                         addr = "::";
365 #else
366                         addr = "0.0.0.0";
367 #endif
368                 }
369         } else if (strcasecmp(fam, "ipv4") == 0) {
370                 hints.ai_family = AF_INET;
371                 if (!addr) {
372                         addr = "0.0.0.0";
373                 }
374 #ifdef HAVE_IPV6
375         } else if (strcasecmp(fam, "ipv6") == 0) {
376                 hints.ai_family = AF_INET6;
377                 if (!addr) {
378                         addr = "::";
379                 }
380 #endif
381         } else {
382                 errno = EAFNOSUPPORT;
383                 return -1;
384         }
385
386         snprintf(port_str, sizeof(port_str) - 1, "%u", port);
387
388         ret = getaddrinfo(addr, port_str, &hints, &result);
389         if (ret != 0) {
390                 switch (ret) {
391                 case EAI_FAIL:
392                         errno = EINVAL;
393                         break;
394                 }
395                 ret = -1;
396                 goto done;
397         }
398
399         if (result->ai_socktype != SOCK_STREAM) {
400                 errno = EINVAL;
401                 ret = -1;
402                 goto done;
403         }
404
405         ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
406                                                   result->ai_addr,
407                                                   result->ai_addrlen,
408                                                   _addr,
409                                                   location);
410
411 done:
412         if (result) {
413                 freeaddrinfo(result);
414         }
415         return ret;
416 }
417
418 char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
419                                        TALLOC_CTX *mem_ctx)
420 {
421         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
422                                            struct tsocket_address_bsd);
423         char addr_str[INET6_ADDRSTRLEN+1];
424         const char *str;
425
426         if (!bsda) {
427                 errno = EINVAL;
428                 return NULL;
429         }
430
431         switch (bsda->u.sa.sa_family) {
432         case AF_INET:
433                 str = inet_ntop(bsda->u.in.sin_family,
434                                 &bsda->u.in.sin_addr,
435                                 addr_str, sizeof(addr_str));
436                 break;
437 #ifdef HAVE_IPV6
438         case AF_INET6:
439                 str = inet_ntop(bsda->u.in6.sin6_family,
440                                 &bsda->u.in6.sin6_addr,
441                                 addr_str, sizeof(addr_str));
442                 break;
443 #endif
444         default:
445                 errno = EINVAL;
446                 return NULL;
447         }
448
449         if (!str) {
450                 return NULL;
451         }
452
453         return talloc_strdup(mem_ctx, str);
454 }
455
456 uint16_t tsocket_address_inet_port(const struct tsocket_address *addr)
457 {
458         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
459                                            struct tsocket_address_bsd);
460         uint16_t port = 0;
461
462         if (!bsda) {
463                 errno = EINVAL;
464                 return 0;
465         }
466
467         switch (bsda->u.sa.sa_family) {
468         case AF_INET:
469                 port = ntohs(bsda->u.in.sin_port);
470                 break;
471 #ifdef HAVE_IPV6
472         case AF_INET6:
473                 port = ntohs(bsda->u.in6.sin6_port);
474                 break;
475 #endif
476         default:
477                 errno = EINVAL;
478                 return 0;
479         }
480
481         return port;
482 }
483
484 int tsocket_address_inet_set_port(struct tsocket_address *addr,
485                                   uint16_t port)
486 {
487         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
488                                            struct tsocket_address_bsd);
489
490         if (!bsda) {
491                 errno = EINVAL;
492                 return -1;
493         }
494
495         switch (bsda->u.sa.sa_family) {
496         case AF_INET:
497                 bsda->u.in.sin_port = htons(port);
498                 break;
499 #ifdef HAVE_IPV6
500         case AF_INET6:
501                 bsda->u.in6.sin6_port = htons(port);
502                 break;
503 #endif
504         default:
505                 errno = EINVAL;
506                 return -1;
507         }
508
509         return 0;
510 }
511
512 bool tsocket_address_is_unix(const struct tsocket_address *addr)
513 {
514         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
515                                            struct tsocket_address_bsd);
516
517         if (!bsda) {
518                 return false;
519         }
520
521         switch (bsda->u.sa.sa_family) {
522         case AF_UNIX:
523                 return true;
524         }
525
526         return false;
527 }
528
529 int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
530                                     const char *path,
531                                     struct tsocket_address **_addr,
532                                     const char *location)
533 {
534         struct sockaddr_un un;
535         void *p = &un;
536         int ret;
537
538         if (!path) {
539                 path = "";
540         }
541
542         if (strlen(path) > sizeof(un.sun_path)-1) {
543                 errno = ENAMETOOLONG;
544                 return -1;
545         }
546
547         ZERO_STRUCT(un);
548         un.sun_family = AF_UNIX;
549         strncpy(un.sun_path, path, sizeof(un.sun_path)-1);
550
551         ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
552                                                  (struct sockaddr *)p,
553                                                  sizeof(un),
554                                                  _addr,
555                                                  location);
556
557         return ret;
558 }
559
560 char *tsocket_address_unix_path(const struct tsocket_address *addr,
561                                 TALLOC_CTX *mem_ctx)
562 {
563         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
564                                            struct tsocket_address_bsd);
565         const char *str;
566
567         if (!bsda) {
568                 errno = EINVAL;
569                 return NULL;
570         }
571
572         switch (bsda->u.sa.sa_family) {
573         case AF_UNIX:
574                 str = bsda->u.un.sun_path;
575                 break;
576         default:
577                 errno = EINVAL;
578                 return NULL;
579         }
580
581         return talloc_strdup(mem_ctx, str);
582 }
583
584 static char *tsocket_address_bsd_string(const struct tsocket_address *addr,
585                                         TALLOC_CTX *mem_ctx)
586 {
587         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
588                                            struct tsocket_address_bsd);
589         char *str;
590         char *addr_str;
591         const char *prefix = NULL;
592         uint16_t port;
593
594         switch (bsda->u.sa.sa_family) {
595         case AF_UNIX:
596                 return talloc_asprintf(mem_ctx, "unix:%s",
597                                        bsda->u.un.sun_path);
598         case AF_INET:
599                 prefix = "ipv4";
600                 break;
601 #ifdef HAVE_IPV6
602         case AF_INET6:
603                 prefix = "ipv6";
604                 break;
605 #endif
606         default:
607                 errno = EINVAL;
608                 return NULL;
609         }
610
611         addr_str = tsocket_address_inet_addr_string(addr, mem_ctx);
612         if (!addr_str) {
613                 return NULL;
614         }
615
616         port = tsocket_address_inet_port(addr);
617
618         str = talloc_asprintf(mem_ctx, "%s:%s:%u",
619                               prefix, addr_str, port);
620         talloc_free(addr_str);
621
622         return str;
623 }
624
625 static struct tsocket_address *tsocket_address_bsd_copy(const struct tsocket_address *addr,
626                                                          TALLOC_CTX *mem_ctx,
627                                                          const char *location)
628 {
629         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
630                                            struct tsocket_address_bsd);
631         struct tsocket_address *copy;
632         int ret;
633
634         ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
635                                                  &bsda->u.sa,
636                                                  bsda->sa_socklen,
637                                                  &copy,
638                                                  location);
639         if (ret != 0) {
640                 return NULL;
641         }
642
643         return copy;
644 }
645
646 static const struct tsocket_address_ops tsocket_address_bsd_ops = {
647         .name           = "bsd",
648         .string         = tsocket_address_bsd_string,
649         .copy           = tsocket_address_bsd_copy,
650 };
651
652 struct tdgram_bsd {
653         int fd;
654
655         void *event_ptr;
656         struct tevent_fd *fde;
657
658         void *readable_private;
659         void (*readable_handler)(void *private_data);
660         void *writeable_private;
661         void (*writeable_handler)(void *private_data);
662 };
663
664 static void tdgram_bsd_fde_handler(struct tevent_context *ev,
665                                    struct tevent_fd *fde,
666                                    uint16_t flags,
667                                    void *private_data)
668 {
669         struct tdgram_bsd *bsds = talloc_get_type_abort(private_data,
670                                   struct tdgram_bsd);
671
672         if (flags & TEVENT_FD_WRITE) {
673                 bsds->writeable_handler(bsds->writeable_private);
674                 return;
675         }
676         if (flags & TEVENT_FD_READ) {
677                 if (!bsds->readable_handler) {
678                         TEVENT_FD_NOT_READABLE(bsds->fde);
679                         return;
680                 }
681                 bsds->readable_handler(bsds->readable_private);
682                 return;
683         }
684 }
685
686 static int tdgram_bsd_set_readable_handler(struct tdgram_bsd *bsds,
687                                            struct tevent_context *ev,
688                                            void (*handler)(void *private_data),
689                                            void *private_data)
690 {
691         if (ev == NULL) {
692                 if (handler) {
693                         errno = EINVAL;
694                         return -1;
695                 }
696                 if (!bsds->readable_handler) {
697                         return 0;
698                 }
699                 bsds->readable_handler = NULL;
700                 bsds->readable_private = NULL;
701
702                 return 0;
703         }
704
705         /* read and write must use the same tevent_context */
706         if (bsds->event_ptr != ev) {
707                 if (bsds->readable_handler || bsds->writeable_handler) {
708                         errno = EINVAL;
709                         return -1;
710                 }
711                 bsds->event_ptr = NULL;
712                 TALLOC_FREE(bsds->fde);
713         }
714
715         if (tevent_fd_get_flags(bsds->fde) == 0) {
716                 TALLOC_FREE(bsds->fde);
717
718                 bsds->fde = tevent_add_fd(ev, bsds,
719                                           bsds->fd, TEVENT_FD_READ,
720                                           tdgram_bsd_fde_handler,
721                                           bsds);
722                 if (!bsds->fde) {
723                         errno = ENOMEM;
724                         return -1;
725                 }
726
727                 /* cache the event context we're running on */
728                 bsds->event_ptr = ev;
729         } else if (!bsds->readable_handler) {
730                 TEVENT_FD_READABLE(bsds->fde);
731         }
732
733         bsds->readable_handler = handler;
734         bsds->readable_private = private_data;
735
736         return 0;
737 }
738
739 static int tdgram_bsd_set_writeable_handler(struct tdgram_bsd *bsds,
740                                             struct tevent_context *ev,
741                                             void (*handler)(void *private_data),
742                                             void *private_data)
743 {
744         if (ev == NULL) {
745                 if (handler) {
746                         errno = EINVAL;
747                         return -1;
748                 }
749                 if (!bsds->writeable_handler) {
750                         return 0;
751                 }
752                 bsds->writeable_handler = NULL;
753                 bsds->writeable_private = NULL;
754                 TEVENT_FD_NOT_WRITEABLE(bsds->fde);
755
756                 return 0;
757         }
758
759         /* read and write must use the same tevent_context */
760         if (bsds->event_ptr != ev) {
761                 if (bsds->readable_handler || bsds->writeable_handler) {
762                         errno = EINVAL;
763                         return -1;
764                 }
765                 bsds->event_ptr = NULL;
766                 TALLOC_FREE(bsds->fde);
767         }
768
769         if (tevent_fd_get_flags(bsds->fde) == 0) {
770                 TALLOC_FREE(bsds->fde);
771
772                 bsds->fde = tevent_add_fd(ev, bsds,
773                                           bsds->fd, TEVENT_FD_WRITE,
774                                           tdgram_bsd_fde_handler,
775                                           bsds);
776                 if (!bsds->fde) {
777                         errno = ENOMEM;
778                         return -1;
779                 }
780
781                 /* cache the event context we're running on */
782                 bsds->event_ptr = ev;
783         } else if (!bsds->writeable_handler) {
784                 TEVENT_FD_WRITEABLE(bsds->fde);
785         }
786
787         bsds->writeable_handler = handler;
788         bsds->writeable_private = private_data;
789
790         return 0;
791 }
792
793 struct tdgram_bsd_recvfrom_state {
794         struct tdgram_context *dgram;
795         bool first_try;
796         uint8_t *buf;
797         size_t len;
798         struct tsocket_address *src;
799 };
800
801 static int tdgram_bsd_recvfrom_destructor(struct tdgram_bsd_recvfrom_state *state)
802 {
803         struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
804                                   struct tdgram_bsd);
805
806         tdgram_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
807
808         return 0;
809 }
810
811 static void tdgram_bsd_recvfrom_handler(void *private_data);
812
813 static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx,
814                                         struct tevent_context *ev,
815                                         struct tdgram_context *dgram)
816 {
817         struct tevent_req *req;
818         struct tdgram_bsd_recvfrom_state *state;
819         struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
820         int ret;
821
822         req = tevent_req_create(mem_ctx, &state,
823                                 struct tdgram_bsd_recvfrom_state);
824         if (!req) {
825                 return NULL;
826         }
827
828         state->dgram    = dgram;
829         state->first_try= true;
830         state->buf      = NULL;
831         state->len      = 0;
832         state->src      = NULL;
833
834         talloc_set_destructor(state, tdgram_bsd_recvfrom_destructor);
835
836         if (bsds->fd == -1) {
837                 tevent_req_error(req, ENOTCONN);
838                 goto post;
839         }
840
841         /*
842          * this is a fast path, not waiting for the
843          * socket to become explicit readable gains
844          * about 10%-20% performance in benchmark tests.
845          */
846         tdgram_bsd_recvfrom_handler(req);
847         if (!tevent_req_is_in_progress(req)) {
848                 goto post;
849         }
850
851         ret = tdgram_bsd_set_readable_handler(bsds, ev,
852                                               tdgram_bsd_recvfrom_handler,
853                                               req);
854         if (ret == -1) {
855                 tevent_req_error(req, errno);
856                 goto post;
857         }
858
859         return req;
860
861  post:
862         tevent_req_post(req, ev);
863         return req;
864 }
865
866 static void tdgram_bsd_recvfrom_handler(void *private_data)
867 {
868         struct tevent_req *req = talloc_get_type_abort(private_data,
869                                  struct tevent_req);
870         struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
871                                         struct tdgram_bsd_recvfrom_state);
872         struct tdgram_context *dgram = state->dgram;
873         struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
874         struct tsocket_address_bsd *bsda;
875         ssize_t ret;
876         int err;
877         bool retry;
878
879         ret = tsocket_bsd_pending(bsds->fd);
880         if (state->first_try && ret == 0) {
881                 state->first_try = false;
882                 /* retry later */
883                 return;
884         }
885         state->first_try = false;
886
887         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
888         if (retry) {
889                 /* retry later */
890                 return;
891         }
892         if (tevent_req_error(req, err)) {
893                 return;
894         }
895
896         /* note that 'ret' can be 0 here */
897         state->buf = talloc_array(state, uint8_t, ret);
898         if (tevent_req_nomem(state->buf, req)) {
899                 return;
900         }
901         state->len = ret;
902
903         state->src = tsocket_address_create(state,
904                                             &tsocket_address_bsd_ops,
905                                             &bsda,
906                                             struct tsocket_address_bsd,
907                                             __location__ "bsd_recvfrom");
908         if (tevent_req_nomem(state->src, req)) {
909                 return;
910         }
911
912         ZERO_STRUCTP(bsda);
913         bsda->sa_socklen = sizeof(bsda->u.ss);
914 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
915         bsda->u.sa.sa_len = bsda->sa_socklen;
916 #endif
917
918         ret = recvfrom(bsds->fd, state->buf, state->len, 0,
919                        &bsda->u.sa, &bsda->sa_socklen);
920         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
921         if (retry) {
922                 /* retry later */
923                 return;
924         }
925         if (tevent_req_error(req, err)) {
926                 return;
927         }
928
929         /*
930          * Some systems (FreeBSD, see bug #7115) return too much
931          * bytes in tsocket_bsd_pending()/ioctl(fd, FIONREAD, ...),
932          * the return value includes some IP/UDP header bytes,
933          * while recvfrom() just returns the payload.
934          */
935         state->buf = talloc_realloc(state, state->buf, uint8_t, ret);
936         if (tevent_req_nomem(state->buf, req)) {
937                 return;
938         }
939         state->len = ret;
940
941         tevent_req_done(req);
942 }
943
944 static ssize_t tdgram_bsd_recvfrom_recv(struct tevent_req *req,
945                                         int *perrno,
946                                         TALLOC_CTX *mem_ctx,
947                                         uint8_t **buf,
948                                         struct tsocket_address **src)
949 {
950         struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
951                                         struct tdgram_bsd_recvfrom_state);
952         ssize_t ret;
953
954         ret = tsocket_simple_int_recv(req, perrno);
955         if (ret == 0) {
956                 *buf = talloc_move(mem_ctx, &state->buf);
957                 ret = state->len;
958                 if (src) {
959                         *src = talloc_move(mem_ctx, &state->src);
960                 }
961         }
962
963         tevent_req_received(req);
964         return ret;
965 }
966
967 struct tdgram_bsd_sendto_state {
968         struct tdgram_context *dgram;
969
970         const uint8_t *buf;
971         size_t len;
972         const struct tsocket_address *dst;
973
974         ssize_t ret;
975 };
976
977 static int tdgram_bsd_sendto_destructor(struct tdgram_bsd_sendto_state *state)
978 {
979         struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
980                                   struct tdgram_bsd);
981
982         tdgram_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
983
984         return 0;
985 }
986
987 static void tdgram_bsd_sendto_handler(void *private_data);
988
989 static struct tevent_req *tdgram_bsd_sendto_send(TALLOC_CTX *mem_ctx,
990                                                  struct tevent_context *ev,
991                                                  struct tdgram_context *dgram,
992                                                  const uint8_t *buf,
993                                                  size_t len,
994                                                  const struct tsocket_address *dst)
995 {
996         struct tevent_req *req;
997         struct tdgram_bsd_sendto_state *state;
998         struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
999         int ret;
1000
1001         req = tevent_req_create(mem_ctx, &state,
1002                                 struct tdgram_bsd_sendto_state);
1003         if (!req) {
1004                 return NULL;
1005         }
1006
1007         state->dgram    = dgram;
1008         state->buf      = buf;
1009         state->len      = len;
1010         state->dst      = dst;
1011         state->ret      = -1;
1012
1013         talloc_set_destructor(state, tdgram_bsd_sendto_destructor);
1014
1015         if (bsds->fd == -1) {
1016                 tevent_req_error(req, ENOTCONN);
1017                 goto post;
1018         }
1019
1020         /*
1021          * this is a fast path, not waiting for the
1022          * socket to become explicit writeable gains
1023          * about 10%-20% performance in benchmark tests.
1024          */
1025         tdgram_bsd_sendto_handler(req);
1026         if (!tevent_req_is_in_progress(req)) {
1027                 goto post;
1028         }
1029
1030         ret = tdgram_bsd_set_writeable_handler(bsds, ev,
1031                                                tdgram_bsd_sendto_handler,
1032                                                req);
1033         if (ret == -1) {
1034                 tevent_req_error(req, errno);
1035                 goto post;
1036         }
1037
1038         return req;
1039
1040  post:
1041         tevent_req_post(req, ev);
1042         return req;
1043 }
1044
1045 static void tdgram_bsd_sendto_handler(void *private_data)
1046 {
1047         struct tevent_req *req = talloc_get_type_abort(private_data,
1048                                  struct tevent_req);
1049         struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
1050                                         struct tdgram_bsd_sendto_state);
1051         struct tdgram_context *dgram = state->dgram;
1052         struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
1053         struct sockaddr *sa = NULL;
1054         socklen_t sa_socklen = 0;
1055         ssize_t ret;
1056         int err;
1057         bool retry;
1058
1059         if (state->dst) {
1060                 struct tsocket_address_bsd *bsda =
1061                         talloc_get_type(state->dst->private_data,
1062                         struct tsocket_address_bsd);
1063
1064                 sa = &bsda->u.sa;
1065                 sa_socklen = bsda->sa_socklen;
1066         }
1067
1068         ret = sendto(bsds->fd, state->buf, state->len, 0, sa, sa_socklen);
1069         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
1070         if (retry) {
1071                 /* retry later */
1072                 return;
1073         }
1074         if (tevent_req_error(req, err)) {
1075                 return;
1076         }
1077
1078         state->ret = ret;
1079
1080         tevent_req_done(req);
1081 }
1082
1083 static ssize_t tdgram_bsd_sendto_recv(struct tevent_req *req, int *perrno)
1084 {
1085         struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
1086                                         struct tdgram_bsd_sendto_state);
1087         ssize_t ret;
1088
1089         ret = tsocket_simple_int_recv(req, perrno);
1090         if (ret == 0) {
1091                 ret = state->ret;
1092         }
1093
1094         tevent_req_received(req);
1095         return ret;
1096 }
1097
1098 struct tdgram_bsd_disconnect_state {
1099         uint8_t __dummy;
1100 };
1101
1102 static struct tevent_req *tdgram_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
1103                                                      struct tevent_context *ev,
1104                                                      struct tdgram_context *dgram)
1105 {
1106         struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
1107         struct tevent_req *req;
1108         struct tdgram_bsd_disconnect_state *state;
1109         int ret;
1110         int err;
1111         bool dummy;
1112
1113         req = tevent_req_create(mem_ctx, &state,
1114                                 struct tdgram_bsd_disconnect_state);
1115         if (req == NULL) {
1116                 return NULL;
1117         }
1118
1119         if (bsds->fd == -1) {
1120                 tevent_req_error(req, ENOTCONN);
1121                 goto post;
1122         }
1123
1124         TALLOC_FREE(bsds->fde);
1125         ret = close(bsds->fd);
1126         bsds->fd = -1;
1127         err = tsocket_bsd_error_from_errno(ret, errno, &dummy);
1128         if (tevent_req_error(req, err)) {
1129                 goto post;
1130         }
1131
1132         tevent_req_done(req);
1133 post:
1134         tevent_req_post(req, ev);
1135         return req;
1136 }
1137
1138 static int tdgram_bsd_disconnect_recv(struct tevent_req *req,
1139                                       int *perrno)
1140 {
1141         int ret;
1142
1143         ret = tsocket_simple_int_recv(req, perrno);
1144
1145         tevent_req_received(req);
1146         return ret;
1147 }
1148
1149 static const struct tdgram_context_ops tdgram_bsd_ops = {
1150         .name                   = "bsd",
1151
1152         .recvfrom_send          = tdgram_bsd_recvfrom_send,
1153         .recvfrom_recv          = tdgram_bsd_recvfrom_recv,
1154
1155         .sendto_send            = tdgram_bsd_sendto_send,
1156         .sendto_recv            = tdgram_bsd_sendto_recv,
1157
1158         .disconnect_send        = tdgram_bsd_disconnect_send,
1159         .disconnect_recv        = tdgram_bsd_disconnect_recv,
1160 };
1161
1162 static int tdgram_bsd_destructor(struct tdgram_bsd *bsds)
1163 {
1164         TALLOC_FREE(bsds->fde);
1165         if (bsds->fd != -1) {
1166                 close(bsds->fd);
1167                 bsds->fd = -1;
1168         }
1169         return 0;
1170 }
1171
1172 static int tdgram_bsd_dgram_socket(const struct tsocket_address *local,
1173                                    const struct tsocket_address *remote,
1174                                    bool broadcast,
1175                                    TALLOC_CTX *mem_ctx,
1176                                    struct tdgram_context **_dgram,
1177                                    const char *location)
1178 {
1179         struct tsocket_address_bsd *lbsda =
1180                 talloc_get_type_abort(local->private_data,
1181                 struct tsocket_address_bsd);
1182         struct tsocket_address_bsd *rbsda = NULL;
1183         struct tdgram_context *dgram;
1184         struct tdgram_bsd *bsds;
1185         int fd;
1186         int ret;
1187         bool do_bind = false;
1188         bool do_reuseaddr = false;
1189         bool do_ipv6only = false;
1190         bool is_inet = false;
1191         int sa_fam = lbsda->u.sa.sa_family;
1192
1193         if (remote) {
1194                 rbsda = talloc_get_type_abort(remote->private_data,
1195                         struct tsocket_address_bsd);
1196         }
1197
1198         switch (lbsda->u.sa.sa_family) {
1199         case AF_UNIX:
1200                 if (broadcast) {
1201                         errno = EINVAL;
1202                         return -1;
1203                 }
1204                 if (lbsda->u.un.sun_path[0] != 0) {
1205                         do_reuseaddr = true;
1206                         do_bind = true;
1207                 }
1208                 break;
1209         case AF_INET:
1210                 if (lbsda->u.in.sin_port != 0) {
1211                         do_reuseaddr = true;
1212                         do_bind = true;
1213                 }
1214                 if (lbsda->u.in.sin_addr.s_addr != INADDR_ANY) {
1215                         do_bind = true;
1216                 }
1217                 is_inet = true;
1218                 break;
1219 #ifdef HAVE_IPV6
1220         case AF_INET6:
1221                 if (lbsda->u.in6.sin6_port != 0) {
1222                         do_reuseaddr = true;
1223                         do_bind = true;
1224                 }
1225                 if (memcmp(&in6addr_any,
1226                            &lbsda->u.in6.sin6_addr,
1227                            sizeof(in6addr_any)) != 0) {
1228                         do_bind = true;
1229                 }
1230                 is_inet = true;
1231                 do_ipv6only = true;
1232                 break;
1233 #endif
1234         default:
1235                 errno = EINVAL;
1236                 return -1;
1237         }
1238
1239         if (!do_bind && is_inet && rbsda) {
1240                 sa_fam = rbsda->u.sa.sa_family;
1241                 switch (sa_fam) {
1242                 case AF_INET:
1243                         do_ipv6only = false;
1244                         break;
1245 #ifdef HAVE_IPV6
1246                 case AF_INET6:
1247                         do_ipv6only = true;
1248                         break;
1249 #endif
1250                 }
1251         }
1252
1253         fd = socket(sa_fam, SOCK_DGRAM, 0);
1254         if (fd < 0) {
1255                 return -1;
1256         }
1257
1258         fd = tsocket_bsd_common_prepare_fd(fd, true);
1259         if (fd < 0) {
1260                 return -1;
1261         }
1262
1263         dgram = tdgram_context_create(mem_ctx,
1264                                       &tdgram_bsd_ops,
1265                                       &bsds,
1266                                       struct tdgram_bsd,
1267                                       location);
1268         if (!dgram) {
1269                 int saved_errno = errno;
1270                 close(fd);
1271                 errno = saved_errno;
1272                 return -1;
1273         }
1274         ZERO_STRUCTP(bsds);
1275         bsds->fd = fd;
1276         talloc_set_destructor(bsds, tdgram_bsd_destructor);
1277
1278 #ifdef HAVE_IPV6
1279         if (do_ipv6only) {
1280                 int val = 1;
1281
1282                 ret = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
1283                                  (const void *)&val, sizeof(val));
1284                 if (ret == -1) {
1285                         int saved_errno = errno;
1286                         talloc_free(dgram);
1287                         errno = saved_errno;
1288                         return -1;
1289                 }
1290         }
1291 #endif
1292
1293         if (broadcast) {
1294                 int val = 1;
1295
1296                 ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
1297                                  (const void *)&val, sizeof(val));
1298                 if (ret == -1) {
1299                         int saved_errno = errno;
1300                         talloc_free(dgram);
1301                         errno = saved_errno;
1302                         return -1;
1303                 }
1304         }
1305
1306         if (do_reuseaddr) {
1307                 int val = 1;
1308
1309                 ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
1310                                  (const void *)&val, sizeof(val));
1311                 if (ret == -1) {
1312                         int saved_errno = errno;
1313                         talloc_free(dgram);
1314                         errno = saved_errno;
1315                         return -1;
1316                 }
1317         }
1318
1319         if (do_bind) {
1320                 ret = bind(fd, &lbsda->u.sa, lbsda->sa_socklen);
1321                 if (ret == -1) {
1322                         int saved_errno = errno;
1323                         talloc_free(dgram);
1324                         errno = saved_errno;
1325                         return -1;
1326                 }
1327         }
1328
1329         if (rbsda) {
1330                 if (rbsda->u.sa.sa_family != sa_fam) {
1331                         talloc_free(dgram);
1332                         errno = EINVAL;
1333                         return -1;
1334                 }
1335
1336                 ret = connect(fd, &rbsda->u.sa, rbsda->sa_socklen);
1337                 if (ret == -1) {
1338                         int saved_errno = errno;
1339                         talloc_free(dgram);
1340                         errno = saved_errno;
1341                         return -1;
1342                 }
1343         }
1344
1345         *_dgram = dgram;
1346         return 0;
1347 }
1348
1349 int _tdgram_inet_udp_socket(const struct tsocket_address *local,
1350                             const struct tsocket_address *remote,
1351                             TALLOC_CTX *mem_ctx,
1352                             struct tdgram_context **dgram,
1353                             const char *location)
1354 {
1355         struct tsocket_address_bsd *lbsda =
1356                 talloc_get_type_abort(local->private_data,
1357                 struct tsocket_address_bsd);
1358         int ret;
1359
1360         switch (lbsda->u.sa.sa_family) {
1361         case AF_INET:
1362                 break;
1363 #ifdef HAVE_IPV6
1364         case AF_INET6:
1365                 break;
1366 #endif
1367         default:
1368                 errno = EINVAL;
1369                 return -1;
1370         }
1371
1372         ret = tdgram_bsd_dgram_socket(local, remote, false,
1373                                       mem_ctx, dgram, location);
1374
1375         return ret;
1376 }
1377
1378 int _tdgram_unix_socket(const struct tsocket_address *local,
1379                         const struct tsocket_address *remote,
1380                         TALLOC_CTX *mem_ctx,
1381                         struct tdgram_context **dgram,
1382                         const char *location)
1383 {
1384         struct tsocket_address_bsd *lbsda =
1385                 talloc_get_type_abort(local->private_data,
1386                 struct tsocket_address_bsd);
1387         int ret;
1388
1389         switch (lbsda->u.sa.sa_family) {
1390         case AF_UNIX:
1391                 break;
1392         default:
1393                 errno = EINVAL;
1394                 return -1;
1395         }
1396
1397         ret = tdgram_bsd_dgram_socket(local, remote, false,
1398                                       mem_ctx, dgram, location);
1399
1400         return ret;
1401 }
1402
1403 struct tstream_bsd {
1404         int fd;
1405
1406         void *event_ptr;
1407         struct tevent_fd *fde;
1408
1409         void *readable_private;
1410         void (*readable_handler)(void *private_data);
1411         void *writeable_private;
1412         void (*writeable_handler)(void *private_data);
1413 };
1414
1415 static void tstream_bsd_fde_handler(struct tevent_context *ev,
1416                                     struct tevent_fd *fde,
1417                                     uint16_t flags,
1418                                     void *private_data)
1419 {
1420         struct tstream_bsd *bsds = talloc_get_type_abort(private_data,
1421                                    struct tstream_bsd);
1422
1423         if (flags & TEVENT_FD_WRITE) {
1424                 bsds->writeable_handler(bsds->writeable_private);
1425                 return;
1426         }
1427         if (flags & TEVENT_FD_READ) {
1428                 if (!bsds->readable_handler) {
1429                         if (bsds->writeable_handler) {
1430                                 bsds->writeable_handler(bsds->writeable_private);
1431                                 return;
1432                         }
1433                         TEVENT_FD_NOT_READABLE(bsds->fde);
1434                         return;
1435                 }
1436                 bsds->readable_handler(bsds->readable_private);
1437                 return;
1438         }
1439 }
1440
1441 static int tstream_bsd_set_readable_handler(struct tstream_bsd *bsds,
1442                                             struct tevent_context *ev,
1443                                             void (*handler)(void *private_data),
1444                                             void *private_data)
1445 {
1446         if (ev == NULL) {
1447                 if (handler) {
1448                         errno = EINVAL;
1449                         return -1;
1450                 }
1451                 if (!bsds->readable_handler) {
1452                         return 0;
1453                 }
1454                 bsds->readable_handler = NULL;
1455                 bsds->readable_private = NULL;
1456
1457                 return 0;
1458         }
1459
1460         /* read and write must use the same tevent_context */
1461         if (bsds->event_ptr != ev) {
1462                 if (bsds->readable_handler || bsds->writeable_handler) {
1463                         errno = EINVAL;
1464                         return -1;
1465                 }
1466                 bsds->event_ptr = NULL;
1467                 TALLOC_FREE(bsds->fde);
1468         }
1469
1470         if (tevent_fd_get_flags(bsds->fde) == 0) {
1471                 TALLOC_FREE(bsds->fde);
1472
1473                 bsds->fde = tevent_add_fd(ev, bsds,
1474                                           bsds->fd, TEVENT_FD_READ,
1475                                           tstream_bsd_fde_handler,
1476                                           bsds);
1477                 if (!bsds->fde) {
1478                         errno = ENOMEM;
1479                         return -1;
1480                 }
1481
1482                 /* cache the event context we're running on */
1483                 bsds->event_ptr = ev;
1484         } else if (!bsds->readable_handler) {
1485                 TEVENT_FD_READABLE(bsds->fde);
1486         }
1487
1488         bsds->readable_handler = handler;
1489         bsds->readable_private = private_data;
1490
1491         return 0;
1492 }
1493
1494 static int tstream_bsd_set_writeable_handler(struct tstream_bsd *bsds,
1495                                              struct tevent_context *ev,
1496                                              void (*handler)(void *private_data),
1497                                              void *private_data)
1498 {
1499         if (ev == NULL) {
1500                 if (handler) {
1501                         errno = EINVAL;
1502                         return -1;
1503                 }
1504                 if (!bsds->writeable_handler) {
1505                         return 0;
1506                 }
1507                 bsds->writeable_handler = NULL;
1508                 bsds->writeable_private = NULL;
1509                 TEVENT_FD_NOT_WRITEABLE(bsds->fde);
1510
1511                 return 0;
1512         }
1513
1514         /* read and write must use the same tevent_context */
1515         if (bsds->event_ptr != ev) {
1516                 if (bsds->readable_handler || bsds->writeable_handler) {
1517                         errno = EINVAL;
1518                         return -1;
1519                 }
1520                 bsds->event_ptr = NULL;
1521                 TALLOC_FREE(bsds->fde);
1522         }
1523
1524         if (tevent_fd_get_flags(bsds->fde) == 0) {
1525                 TALLOC_FREE(bsds->fde);
1526
1527                 bsds->fde = tevent_add_fd(ev, bsds,
1528                                           bsds->fd,
1529                                           TEVENT_FD_READ | TEVENT_FD_WRITE,
1530                                           tstream_bsd_fde_handler,
1531                                           bsds);
1532                 if (!bsds->fde) {
1533                         errno = ENOMEM;
1534                         return -1;
1535                 }
1536
1537                 /* cache the event context we're running on */
1538                 bsds->event_ptr = ev;
1539         } else if (!bsds->writeable_handler) {
1540                 uint16_t flags = tevent_fd_get_flags(bsds->fde);
1541                 flags |= TEVENT_FD_READ | TEVENT_FD_WRITE;
1542                 tevent_fd_set_flags(bsds->fde, flags);
1543         }
1544
1545         bsds->writeable_handler = handler;
1546         bsds->writeable_private = private_data;
1547
1548         return 0;
1549 }
1550
1551 static ssize_t tstream_bsd_pending_bytes(struct tstream_context *stream)
1552 {
1553         struct tstream_bsd *bsds = tstream_context_data(stream,
1554                                    struct tstream_bsd);
1555         ssize_t ret;
1556
1557         if (bsds->fd == -1) {
1558                 errno = ENOTCONN;
1559                 return -1;
1560         }
1561
1562         ret = tsocket_bsd_pending(bsds->fd);
1563
1564         return ret;
1565 }
1566
1567 struct tstream_bsd_readv_state {
1568         struct tstream_context *stream;
1569
1570         struct iovec *vector;
1571         size_t count;
1572
1573         int ret;
1574 };
1575
1576 static int tstream_bsd_readv_destructor(struct tstream_bsd_readv_state *state)
1577 {
1578         struct tstream_bsd *bsds = tstream_context_data(state->stream,
1579                                    struct tstream_bsd);
1580
1581         tstream_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
1582
1583         return 0;
1584 }
1585
1586 static void tstream_bsd_readv_handler(void *private_data);
1587
1588 static struct tevent_req *tstream_bsd_readv_send(TALLOC_CTX *mem_ctx,
1589                                         struct tevent_context *ev,
1590                                         struct tstream_context *stream,
1591                                         struct iovec *vector,
1592                                         size_t count)
1593 {
1594         struct tevent_req *req;
1595         struct tstream_bsd_readv_state *state;
1596         struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
1597         int ret;
1598
1599         req = tevent_req_create(mem_ctx, &state,
1600                                 struct tstream_bsd_readv_state);
1601         if (!req) {
1602                 return NULL;
1603         }
1604
1605         state->stream   = stream;
1606         /* we make a copy of the vector so that we can modify it */
1607         state->vector   = talloc_array(state, struct iovec, count);
1608         if (tevent_req_nomem(state->vector, req)) {
1609                 goto post;
1610         }
1611         memcpy(state->vector, vector, sizeof(struct iovec)*count);
1612         state->count    = count;
1613         state->ret      = 0;
1614
1615         talloc_set_destructor(state, tstream_bsd_readv_destructor);
1616
1617         if (bsds->fd == -1) {
1618                 tevent_req_error(req, ENOTCONN);
1619                 goto post;
1620         }
1621
1622         /*
1623          * this is a fast path, not waiting for the
1624          * socket to become explicit readable gains
1625          * about 10%-20% performance in benchmark tests.
1626          */
1627         tstream_bsd_readv_handler(req);
1628         if (!tevent_req_is_in_progress(req)) {
1629                 goto post;
1630         }
1631
1632         ret = tstream_bsd_set_readable_handler(bsds, ev,
1633                                               tstream_bsd_readv_handler,
1634                                               req);
1635         if (ret == -1) {
1636                 tevent_req_error(req, errno);
1637                 goto post;
1638         }
1639
1640         return req;
1641
1642  post:
1643         tevent_req_post(req, ev);
1644         return req;
1645 }
1646
1647 static void tstream_bsd_readv_handler(void *private_data)
1648 {
1649         struct tevent_req *req = talloc_get_type_abort(private_data,
1650                                  struct tevent_req);
1651         struct tstream_bsd_readv_state *state = tevent_req_data(req,
1652                                         struct tstream_bsd_readv_state);
1653         struct tstream_context *stream = state->stream;
1654         struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
1655         int ret;
1656         int err;
1657         bool retry;
1658
1659         ret = readv(bsds->fd, state->vector, state->count);
1660         if (ret == 0) {
1661                 /* propagate end of file */
1662                 tevent_req_error(req, EPIPE);
1663                 return;
1664         }
1665         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
1666         if (retry) {
1667                 /* retry later */
1668                 return;
1669         }
1670         if (tevent_req_error(req, err)) {
1671                 return;
1672         }
1673
1674         state->ret += ret;
1675
1676         while (ret > 0) {
1677                 if (ret < state->vector[0].iov_len) {
1678                         uint8_t *base;
1679                         base = (uint8_t *)state->vector[0].iov_base;
1680                         base += ret;
1681                         state->vector[0].iov_base = (void *)base;
1682                         state->vector[0].iov_len -= ret;
1683                         break;
1684                 }
1685                 ret -= state->vector[0].iov_len;
1686                 state->vector += 1;
1687                 state->count -= 1;
1688         }
1689
1690         /*
1691          * there're maybe some empty vectors at the end
1692          * which we need to skip, otherwise we would get
1693          * ret == 0 from the readv() call and return EPIPE
1694          */
1695         while (state->count > 0) {
1696                 if (state->vector[0].iov_len > 0) {
1697                         break;
1698                 }
1699                 state->vector += 1;
1700                 state->count -= 1;
1701         }
1702
1703         if (state->count > 0) {
1704                 /* we have more to read */
1705                 return;
1706         }
1707
1708         tevent_req_done(req);
1709 }
1710
1711 static int tstream_bsd_readv_recv(struct tevent_req *req,
1712                                   int *perrno)
1713 {
1714         struct tstream_bsd_readv_state *state = tevent_req_data(req,
1715                                         struct tstream_bsd_readv_state);
1716         int ret;
1717
1718         ret = tsocket_simple_int_recv(req, perrno);
1719         if (ret == 0) {
1720                 ret = state->ret;
1721         }
1722
1723         tevent_req_received(req);
1724         return ret;
1725 }
1726
1727 struct tstream_bsd_writev_state {
1728         struct tstream_context *stream;
1729
1730         struct iovec *vector;
1731         size_t count;
1732
1733         int ret;
1734 };
1735
1736 static int tstream_bsd_writev_destructor(struct tstream_bsd_writev_state *state)
1737 {
1738         struct tstream_bsd *bsds = tstream_context_data(state->stream,
1739                                   struct tstream_bsd);
1740
1741         tstream_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
1742
1743         return 0;
1744 }
1745
1746 static void tstream_bsd_writev_handler(void *private_data);
1747
1748 static struct tevent_req *tstream_bsd_writev_send(TALLOC_CTX *mem_ctx,
1749                                                  struct tevent_context *ev,
1750                                                  struct tstream_context *stream,
1751                                                  const struct iovec *vector,
1752                                                  size_t count)
1753 {
1754         struct tevent_req *req;
1755         struct tstream_bsd_writev_state *state;
1756         struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
1757         int ret;
1758
1759         req = tevent_req_create(mem_ctx, &state,
1760                                 struct tstream_bsd_writev_state);
1761         if (!req) {
1762                 return NULL;
1763         }
1764
1765         state->stream   = stream;
1766         /* we make a copy of the vector so that we can modify it */
1767         state->vector   = talloc_array(state, struct iovec, count);
1768         if (tevent_req_nomem(state->vector, req)) {
1769                 goto post;
1770         }
1771         memcpy(state->vector, vector, sizeof(struct iovec)*count);
1772         state->count    = count;
1773         state->ret      = 0;
1774
1775         talloc_set_destructor(state, tstream_bsd_writev_destructor);
1776
1777         if (bsds->fd == -1) {
1778                 tevent_req_error(req, ENOTCONN);
1779                 goto post;
1780         }
1781
1782         /*
1783          * this is a fast path, not waiting for the
1784          * socket to become explicit writeable gains
1785          * about 10%-20% performance in benchmark tests.
1786          */
1787         tstream_bsd_writev_handler(req);
1788         if (!tevent_req_is_in_progress(req)) {
1789                 goto post;
1790         }
1791
1792         ret = tstream_bsd_set_writeable_handler(bsds, ev,
1793                                                tstream_bsd_writev_handler,
1794                                                req);
1795         if (ret == -1) {
1796                 tevent_req_error(req, errno);
1797                 goto post;
1798         }
1799
1800         return req;
1801
1802  post:
1803         tevent_req_post(req, ev);
1804         return req;
1805 }
1806
1807 static void tstream_bsd_writev_handler(void *private_data)
1808 {
1809         struct tevent_req *req = talloc_get_type_abort(private_data,
1810                                  struct tevent_req);
1811         struct tstream_bsd_writev_state *state = tevent_req_data(req,
1812                                         struct tstream_bsd_writev_state);
1813         struct tstream_context *stream = state->stream;
1814         struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
1815         ssize_t ret;
1816         int err;
1817         bool retry;
1818
1819         ret = writev(bsds->fd, state->vector, state->count);
1820         if (ret == 0) {
1821                 /* propagate end of file */
1822                 tevent_req_error(req, EPIPE);
1823                 return;
1824         }
1825         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
1826         if (retry) {
1827                 /* retry later */
1828                 return;
1829         }
1830         if (tevent_req_error(req, err)) {
1831                 return;
1832         }
1833
1834         state->ret += ret;
1835
1836         while (ret > 0) {
1837                 if (ret < state->vector[0].iov_len) {
1838                         uint8_t *base;
1839                         base = (uint8_t *)state->vector[0].iov_base;
1840                         base += ret;
1841                         state->vector[0].iov_base = (void *)base;
1842                         state->vector[0].iov_len -= ret;
1843                         break;
1844                 }
1845                 ret -= state->vector[0].iov_len;
1846                 state->vector += 1;
1847                 state->count -= 1;
1848         }
1849
1850         /*
1851          * there're maybe some empty vectors at the end
1852          * which we need to skip, otherwise we would get
1853          * ret == 0 from the writev() call and return EPIPE
1854          */
1855         while (state->count > 0) {
1856                 if (state->vector[0].iov_len > 0) {
1857                         break;
1858                 }
1859                 state->vector += 1;
1860                 state->count -= 1;
1861         }
1862
1863         if (state->count > 0) {
1864                 /* we have more to read */
1865                 return;
1866         }
1867
1868         tevent_req_done(req);
1869 }
1870
1871 static int tstream_bsd_writev_recv(struct tevent_req *req, int *perrno)
1872 {
1873         struct tstream_bsd_writev_state *state = tevent_req_data(req,
1874                                         struct tstream_bsd_writev_state);
1875         int ret;
1876
1877         ret = tsocket_simple_int_recv(req, perrno);
1878         if (ret == 0) {
1879                 ret = state->ret;
1880         }
1881
1882         tevent_req_received(req);
1883         return ret;
1884 }
1885
1886 struct tstream_bsd_disconnect_state {
1887         void *__dummy;
1888 };
1889
1890 static struct tevent_req *tstream_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
1891                                                      struct tevent_context *ev,
1892                                                      struct tstream_context *stream)
1893 {
1894         struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
1895         struct tevent_req *req;
1896         struct tstream_bsd_disconnect_state *state;
1897         int ret;
1898         int err;
1899         bool dummy;
1900
1901         req = tevent_req_create(mem_ctx, &state,
1902                                 struct tstream_bsd_disconnect_state);
1903         if (req == NULL) {
1904                 return NULL;
1905         }
1906
1907         if (bsds->fd == -1) {
1908                 tevent_req_error(req, ENOTCONN);
1909                 goto post;
1910         }
1911
1912         TALLOC_FREE(bsds->fde);
1913         ret = close(bsds->fd);
1914         bsds->fd = -1;
1915         err = tsocket_bsd_error_from_errno(ret, errno, &dummy);
1916         if (tevent_req_error(req, err)) {
1917                 goto post;
1918         }
1919
1920         tevent_req_done(req);
1921 post:
1922         tevent_req_post(req, ev);
1923         return req;
1924 }
1925
1926 static int tstream_bsd_disconnect_recv(struct tevent_req *req,
1927                                       int *perrno)
1928 {
1929         int ret;
1930
1931         ret = tsocket_simple_int_recv(req, perrno);
1932
1933         tevent_req_received(req);
1934         return ret;
1935 }
1936
1937 static const struct tstream_context_ops tstream_bsd_ops = {
1938         .name                   = "bsd",
1939
1940         .pending_bytes          = tstream_bsd_pending_bytes,
1941
1942         .readv_send             = tstream_bsd_readv_send,
1943         .readv_recv             = tstream_bsd_readv_recv,
1944
1945         .writev_send            = tstream_bsd_writev_send,
1946         .writev_recv            = tstream_bsd_writev_recv,
1947
1948         .disconnect_send        = tstream_bsd_disconnect_send,
1949         .disconnect_recv        = tstream_bsd_disconnect_recv,
1950 };
1951
1952 static int tstream_bsd_destructor(struct tstream_bsd *bsds)
1953 {
1954         TALLOC_FREE(bsds->fde);
1955         if (bsds->fd != -1) {
1956                 close(bsds->fd);
1957                 bsds->fd = -1;
1958         }
1959         return 0;
1960 }
1961
1962 int _tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
1963                                  int fd,
1964                                  struct tstream_context **_stream,
1965                                  const char *location)
1966 {
1967         struct tstream_context *stream;
1968         struct tstream_bsd *bsds;
1969
1970         stream = tstream_context_create(mem_ctx,
1971                                         &tstream_bsd_ops,
1972                                         &bsds,
1973                                         struct tstream_bsd,
1974                                         location);
1975         if (!stream) {
1976                 return -1;
1977         }
1978         ZERO_STRUCTP(bsds);
1979         bsds->fd = fd;
1980         talloc_set_destructor(bsds, tstream_bsd_destructor);
1981
1982         *_stream = stream;
1983         return 0;
1984 }
1985
1986 struct tstream_bsd_connect_state {
1987         int fd;
1988         struct tevent_fd *fde;
1989         struct tstream_conext *stream;
1990         struct tsocket_address *local;
1991 };
1992
1993 static int tstream_bsd_connect_destructor(struct tstream_bsd_connect_state *state)
1994 {
1995         TALLOC_FREE(state->fde);
1996         if (state->fd != -1) {
1997                 close(state->fd);
1998                 state->fd = -1;
1999         }
2000
2001         return 0;
2002 }
2003
2004 static void tstream_bsd_connect_fde_handler(struct tevent_context *ev,
2005                                             struct tevent_fd *fde,
2006                                             uint16_t flags,
2007                                             void *private_data);
2008
2009 static struct tevent_req *tstream_bsd_connect_send(TALLOC_CTX *mem_ctx,
2010                                         struct tevent_context *ev,
2011                                         int sys_errno,
2012                                         const struct tsocket_address *local,
2013                                         const struct tsocket_address *remote)
2014 {
2015         struct tevent_req *req;
2016         struct tstream_bsd_connect_state *state;
2017         struct tsocket_address_bsd *lbsda =
2018                 talloc_get_type_abort(local->private_data,
2019                 struct tsocket_address_bsd);
2020         struct tsocket_address_bsd *lrbsda = NULL;
2021         struct tsocket_address_bsd *rbsda =
2022                 talloc_get_type_abort(remote->private_data,
2023                 struct tsocket_address_bsd);
2024         int ret;
2025         int err;
2026         bool retry;
2027         bool do_bind = false;
2028         bool do_reuseaddr = false;
2029         bool do_ipv6only = false;
2030         bool is_inet = false;
2031         int sa_fam = lbsda->u.sa.sa_family;
2032
2033         req = tevent_req_create(mem_ctx, &state,
2034                                 struct tstream_bsd_connect_state);
2035         if (!req) {
2036                 return NULL;
2037         }
2038         state->fd = -1;
2039         state->fde = NULL;
2040
2041         talloc_set_destructor(state, tstream_bsd_connect_destructor);
2042
2043         /* give the wrappers a chance to report an error */
2044         if (sys_errno != 0) {
2045                 tevent_req_error(req, sys_errno);
2046                 goto post;
2047         }
2048
2049         switch (lbsda->u.sa.sa_family) {
2050         case AF_UNIX:
2051                 if (lbsda->u.un.sun_path[0] != 0) {
2052                         do_reuseaddr = true;
2053                         do_bind = true;
2054                 }
2055                 break;
2056         case AF_INET:
2057                 if (lbsda->u.in.sin_port != 0) {
2058                         do_reuseaddr = true;
2059                         do_bind = true;
2060                 }
2061                 if (lbsda->u.in.sin_addr.s_addr != INADDR_ANY) {
2062                         do_bind = true;
2063                 }
2064                 is_inet = true;
2065                 break;
2066 #ifdef HAVE_IPV6
2067         case AF_INET6:
2068                 if (lbsda->u.in6.sin6_port != 0) {
2069                         do_reuseaddr = true;
2070                         do_bind = true;
2071                 }
2072                 if (memcmp(&in6addr_any,
2073                            &lbsda->u.in6.sin6_addr,
2074                            sizeof(in6addr_any)) != 0) {
2075                         do_bind = true;
2076                 }
2077                 is_inet = true;
2078                 do_ipv6only = true;
2079                 break;
2080 #endif
2081         default:
2082                 tevent_req_error(req, EINVAL);
2083                 goto post;
2084         }
2085
2086         if (!do_bind && is_inet) {
2087                 sa_fam = rbsda->u.sa.sa_family;
2088                 switch (sa_fam) {
2089                 case AF_INET:
2090                         do_ipv6only = false;
2091                         break;
2092 #ifdef HAVE_IPV6
2093                 case AF_INET6:
2094                         do_ipv6only = true;
2095                         break;
2096 #endif
2097                 }
2098         }
2099
2100         if (is_inet) {
2101                 state->local = tsocket_address_create(state,
2102                                                       &tsocket_address_bsd_ops,
2103                                                       &lrbsda,
2104                                                       struct tsocket_address_bsd,
2105                                                       __location__ "bsd_connect");
2106                 if (tevent_req_nomem(state->local, req)) {
2107                         goto post;
2108                 }
2109
2110                 ZERO_STRUCTP(lrbsda);
2111                 lrbsda->sa_socklen = sizeof(lrbsda->u.ss);
2112 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
2113                 lrbsda->u.sa.sa_len = lrbsda->sa_socklen;
2114 #endif
2115         }
2116
2117         state->fd = socket(sa_fam, SOCK_STREAM, 0);
2118         if (state->fd == -1) {
2119                 tevent_req_error(req, errno);
2120                 goto post;
2121         }
2122
2123         state->fd = tsocket_bsd_common_prepare_fd(state->fd, true);
2124         if (state->fd == -1) {
2125                 tevent_req_error(req, errno);
2126                 goto post;
2127         }
2128
2129 #ifdef HAVE_IPV6
2130         if (do_ipv6only) {
2131                 int val = 1;
2132
2133                 ret = setsockopt(state->fd, IPPROTO_IPV6, IPV6_V6ONLY,
2134                                  (const void *)&val, sizeof(val));
2135                 if (ret == -1) {
2136                         tevent_req_error(req, errno);
2137                         goto post;
2138                 }
2139         }
2140 #endif
2141
2142         if (do_reuseaddr) {
2143                 int val = 1;
2144
2145                 ret = setsockopt(state->fd, SOL_SOCKET, SO_REUSEADDR,
2146                                  (const void *)&val, sizeof(val));
2147                 if (ret == -1) {
2148                         tevent_req_error(req, errno);
2149                         goto post;
2150                 }
2151         }
2152
2153         if (do_bind) {
2154                 ret = bind(state->fd, &lbsda->u.sa, lbsda->sa_socklen);
2155                 if (ret == -1) {
2156                         tevent_req_error(req, errno);
2157                         goto post;
2158                 }
2159         }
2160
2161         if (rbsda->u.sa.sa_family != sa_fam) {
2162                 tevent_req_error(req, EINVAL);
2163                 goto post;
2164         }
2165
2166         ret = connect(state->fd, &rbsda->u.sa, rbsda->sa_socklen);
2167         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
2168         if (retry) {
2169                 /* retry later */
2170                 goto async;
2171         }
2172         if (tevent_req_error(req, err)) {
2173                 goto post;
2174         }
2175
2176         if (!state->local) {
2177                 tevent_req_done(req);
2178                 goto post;
2179         }
2180
2181         ret = getsockname(state->fd, &lrbsda->u.sa, &lrbsda->sa_socklen);
2182         if (ret == -1) {
2183                 tevent_req_error(req, errno);
2184                 goto post;
2185         }
2186
2187         tevent_req_done(req);
2188         goto post;
2189
2190  async:
2191         state->fde = tevent_add_fd(ev, state,
2192                                    state->fd,
2193                                    TEVENT_FD_READ | TEVENT_FD_WRITE,
2194                                    tstream_bsd_connect_fde_handler,
2195                                    req);
2196         if (tevent_req_nomem(state->fde, req)) {
2197                 goto post;
2198         }
2199
2200         return req;
2201
2202  post:
2203         tevent_req_post(req, ev);
2204         return req;
2205 }
2206
2207 static void tstream_bsd_connect_fde_handler(struct tevent_context *ev,
2208                                             struct tevent_fd *fde,
2209                                             uint16_t flags,
2210                                             void *private_data)
2211 {
2212         struct tevent_req *req = talloc_get_type_abort(private_data,
2213                                  struct tevent_req);
2214         struct tstream_bsd_connect_state *state = tevent_req_data(req,
2215                                         struct tstream_bsd_connect_state);
2216         struct tsocket_address_bsd *lrbsda = NULL;
2217         int ret;
2218         int error=0;
2219         socklen_t len = sizeof(error);
2220         int err;
2221         bool retry;
2222
2223         ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR, &error, &len);
2224         if (ret == 0) {
2225                 if (error != 0) {
2226                         errno = error;
2227                         ret = -1;
2228                 }
2229         }
2230         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
2231         if (retry) {
2232                 /* retry later */
2233                 return;
2234         }
2235         if (tevent_req_error(req, err)) {
2236                 return;
2237         }
2238
2239         if (!state->local) {
2240                 tevent_req_done(req);
2241                 return;
2242         }
2243
2244         lrbsda = talloc_get_type_abort(state->local->private_data,
2245                                        struct tsocket_address_bsd);
2246
2247         ret = getsockname(state->fd, &lrbsda->u.sa, &lrbsda->sa_socklen);
2248         if (ret == -1) {
2249                 tevent_req_error(req, errno);
2250                 return;
2251         }
2252
2253         tevent_req_done(req);
2254 }
2255
2256 static int tstream_bsd_connect_recv(struct tevent_req *req,
2257                                     int *perrno,
2258                                     TALLOC_CTX *mem_ctx,
2259                                     struct tstream_context **stream,
2260                                     struct tsocket_address **local,
2261                                     const char *location)
2262 {
2263         struct tstream_bsd_connect_state *state = tevent_req_data(req,
2264                                         struct tstream_bsd_connect_state);
2265         int ret;
2266
2267         ret = tsocket_simple_int_recv(req, perrno);
2268         if (ret == 0) {
2269                 ret = _tstream_bsd_existing_socket(mem_ctx,
2270                                                    state->fd,
2271                                                    stream,
2272                                                    location);
2273                 if (ret == -1) {
2274                         *perrno = errno;
2275                         goto done;
2276                 }
2277                 TALLOC_FREE(state->fde);
2278                 state->fd = -1;
2279
2280                 if (local) {
2281                         *local = talloc_move(mem_ctx, &state->local);
2282                 }
2283         }
2284
2285 done:
2286         tevent_req_received(req);
2287         return ret;
2288 }
2289
2290 struct tevent_req * tstream_inet_tcp_connect_send(TALLOC_CTX *mem_ctx,
2291                                         struct tevent_context *ev,
2292                                         const struct tsocket_address *local,
2293                                         const struct tsocket_address *remote)
2294 {
2295         struct tsocket_address_bsd *lbsda =
2296                 talloc_get_type_abort(local->private_data,
2297                 struct tsocket_address_bsd);
2298         struct tevent_req *req;
2299         int sys_errno = 0;
2300
2301         switch (lbsda->u.sa.sa_family) {
2302         case AF_INET:
2303                 break;
2304 #ifdef HAVE_IPV6
2305         case AF_INET6:
2306                 break;
2307 #endif
2308         default:
2309                 sys_errno = EINVAL;
2310                 break;
2311         }
2312
2313         req = tstream_bsd_connect_send(mem_ctx, ev, sys_errno, local, remote);
2314
2315         return req;
2316 }
2317
2318 int _tstream_inet_tcp_connect_recv(struct tevent_req *req,
2319                                    int *perrno,
2320                                    TALLOC_CTX *mem_ctx,
2321                                    struct tstream_context **stream,
2322                                    struct tsocket_address **local,
2323                                    const char *location)
2324 {
2325         return tstream_bsd_connect_recv(req, perrno,
2326                                         mem_ctx, stream, local,
2327                                         location);
2328 }
2329
2330 struct tevent_req * tstream_unix_connect_send(TALLOC_CTX *mem_ctx,
2331                                         struct tevent_context *ev,
2332                                         const struct tsocket_address *local,
2333                                         const struct tsocket_address *remote)
2334 {
2335         struct tsocket_address_bsd *lbsda =
2336                 talloc_get_type_abort(local->private_data,
2337                 struct tsocket_address_bsd);
2338         struct tevent_req *req;
2339         int sys_errno = 0;
2340
2341         switch (lbsda->u.sa.sa_family) {
2342         case AF_UNIX:
2343                 break;
2344         default:
2345                 sys_errno = EINVAL;
2346                 break;
2347         }
2348
2349         req = tstream_bsd_connect_send(mem_ctx, ev, sys_errno, local, remote);
2350
2351         return req;
2352 }
2353
2354 int _tstream_unix_connect_recv(struct tevent_req *req,
2355                                       int *perrno,
2356                                       TALLOC_CTX *mem_ctx,
2357                                       struct tstream_context **stream,
2358                                       const char *location)
2359 {
2360         return tstream_bsd_connect_recv(req, perrno,
2361                                         mem_ctx, stream, NULL,
2362                                         location);
2363 }
2364
2365 int _tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
2366                              struct tstream_context **_stream1,
2367                              TALLOC_CTX *mem_ctx2,
2368                              struct tstream_context **_stream2,
2369                              const char *location)
2370 {
2371         int ret;
2372         int fds[2];
2373         int fd1;
2374         int fd2;
2375         struct tstream_context *stream1 = NULL;
2376         struct tstream_context *stream2 = NULL;
2377
2378         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
2379         if (ret == -1) {
2380                 return -1;
2381         }
2382         fd1 = fds[0];
2383         fd2 = fds[1];
2384
2385         fd1 = tsocket_bsd_common_prepare_fd(fd1, true);
2386         if (fd1 == -1) {
2387                 int sys_errno = errno;
2388                 close(fd2);
2389                 errno = sys_errno;
2390                 return -1;
2391         }
2392
2393         fd2 = tsocket_bsd_common_prepare_fd(fd2, true);
2394         if (fd2 == -1) {
2395                 int sys_errno = errno;
2396                 close(fd1);
2397                 errno = sys_errno;
2398                 return -1;
2399         }
2400
2401         ret = _tstream_bsd_existing_socket(mem_ctx1,
2402                                            fd1,
2403                                            &stream1,
2404                                            location);
2405         if (ret == -1) {
2406                 int sys_errno = errno;
2407                 close(fd1);
2408                 close(fd2);
2409                 errno = sys_errno;
2410                 return -1;
2411         }
2412
2413         ret = _tstream_bsd_existing_socket(mem_ctx2,
2414                                            fd2,
2415                                            &stream2,
2416                                            location);
2417         if (ret == -1) {
2418                 int sys_errno = errno;
2419                 talloc_free(stream1);
2420                 close(fd2);
2421                 errno = sys_errno;
2422                 return -1;
2423         }
2424
2425         *_stream1 = stream1;
2426         *_stream2 = stream2;
2427         return 0;
2428 }
2429