Merge branch 'master' into wspp-schema
[ira/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 tevent
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/network.h"
26 #include "tsocket.h"
27 #include "tsocket_internal.h"
28
29 static const struct tsocket_context_ops tsocket_context_bsd_ops;
30 static const struct tsocket_address_ops tsocket_address_bsd_ops;
31
32 static int tsocket_context_bsd_set_option(const struct tsocket_context *sock,
33                                           const char *option,
34                                           bool force,
35                                           const char *value);
36
37 struct tsocket_context_bsd {
38         bool close_on_disconnect;
39         int fd;
40         struct tevent_fd *fde;
41 };
42
43 struct tsocket_address_bsd {
44         bool broadcast;
45         union {
46                 struct sockaddr sa;
47                 struct sockaddr_in in;
48 #ifdef HAVE_IPV6
49                 struct sockaddr_in6 in6;
50 #endif
51                 struct sockaddr_un un;
52                 struct sockaddr_storage ss;
53         } u;
54 };
55
56 static int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
57                                               struct sockaddr *sa,
58                                               socklen_t sa_len,
59                                               struct tsocket_address **_addr,
60                                               const char *location)
61 {
62         struct tsocket_address *addr;
63         struct tsocket_address_bsd *bsda;
64
65         switch (sa->sa_family) {
66         case AF_UNIX:
67                 if (sa_len < sizeof(struct sockaddr_un)) {
68                         errno = EINVAL;
69                         return -1;
70                 }
71                 break;
72         case AF_INET:
73                 if (sa_len < sizeof(struct sockaddr_in)) {
74                         errno = EINVAL;
75                         return -1;
76                 }
77                 break;
78 #ifdef HAVE_IPV6
79         case AF_INET6:
80                 if (sa_len < sizeof(struct sockaddr_in6)) {
81                         errno = EINVAL;
82                         return -1;
83                 }
84                 break;
85 #endif
86         default:
87                 errno = EAFNOSUPPORT;
88                 return -1;
89         }
90
91         if (sa_len > sizeof(struct sockaddr_storage)) {
92                 errno = EINVAL;
93                 return -1;
94         }
95
96         addr = tsocket_address_create(mem_ctx,
97                                       &tsocket_address_bsd_ops,
98                                       &bsda,
99                                       struct tsocket_address_bsd,
100                                       location);
101         if (!addr) {
102                 errno = ENOMEM;
103                 return -1;
104         }
105
106         ZERO_STRUCTP(bsda);
107
108         memcpy(&bsda->u.ss, sa, sa_len);
109
110         *_addr = addr;
111         return 0;
112 }
113
114 int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
115                                        const char *fam,
116                                        const char *addr,
117                                        uint16_t port,
118                                        struct tsocket_address **_addr,
119                                        const char *location)
120 {
121         struct addrinfo hints;
122         struct addrinfo *result = NULL;
123         char port_str[6];
124         int ret;
125
126         ZERO_STRUCT(hints);
127         /*
128          * we use SOCKET_STREAM here to get just one result
129          * back from getaddrinfo().
130          */
131         hints.ai_socktype = SOCK_STREAM;
132         hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
133
134         if (strcasecmp(fam, "ip") == 0) {
135                 hints.ai_family = AF_UNSPEC;
136                 if (!addr) {
137 #ifdef HAVE_IPV6
138                         addr = "::";
139 #else
140                         addr = "0.0.0.0";
141 #endif
142                 }
143         } else if (strcasecmp(fam, "ipv4") == 0) {
144                 hints.ai_family = AF_INET;
145                 if (!addr) {
146                         addr = "0.0.0.0";
147                 }
148 #ifdef HAVE_IPV6
149         } else if (strcasecmp(fam, "ipv6") == 0) {
150                 hints.ai_family = AF_INET6;
151                 if (!addr) {
152                         addr = "::";
153                 }
154 #endif
155         } else {
156                 errno = EAFNOSUPPORT;
157                 return -1;
158         }
159
160         snprintf(port_str, sizeof(port_str) - 1, "%u", port);
161
162         ret = getaddrinfo(addr, port_str, &hints, &result);
163         if (ret != 0) {
164                 switch (ret) {
165                 case EAI_FAIL:
166                         errno = EINVAL;
167                         break;
168                 }
169                 ret = -1;
170                 goto done;
171         }
172
173         if (result->ai_socktype != SOCK_STREAM) {
174                 errno = EINVAL;
175                 ret = -1;
176                 goto done;
177         }
178
179         ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
180                                                   result->ai_addr,
181                                                   result->ai_addrlen,
182                                                   _addr,
183                                                   location);
184
185 done:
186         if (result) {
187                 freeaddrinfo(result);
188         }
189         return ret;
190 }
191
192 char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
193                                        TALLOC_CTX *mem_ctx)
194 {
195         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
196                                            struct tsocket_address_bsd);
197         char addr_str[INET6_ADDRSTRLEN+1];
198         const char *str;
199
200         if (!bsda) {
201                 errno = EINVAL;
202                 return NULL;
203         }
204
205         switch (bsda->u.sa.sa_family) {
206         case AF_INET:
207                 str = inet_ntop(bsda->u.in.sin_family,
208                                 &bsda->u.in.sin_addr,
209                                 addr_str, sizeof(addr_str));
210                 break;
211 #ifdef HAVE_IPV6
212         case AF_INET6:
213                 str = inet_ntop(bsda->u.in6.sin6_family,
214                                 &bsda->u.in6.sin6_addr,
215                                 addr_str, sizeof(addr_str));
216                 break;
217 #endif
218         default:
219                 errno = EINVAL;
220                 return NULL;
221         }
222
223         if (!str) {
224                 return NULL;
225         }
226
227         return talloc_strdup(mem_ctx, str);
228 }
229
230 uint16_t tsocket_address_inet_port(const struct tsocket_address *addr)
231 {
232         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
233                                            struct tsocket_address_bsd);
234         uint16_t port = 0;
235
236         if (!bsda) {
237                 errno = EINVAL;
238                 return 0;
239         }
240
241         switch (bsda->u.sa.sa_family) {
242         case AF_INET:
243                 port = ntohs(bsda->u.in.sin_port);
244                 break;
245 #ifdef HAVE_IPV6
246         case AF_INET6:
247                 port = ntohs(bsda->u.in6.sin6_port);
248                 break;
249 #endif
250         default:
251                 errno = EINVAL;
252                 return 0;
253         }
254
255         return port;
256 }
257
258 int tsocket_address_inet_set_port(struct tsocket_address *addr,
259                                   uint16_t port)
260 {
261         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
262                                            struct tsocket_address_bsd);
263
264         if (!bsda) {
265                 errno = EINVAL;
266                 return -1;
267         }
268
269         switch (bsda->u.sa.sa_family) {
270         case AF_INET:
271                 bsda->u.in.sin_port = htons(port);
272                 break;
273 #ifdef HAVE_IPV6
274         case AF_INET6:
275                 bsda->u.in6.sin6_port = htons(port);
276                 break;
277 #endif
278         default:
279                 errno = EINVAL;
280                 return -1;
281         }
282
283         return 0;
284 }
285
286 void tsocket_address_inet_set_broadcast(struct tsocket_address *addr,
287                                         bool broadcast)
288 {
289         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
290                                            struct tsocket_address_bsd);
291
292         if (!bsda) {
293                 return;
294         }
295
296         bsda->broadcast = broadcast;
297 }
298
299 int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
300                                     const char *path,
301                                     struct tsocket_address **_addr,
302                                     const char *location)
303 {
304         struct sockaddr_un un;
305         void *p = &un;
306         int ret;
307
308         if (!path) {
309                 path = "";
310         }
311
312         ZERO_STRUCT(un);
313         un.sun_family = AF_UNIX;
314         strncpy(un.sun_path, path, sizeof(un.sun_path));
315
316         ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
317                                                  (struct sockaddr *)p,
318                                                  sizeof(un),
319                                                  _addr,
320                                                  location);
321
322         return ret;
323 }
324
325 char *tsocket_address_unix_path(const struct tsocket_address *addr,
326                                 TALLOC_CTX *mem_ctx)
327 {
328         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
329                                            struct tsocket_address_bsd);
330         const char *str;
331
332         if (!bsda) {
333                 errno = EINVAL;
334                 return NULL;
335         }
336
337         switch (bsda->u.sa.sa_family) {
338         case AF_UNIX:
339                 str = bsda->u.un.sun_path;
340                 break;
341         default:
342                 errno = EINVAL;
343                 return NULL;
344         }
345
346         return talloc_strdup(mem_ctx, str);
347 }
348
349 static char *tsocket_address_bsd_string(const struct tsocket_address *addr,
350                                         TALLOC_CTX *mem_ctx)
351 {
352         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
353                                            struct tsocket_address_bsd);
354         char *str;
355         char *addr_str;
356         const char *prefix = NULL;
357         uint16_t port;
358
359         switch (bsda->u.sa.sa_family) {
360         case AF_UNIX:
361                 return talloc_asprintf(mem_ctx, "unix:%s",
362                                        bsda->u.un.sun_path);
363         case AF_INET:
364                 prefix = "ipv4";
365                 break;
366         case AF_INET6:
367                 prefix = "ipv6";
368                 break;
369         default:
370                 errno = EINVAL;
371                 return NULL;
372         }
373
374         addr_str = tsocket_address_inet_addr_string(addr, mem_ctx);
375         if (!addr_str) {
376                 return NULL;
377         }
378
379         port = tsocket_address_inet_port(addr);
380
381         str = talloc_asprintf(mem_ctx, "%s:%s:%u",
382                               prefix, addr_str, port);
383         talloc_free(addr_str);
384
385         return str;
386 }
387
388 static struct tsocket_address *tsocket_address_bsd_copy(const struct tsocket_address *addr,
389                                                          TALLOC_CTX *mem_ctx,
390                                                          const char *location)
391 {
392         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
393                                            struct tsocket_address_bsd);
394         struct tsocket_address *copy;
395         int ret;
396
397         ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
398                                                  &bsda->u.sa,
399                                                  sizeof(bsda->u.ss),
400                                                  &copy,
401                                                  location);
402         if (ret != 0) {
403                 return NULL;
404         }
405
406         tsocket_address_inet_set_broadcast(copy, bsda->broadcast);
407         return copy;
408 }
409
410 int _tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx,
411                                        int fd, bool close_on_disconnect,
412                                        struct tsocket_context **_sock,
413                                        const char *location)
414 {
415         struct tsocket_context *sock;
416         struct tsocket_context_bsd *bsds;
417
418         sock = tsocket_context_create(mem_ctx,
419                                       &tsocket_context_bsd_ops,
420                                       &bsds,
421                                       struct tsocket_context_bsd,
422                                       location);
423         if (!sock) {
424                 return -1;
425         }
426
427         bsds->close_on_disconnect       = close_on_disconnect;
428         bsds->fd                        = fd;
429         bsds->fde                       = NULL;
430
431         *_sock = sock;
432         return 0;
433 }
434
435 static int tsocket_address_bsd_create_socket(const struct tsocket_address *addr,
436                                              enum tsocket_type type,
437                                              TALLOC_CTX *mem_ctx,
438                                              struct tsocket_context **_sock,
439                                              const char *location)
440 {
441         struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
442                                            struct tsocket_address_bsd);
443         struct tsocket_context *sock;
444         int bsd_type;
445         int fd;
446         int ret;
447         bool do_bind = false;
448         bool do_reuseaddr = false;
449
450         switch (type) {
451         case TSOCKET_TYPE_STREAM:
452                 if (bsda->broadcast) {
453                         errno = EINVAL;
454                         return -1;
455                 }
456                 bsd_type = SOCK_STREAM;
457                 break;
458         case TSOCKET_TYPE_DGRAM:
459                 bsd_type = SOCK_DGRAM;
460                 break;
461         default:
462                 errno = EPROTONOSUPPORT;
463                 return -1;
464         }
465
466         switch (bsda->u.sa.sa_family) {
467         case AF_UNIX:
468                 if (bsda->broadcast) {
469                         errno = EINVAL;
470                         return -1;
471                 }
472                 if (bsda->u.un.sun_path[0] != 0) {
473                         do_bind = true;
474                 }
475                 break;
476         case AF_INET:
477                 if (bsda->u.in.sin_port != 0) {
478                         do_reuseaddr = true;
479                         do_bind = true;
480                 }
481                 if (bsda->u.in.sin_addr.s_addr == INADDR_ANY) {
482                         do_bind = true;
483                 }
484                 break;
485 #ifdef HAVE_IPV6
486         case AF_INET6:
487                 if (bsda->u.in6.sin6_port != 0) {
488                         do_reuseaddr = true;
489                         do_bind = true;
490                 }
491                 if (memcmp(&in6addr_any,
492                            &bsda->u.in6.sin6_addr,
493                            sizeof(in6addr_any)) != 0) {
494                         do_bind = true;
495                 }
496                 break;
497 #endif
498         default:
499                 errno = EINVAL;
500                 return -1;
501         }
502
503         fd = socket(bsda->u.sa.sa_family, bsd_type, 0);
504         if (fd < 0) {
505                 return fd;
506         }
507
508         fd = tsocket_common_prepare_fd(fd, true);
509         if (fd < 0) {
510                 return fd;
511         }
512
513         ret = _tsocket_context_bsd_wrap_existing(mem_ctx, fd, true,
514                                                  &sock, location);
515         if (ret != 0) {
516                 int saved_errno = errno;
517                 close(fd);
518                 errno = saved_errno;
519                 return ret;
520         }
521
522         if (bsda->broadcast) {
523                 ret = tsocket_context_bsd_set_option(sock, "SO_BROADCAST", true, "1");
524                 if (ret != 0) {
525                         int saved_errno = errno;
526                         talloc_free(sock);
527                         errno = saved_errno;
528                         return ret;
529                 }
530         }
531
532         if (do_reuseaddr) {
533                 ret = tsocket_context_bsd_set_option(sock, "SO_REUSEADDR", true, "1");
534                 if (ret != 0) {
535                         int saved_errno = errno;
536                         talloc_free(sock);
537                         errno = saved_errno;
538                         return ret;
539                 }
540         }
541
542         if (do_bind) {
543                 ret = bind(fd, &bsda->u.sa, sizeof(bsda->u.ss));
544                 if (ret != 0) {
545                         int saved_errno = errno;
546                         talloc_free(sock);
547                         errno = saved_errno;
548                         return ret;
549                 }
550         }
551
552         *_sock = sock;
553         return 0;
554 }
555
556 static const struct tsocket_address_ops tsocket_address_bsd_ops = {
557         .name           = "bsd",
558         .string         = tsocket_address_bsd_string,
559         .copy           = tsocket_address_bsd_copy,
560         .create_socket  = tsocket_address_bsd_create_socket
561 };
562
563 static void tsocket_context_bsd_fde_handler(struct tevent_context *ev,
564                                             struct tevent_fd *fde,
565                                             uint16_t flags,
566                                             void *private_data)
567 {
568         struct tsocket_context *sock = talloc_get_type(private_data,
569                                        struct tsocket_context);
570
571         if (flags & TEVENT_FD_WRITE) {
572                 sock->event.write_handler(sock, sock->event.write_private);
573                 return;
574         }
575         if (flags & TEVENT_FD_READ) {
576                 sock->event.read_handler(sock, sock->event.read_private);
577                 return;
578         }
579 }
580
581 static int tsocket_context_bsd_set_event_context(struct tsocket_context *sock,
582                                                  struct tevent_context *ev)
583 {
584         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
585                                            struct tsocket_context_bsd);
586
587         talloc_free(bsds->fde);
588         bsds->fde = NULL;
589         ZERO_STRUCT(sock->event);
590
591         if (!ev) {
592                 return 0;
593         }
594
595         bsds->fde = tevent_add_fd(ev, bsds,
596                                   bsds->fd,
597                                   0,
598                                   tsocket_context_bsd_fde_handler,
599                                   sock);
600         if (!bsds->fde) {
601                 if (errno == 0) {
602                         errno = ENOMEM;
603                 }
604                 return -1;
605         }
606
607         sock->event.ctx = ev;
608
609         return 0;
610 }
611
612 static int tsocket_context_bsd_set_read_handler(struct tsocket_context *sock,
613                                                 tsocket_event_handler_t handler,
614                                                 void *private_data)
615 {
616         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
617                                            struct tsocket_context_bsd);
618
619         if (sock->event.read_handler && !handler) {
620                 TEVENT_FD_NOT_READABLE(bsds->fde);
621         } else if (!sock->event.read_handler && handler) {
622                 TEVENT_FD_READABLE(bsds->fde);
623         }
624
625         sock->event.read_handler = handler;
626         sock->event.read_private = private_data;
627
628         return 0;
629 }
630
631 static int tsocket_context_bsd_set_write_handler(struct tsocket_context *sock,
632                                                  tsocket_event_handler_t handler,
633                                                  void *private_data)
634 {
635         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
636                                            struct tsocket_context_bsd);
637
638         if (sock->event.write_handler && !handler) {
639                 TEVENT_FD_NOT_WRITEABLE(bsds->fde);
640         } else if (!sock->event.write_handler && handler) {
641                 TEVENT_FD_WRITEABLE(bsds->fde);
642         }
643
644         sock->event.write_handler = handler;
645         sock->event.write_private = private_data;
646
647         return 0;
648 }
649
650 static int tsocket_context_bsd_connect_to(struct tsocket_context *sock,
651                                           const struct tsocket_address *remote)
652 {
653         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
654                                            struct tsocket_context_bsd);
655         struct tsocket_address_bsd *bsda = talloc_get_type(remote->private_data,
656                                            struct tsocket_address_bsd);
657         int ret;
658
659         ret = connect(bsds->fd, &bsda->u.sa,
660                       sizeof(bsda->u.ss));
661
662         return ret;
663 }
664
665 static int tsocket_context_bsd_listen_on(struct tsocket_context *sock,
666                                           int queue_size)
667 {
668         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
669                                            struct tsocket_context_bsd);
670         int ret;
671
672         ret = listen(bsds->fd, queue_size);
673
674         return ret;
675 }
676
677 static int tsocket_context_bsd_accept_new(struct tsocket_context *sock,
678                                            TALLOC_CTX *mem_ctx,
679                                            struct tsocket_context **_new_sock,
680                                            const char *location)
681 {
682         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
683                                            struct tsocket_context_bsd);
684         int new_fd;
685         struct tsocket_context *new_sock;
686         struct tsocket_context_bsd *new_bsds;
687         struct sockaddr_storage ss;
688         void *p = &ss;
689         socklen_t ss_len = sizeof(ss);
690
691         new_fd = accept(bsds->fd, (struct sockaddr *)p, &ss_len);
692         if (new_fd < 0) {
693                 return new_fd;
694         }
695
696         new_fd = tsocket_common_prepare_fd(new_fd, true);
697         if (new_fd < 0) {
698                 return new_fd;
699         }
700
701         new_sock = tsocket_context_create(mem_ctx,
702                                           &tsocket_context_bsd_ops,
703                                           &new_bsds,
704                                           struct tsocket_context_bsd,
705                                           location);
706         if (!new_sock) {
707                 int saved_errno = errno;
708                 close(new_fd);
709                 errno = saved_errno;
710                 return -1;
711         }
712
713         new_bsds->close_on_disconnect   = true;
714         new_bsds->fd                    = new_fd;
715         new_bsds->fde                   = NULL;
716
717         *_new_sock = new_sock;
718         return 0;
719 }
720
721 static ssize_t tsocket_context_bsd_pending_data(struct tsocket_context *sock)
722 {
723         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
724                                            struct tsocket_context_bsd);
725         int ret;
726         int value = 0;
727
728         ret = ioctl(bsds->fd, FIONREAD, &value);
729         if (ret == -1) {
730                 return ret;
731         }
732
733         if (ret == 0) {
734                 if (value == 0) {
735                         int error=0;
736                         socklen_t len = sizeof(error);
737                         /*
738                          * if no data is available check if the socket
739                          * is in error state. For dgram sockets
740                          * it's the way to return ICMP error messages
741                          * of connected sockets to the caller.
742                          */
743                         ret = getsockopt(bsds->fd, SOL_SOCKET, SO_ERROR,
744                                          &error, &len);
745                         if (ret == -1) {
746                                 return ret;
747                         }
748                         if (error != 0) {
749                                 errno = error;
750                                 return -1;
751                         }
752                 }
753                 return value;
754         }
755
756         /* this should not be reached */
757         errno = EIO;
758         return -1;
759 }
760
761 static int tsocket_context_bsd_readv_data(struct tsocket_context *sock,
762                                           const struct iovec *vector,
763                                           size_t count)
764 {
765         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
766                                            struct tsocket_context_bsd);
767         int ret;
768
769         ret = readv(bsds->fd, vector, count);
770
771         return ret;
772 }
773
774 static int tsocket_context_bsd_writev_data(struct tsocket_context *sock,
775                                            const struct iovec *vector,
776                                            size_t count)
777 {
778         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
779                                            struct tsocket_context_bsd);
780         int ret;
781
782         ret = writev(bsds->fd, vector, count);
783
784         return ret;
785 }
786
787 static ssize_t tsocket_context_bsd_recvfrom_data(struct tsocket_context *sock,
788                                                   uint8_t *data, size_t len,
789                                                   TALLOC_CTX *addr_ctx,
790                                                   struct tsocket_address **remote)
791 {
792         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
793                                            struct tsocket_context_bsd);
794         struct tsocket_address *addr = NULL;
795         struct tsocket_address_bsd *bsda;
796         ssize_t ret;
797         struct sockaddr *sa = NULL;
798         socklen_t sa_len = 0;
799
800         if (remote) {
801                 addr = tsocket_address_create(addr_ctx,
802                                               &tsocket_address_bsd_ops,
803                                               &bsda,
804                                               struct tsocket_address_bsd,
805                                               __location__ "recvfrom");
806                 if (!addr) {
807                         return -1;
808                 }
809
810                 ZERO_STRUCTP(bsda);
811
812                 sa = &bsda->u.sa;
813                 sa_len = sizeof(bsda->u.ss);
814         }
815
816         ret = recvfrom(bsds->fd, data, len, 0, sa, &sa_len);
817         if (ret < 0) {
818                 int saved_errno = errno;
819                 talloc_free(addr);
820                 errno = saved_errno;
821                 return ret;
822         }
823
824         if (remote) {
825                 *remote = addr;
826         }
827         return ret;
828 }
829
830 static ssize_t tsocket_context_bsd_sendto_data(struct tsocket_context *sock,
831                                                 const uint8_t *data, size_t len,
832                                                 const struct tsocket_address *remote)
833 {
834         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
835                                            struct tsocket_context_bsd);
836         struct sockaddr *sa = NULL;
837         socklen_t sa_len = 0;
838         ssize_t ret;
839
840         if (remote) {
841                 struct tsocket_address_bsd *bsda =
842                         talloc_get_type(remote->private_data,
843                         struct tsocket_address_bsd);
844
845                 sa = &bsda->u.sa;
846                 sa_len = sizeof(bsda->u.ss);
847         }
848
849         ret = sendto(bsds->fd, data, len, 0, sa, sa_len);
850
851         return ret;
852 }
853
854 static int tsocket_context_bsd_get_status(const struct tsocket_context *sock)
855 {
856         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
857                                            struct tsocket_context_bsd);
858         int ret;
859         int error=0;
860         socklen_t len = sizeof(error);
861
862         if (bsds->fd == -1) {
863                 errno = EPIPE;
864                 return -1;
865         }
866
867         ret = getsockopt(bsds->fd, SOL_SOCKET, SO_ERROR, &error, &len);
868         if (ret == -1) {
869                 return ret;
870         }
871         if (error != 0) {
872                 errno = error;
873                 return -1;
874         }
875
876         return 0;
877 }
878
879 static int tsocket_context_bsd_get_local_address(const struct tsocket_context *sock,
880                                                   TALLOC_CTX *mem_ctx,
881                                                   struct tsocket_address **_addr,
882                                                   const char *location)
883 {
884         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
885                                            struct tsocket_context_bsd);
886         struct tsocket_address *addr;
887         struct tsocket_address_bsd *bsda;
888         ssize_t ret;
889         socklen_t sa_len;
890
891         addr = tsocket_address_create(mem_ctx,
892                                       &tsocket_address_bsd_ops,
893                                       &bsda,
894                                       struct tsocket_address_bsd,
895                                       location);
896         if (!addr) {
897                 return -1;
898         }
899
900         ZERO_STRUCTP(bsda);
901
902         sa_len = sizeof(bsda->u.ss);
903         ret = getsockname(bsds->fd, &bsda->u.sa, &sa_len);
904         if (ret < 0) {
905                 int saved_errno = errno;
906                 talloc_free(addr);
907                 errno = saved_errno;
908                 return ret;
909         }
910
911         *_addr = addr;
912         return 0;
913 }
914
915 static int tsocket_context_bsd_get_remote_address(const struct tsocket_context *sock,
916                                                    TALLOC_CTX *mem_ctx,
917                                                    struct tsocket_address **_addr,
918                                                    const char *location)
919 {
920         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
921                                            struct tsocket_context_bsd);
922         struct tsocket_address *addr;
923         struct tsocket_address_bsd *bsda;
924         ssize_t ret;
925         socklen_t sa_len;
926
927         addr = tsocket_address_create(mem_ctx,
928                                       &tsocket_address_bsd_ops,
929                                       &bsda,
930                                       struct tsocket_address_bsd,
931                                       location);
932         if (!addr) {
933                 return -1;
934         }
935
936         ZERO_STRUCTP(bsda);
937
938         sa_len = sizeof(bsda->u.ss);
939         ret = getpeername(bsds->fd, &bsda->u.sa, &sa_len);
940         if (ret < 0) {
941                 int saved_errno = errno;
942                 talloc_free(addr);
943                 errno = saved_errno;
944                 return ret;
945         }
946
947         *_addr = addr;
948         return 0;
949 }
950
951 static const struct tsocket_context_bsd_option {
952         const char *name;
953         int level;
954         int optnum;
955         int optval;
956 } tsocket_context_bsd_options[] = {
957 #define TSOCKET_OPTION(_level, _optnum, _optval) { \
958         .name = #_optnum, \
959         .level = _level, \
960         .optnum = _optnum, \
961         .optval = _optval \
962 }
963         TSOCKET_OPTION(SOL_SOCKET, SO_REUSEADDR, 0),
964         TSOCKET_OPTION(SOL_SOCKET, SO_BROADCAST, 0)
965 };
966
967 static int tsocket_context_bsd_get_option(const struct tsocket_context *sock,
968                                           const char *option,
969                                           TALLOC_CTX *mem_ctx,
970                                           char **_value)
971 {
972         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
973                                            struct tsocket_context_bsd);
974         const struct tsocket_context_bsd_option *opt = NULL;
975         uint32_t i;
976         int optval;
977         socklen_t optval_len = sizeof(optval);
978         char *value;
979         int ret;
980
981         for (i=0; i < ARRAY_SIZE(tsocket_context_bsd_options); i++) {
982                 if (strcmp(option, tsocket_context_bsd_options[i].name) != 0) {
983                         continue;
984                 }
985
986                 opt = &tsocket_context_bsd_options[i];
987                 break;
988         }
989
990         if (!opt) {
991                 goto nosys;
992         }
993
994         ret = getsockopt(bsds->fd, opt->level, opt->optnum,
995                          (void *)&optval, &optval_len);
996         if (ret != 0) {
997                 return ret;
998         }
999
1000         if (optval_len != sizeof(optval)) {
1001                 value = NULL;
1002         } if (opt->optval != 0) {
1003                 if (optval == opt->optval) {
1004                         value = talloc_strdup(mem_ctx, "1");
1005                 } else {
1006                         value = talloc_strdup(mem_ctx, "0");
1007                 }
1008                 if (!value) {
1009                         goto nomem;
1010                 }
1011         } else {
1012                 value = talloc_asprintf(mem_ctx, "%d", optval);
1013                 if (!value) {
1014                         goto nomem;
1015                 }
1016         }
1017
1018         *_value = value;
1019         return 0;
1020
1021  nomem:
1022         errno = ENOMEM;
1023         return -1;
1024  nosys:
1025         errno = ENOSYS;
1026         return -1;
1027 }
1028
1029 static int tsocket_context_bsd_set_option(const struct tsocket_context *sock,
1030                                           const char *option,
1031                                           bool force,
1032                                           const char *value)
1033 {
1034         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
1035                                            struct tsocket_context_bsd);
1036         const struct tsocket_context_bsd_option *opt = NULL;
1037         uint32_t i;
1038         int optval;
1039         int ret;
1040
1041         for (i=0; i < ARRAY_SIZE(tsocket_context_bsd_options); i++) {
1042                 if (strcmp(option, tsocket_context_bsd_options[i].name) != 0) {
1043                         continue;
1044                 }
1045
1046                 opt = &tsocket_context_bsd_options[i];
1047                 break;
1048         }
1049
1050         if (!opt) {
1051                 goto nosys;
1052         }
1053
1054         if (value) {
1055                 if (opt->optval != 0) {
1056                         errno = EINVAL;
1057                         return -1;
1058                 }
1059
1060                 optval = atoi(value);
1061         } else {
1062                 optval = opt->optval;
1063         }
1064
1065         ret = setsockopt(bsds->fd, opt->level, opt->optnum,
1066                          (const void *)&optval, sizeof(optval));
1067         if (ret != 0) {
1068                 if (!force) {
1069                         errno = 0;
1070                         return 0;
1071                 }
1072                 return ret;
1073         }
1074
1075         return 0;
1076
1077  nosys:
1078         if (!force) {
1079                 return 0;
1080         }
1081
1082         errno = ENOSYS;
1083         return -1;
1084 }
1085
1086 static void tsocket_context_bsd_disconnect(struct tsocket_context *sock)
1087 {
1088         struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
1089                                            struct tsocket_context_bsd);
1090
1091         tsocket_context_bsd_set_event_context(sock, NULL);
1092
1093         if (bsds->fd != -1) {
1094                 if (bsds->close_on_disconnect) {
1095                         close(bsds->fd);
1096                 }
1097                 bsds->fd = -1;
1098         }
1099 }
1100
1101 static const struct tsocket_context_ops tsocket_context_bsd_ops = {
1102         .name                   = "bsd",
1103
1104         .set_event_context      = tsocket_context_bsd_set_event_context,
1105         .set_read_handler       = tsocket_context_bsd_set_read_handler,
1106         .set_write_handler      = tsocket_context_bsd_set_write_handler,
1107
1108         .connect_to             = tsocket_context_bsd_connect_to,
1109         .listen_on              = tsocket_context_bsd_listen_on,
1110         .accept_new             = tsocket_context_bsd_accept_new,
1111
1112         .pending_data           = tsocket_context_bsd_pending_data,
1113         .readv_data             = tsocket_context_bsd_readv_data,
1114         .writev_data            = tsocket_context_bsd_writev_data,
1115         .recvfrom_data          = tsocket_context_bsd_recvfrom_data,
1116         .sendto_data            = tsocket_context_bsd_sendto_data,
1117
1118         .get_status             = tsocket_context_bsd_get_status,
1119         .get_local_address      = tsocket_context_bsd_get_local_address,
1120         .get_remote_address     = tsocket_context_bsd_get_remote_address,
1121
1122         .get_option             = tsocket_context_bsd_get_option,
1123         .set_option             = tsocket_context_bsd_set_option,
1124
1125         .disconnect             = tsocket_context_bsd_disconnect
1126 };