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