LCOV - code coverage report
Current view: top level - lib/tsocket - tsocket_bsd.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 829 1341 61.8 %
Date: 2024-06-13 04:01:37 Functions: 56 68 82.4 %

          Line data    Source code
       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 "system/select.h"
      28             : #include "tsocket.h"
      29             : #include "tsocket_internal.h"
      30             : #include "lib/util/select.h"
      31             : #include "lib/util/iov_buf.h"
      32             : #include "lib/util/blocking.h"
      33             : #include "lib/util/util_net.h"
      34             : #include "lib/util/samba_util.h"
      35             : 
      36    16218708 : static int tsocket_bsd_error_from_errno(int ret,
      37             :                                         int sys_errno,
      38             :                                         bool *retry)
      39             : {
      40    16218708 :         *retry = false;
      41             : 
      42    16218708 :         if (ret >= 0) {
      43    16214784 :                 return 0;
      44             :         }
      45             : 
      46        3924 :         if (ret != -1) {
      47           0 :                 return EIO;
      48             :         }
      49             : 
      50        3924 :         if (sys_errno == 0) {
      51           0 :                 return EIO;
      52             :         }
      53             : 
      54        3924 :         if (sys_errno == EINTR) {
      55           0 :                 *retry = true;
      56           0 :                 return sys_errno;
      57             :         }
      58             : 
      59        3924 :         if (sys_errno == EINPROGRESS) {
      60           0 :                 *retry = true;
      61           0 :                 return sys_errno;
      62             :         }
      63             : 
      64        3924 :         if (sys_errno == EAGAIN) {
      65        3889 :                 *retry = true;
      66        3889 :                 return sys_errno;
      67             :         }
      68             : 
      69             :         /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
      70          35 :         if (sys_errno == ENOMEM) {
      71           0 :                 *retry = true;
      72           0 :                 return sys_errno;
      73             :         }
      74             : 
      75             : #ifdef EWOULDBLOCK
      76          35 :         if (sys_errno == EWOULDBLOCK) {
      77           0 :                 *retry = true;
      78           0 :                 return sys_errno;
      79             :         }
      80             : #endif
      81             : 
      82          35 :         return sys_errno;
      83             : }
      84             : 
      85        7370 : static int tsocket_bsd_common_prepare_fd(int fd, bool high_fd)
      86             : {
      87             :         int i;
      88        7370 :         int sys_errno = 0;
      89             :         int fds[3];
      90        7370 :         int num_fds = 0;
      91             : 
      92             :         int result;
      93             :         bool ok;
      94             : 
      95        7370 :         if (fd == -1) {
      96           0 :                 return -1;
      97             :         }
      98             : 
      99             :         /* first make a fd >= 3 */
     100        7370 :         if (high_fd) {
     101       13791 :                 while (fd < 3) {
     102           0 :                         fds[num_fds++] = fd;
     103           0 :                         fd = dup(fd);
     104           0 :                         if (fd == -1) {
     105           0 :                                 sys_errno = errno;
     106           0 :                                 break;
     107             :                         }
     108             :                 }
     109        7370 :                 for (i=0; i<num_fds; i++) {
     110           0 :                         close(fds[i]);
     111             :                 }
     112        7370 :                 if (fd == -1) {
     113           0 :                         errno = sys_errno;
     114           0 :                         return fd;
     115             :                 }
     116             :         }
     117             : 
     118        7370 :         result = set_blocking(fd, false);
     119        7370 :         if (result == -1) {
     120           0 :                 goto fail;
     121             :         }
     122             : 
     123        7370 :         ok = smb_set_close_on_exec(fd);
     124        7370 :         if (!ok) {
     125           0 :                 goto fail;
     126             :         }
     127             : 
     128        7370 :         return fd;
     129             : 
     130           0 :  fail:
     131           0 :         if (fd != -1) {
     132           0 :                 sys_errno = errno;
     133           0 :                 close(fd);
     134           0 :                 errno = sys_errno;
     135             :         }
     136           0 :         return -1;
     137             : }
     138             : 
     139             : #ifdef HAVE_LINUX_RTNETLINK_H
     140             : /**
     141             :  * Get the amount of pending bytes from a netlink socket
     142             :  *
     143             :  * For some reason netlink sockets don't support querying the amount of pending
     144             :  * data via ioctl with FIONREAD, which is what we use in tsocket_bsd_pending()
     145             :  * below.
     146             :  *
     147             :  * We know we are on Linux as we're using netlink, which means we have a working
     148             :  * MSG_TRUNC flag to recvmsg() as well, so we use that together with MSG_PEEK.
     149             :  **/
     150           0 : static ssize_t tsocket_bsd_netlink_pending(int fd)
     151             : {
     152             :         struct iovec iov;
     153             :         struct msghdr msg;
     154             :         char buf[1];
     155             : 
     156           0 :         iov = (struct iovec) {
     157             :                 .iov_base = buf,
     158             :                 .iov_len = sizeof(buf)
     159             :         };
     160             : 
     161           0 :         msg = (struct msghdr) {
     162             :                 .msg_iov = &iov,
     163             :                 .msg_iovlen = 1
     164             :         };
     165             : 
     166           0 :         return recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC);
     167             : }
     168             : #else
     169             : static ssize_t tsocket_bsd_netlink_pending(int fd)
     170             : {
     171             :         errno = ENOSYS;
     172             :         return -1;
     173             : }
     174             : #endif
     175             : 
     176        1684 : static int tsocket_bsd_poll_error(int fd)
     177             : {
     178        1684 :         struct pollfd pfd = {
     179             :                 .fd = fd,
     180             : #ifdef POLLRDHUP
     181             :                 .events = POLLRDHUP, /* POLLERR and POLLHUP are not needed */
     182             : #endif
     183             :         };
     184             :         int ret;
     185             : 
     186        1684 :         errno = 0;
     187        1684 :         ret = sys_poll_intr(&pfd, 1, 0);
     188        1684 :         if (ret == 0) {
     189        1684 :                 return 0;
     190             :         }
     191           0 :         if (ret != 1) {
     192           0 :                 return POLLNVAL;
     193             :         }
     194             : 
     195           0 :         if (pfd.revents & POLLERR) {
     196           0 :                 return POLLERR;
     197             :         }
     198           0 :         if (pfd.revents & POLLHUP) {
     199           0 :                 return POLLHUP;
     200             :         }
     201             : #ifdef POLLRDHUP
     202           0 :         if (pfd.revents & POLLRDHUP) {
     203           0 :                 return POLLRDHUP;
     204             :         }
     205             : #endif
     206             : 
     207             :         /* should never be reached! */
     208           0 :         return POLLNVAL;
     209             : }
     210             : 
     211           0 : static int tsocket_bsd_sock_error(int fd)
     212             : {
     213           0 :         int ret, error = 0;
     214           0 :         socklen_t len = sizeof(error);
     215             : 
     216             :         /*
     217             :          * if no data is available check if the socket is in error state. For
     218             :          * dgram sockets it's the way to return ICMP error messages of
     219             :          * connected sockets to the caller.
     220             :          */
     221           0 :         ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
     222           0 :         if (ret == -1) {
     223           0 :                 return ret;
     224             :         }
     225           0 :         if (error != 0) {
     226           0 :                 errno = error;
     227           0 :                 return -1;
     228             :         }
     229           0 :         return 0;
     230             : }
     231             : 
     232        1684 : static int tsocket_bsd_error(int fd)
     233             : {
     234             :         int ret;
     235        1684 :         int poll_error = 0;
     236             : 
     237        1684 :         poll_error = tsocket_bsd_poll_error(fd);
     238        1684 :         if (poll_error == 0) {
     239        1684 :                 return 0;
     240             :         }
     241             : 
     242             : #ifdef POLLRDHUP
     243           0 :         if (poll_error == POLLRDHUP) {
     244           0 :                 errno = ECONNRESET;
     245           0 :                 return -1;
     246             :         }
     247             : #endif
     248             : 
     249           0 :         if (poll_error == POLLHUP) {
     250           0 :                 errno = EPIPE;
     251           0 :                 return -1;
     252             :         }
     253             : 
     254             :         /*
     255             :          * POLLERR and POLLNVAL fallback to
     256             :          * getsockopt(fd, SOL_SOCKET, SO_ERROR)
     257             :          * and force EPIPE as fallback.
     258             :          */
     259             : 
     260           0 :         errno = 0;
     261           0 :         ret = tsocket_bsd_sock_error(fd);
     262           0 :         if (ret == 0) {
     263           0 :                 errno = EPIPE;
     264             :         }
     265             : 
     266           0 :         if (errno == 0) {
     267           0 :                 errno = EPIPE;
     268             :         }
     269             : 
     270           0 :         return -1;
     271             : }
     272             : 
     273       54237 : static ssize_t tsocket_bsd_pending(int fd)
     274             : {
     275             :         int ret;
     276       54237 :         int value = 0;
     277             : 
     278       54237 :         ret = ioctl(fd, FIONREAD, &value);
     279       54237 :         if (ret == -1) {
     280           0 :                 return ret;
     281             :         }
     282             : 
     283       54237 :         if (ret != 0) {
     284             :                 /* this should not be reached */
     285           0 :                 errno = EIO;
     286           0 :                 return -1;
     287             :         }
     288             : 
     289       54237 :         if (value != 0) {
     290       52553 :                 return value;
     291             :         }
     292             : 
     293        1684 :         return tsocket_bsd_error(fd);
     294             : }
     295             : 
     296             : static const struct tsocket_address_ops tsocket_address_bsd_ops;
     297             : 
     298      392901 : int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
     299             :                                        const struct sockaddr *sa,
     300             :                                        size_t sa_socklen,
     301             :                                        struct tsocket_address **_addr,
     302             :                                        const char *location)
     303             : {
     304             :         struct tsocket_address *addr;
     305      392901 :         struct samba_sockaddr *bsda = NULL;
     306             : 
     307      392901 :         if (sa_socklen < sizeof(sa->sa_family)) {
     308           0 :                 errno = EINVAL;
     309           0 :                 return -1;
     310             :         }
     311             : 
     312      392901 :         switch (sa->sa_family) {
     313       20859 :         case AF_UNIX:
     314       20859 :                 if (sa_socklen > sizeof(struct sockaddr_un)) {
     315           0 :                         sa_socklen = sizeof(struct sockaddr_un);
     316             :                 }
     317       20859 :                 break;
     318      344826 :         case AF_INET:
     319      344826 :                 if (sa_socklen < sizeof(struct sockaddr_in)) {
     320           0 :                         errno = EINVAL;
     321           0 :                         return -1;
     322             :                 }
     323      344826 :                 sa_socklen = sizeof(struct sockaddr_in);
     324      344826 :                 break;
     325             : #ifdef HAVE_IPV6
     326       27216 :         case AF_INET6:
     327       27216 :                 if (sa_socklen < sizeof(struct sockaddr_in6)) {
     328           0 :                         errno = EINVAL;
     329           0 :                         return -1;
     330             :                 }
     331       27216 :                 sa_socklen = sizeof(struct sockaddr_in6);
     332       27216 :                 break;
     333             : #endif
     334           0 :         default:
     335           0 :                 errno = EAFNOSUPPORT;
     336           0 :                 return -1;
     337             :         }
     338             : 
     339      392901 :         if (sa_socklen > sizeof(struct sockaddr_storage)) {
     340           0 :                 errno = EINVAL;
     341           0 :                 return -1;
     342             :         }
     343             : 
     344      392901 :         addr = tsocket_address_create(mem_ctx,
     345             :                                       &tsocket_address_bsd_ops,
     346             :                                       &bsda,
     347             :                                       struct samba_sockaddr,
     348             :                                       location);
     349      392901 :         if (!addr) {
     350           0 :                 errno = ENOMEM;
     351           0 :                 return -1;
     352             :         }
     353             : 
     354      392901 :         ZERO_STRUCTP(bsda);
     355             : 
     356      392901 :         memcpy(&bsda->u.ss, sa, sa_socklen);
     357             : 
     358      392901 :         bsda->sa_socklen = sa_socklen;
     359             : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
     360             :         bsda->u.sa.sa_len = bsda->sa_socklen;
     361             : #endif
     362             : 
     363      392901 :         *_addr = addr;
     364      392901 :         return 0;
     365             : }
     366             : 
     367         808 : int _tsocket_address_bsd_from_samba_sockaddr(TALLOC_CTX *mem_ctx,
     368             :                                          const struct samba_sockaddr *xs_addr,
     369             :                                          struct tsocket_address **t_addr,
     370             :                                          const char *location)
     371             : {
     372        1210 :         return _tsocket_address_bsd_from_sockaddr(mem_ctx,
     373             :                                                   &xs_addr->u.sa,
     374         808 :                                                   xs_addr->sa_socklen,
     375             :                                                   t_addr,
     376             :                                                   location);
     377             : }
     378             : 
     379       76583 : ssize_t tsocket_address_bsd_sockaddr(const struct tsocket_address *addr,
     380             :                                      struct sockaddr *sa,
     381             :                                      size_t sa_socklen)
     382             : {
     383       76583 :         struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
     384             :                                            struct samba_sockaddr);
     385             : 
     386       76583 :         if (!bsda) {
     387           0 :                 errno = EINVAL;
     388           0 :                 return -1;
     389             :         }
     390             : 
     391       76583 :         if (sa_socklen < bsda->sa_socklen) {
     392           0 :                 errno = EINVAL;
     393           0 :                 return -1;
     394             :         }
     395             : 
     396       76583 :         if (sa_socklen > bsda->sa_socklen) {
     397       76433 :                 memset(sa, 0, sa_socklen);
     398       76433 :                 sa_socklen = bsda->sa_socklen;
     399             :         }
     400             : 
     401       76583 :         memcpy(sa, &bsda->u.ss, sa_socklen);
     402             : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
     403             :         sa->sa_len = sa_socklen;
     404             : #endif
     405       76583 :         return sa_socklen;
     406             : }
     407             : 
     408       28372 : bool tsocket_address_is_inet(const struct tsocket_address *addr, const char *fam)
     409             : {
     410       28372 :         struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
     411             :                                            struct samba_sockaddr);
     412             : 
     413       28372 :         if (!bsda) {
     414           0 :                 return false;
     415             :         }
     416             : 
     417       28372 :         switch (bsda->u.sa.sa_family) {
     418       27576 :         case AF_INET:
     419       27576 :                 if (strcasecmp(fam, "ip") == 0) {
     420       25419 :                         return true;
     421             :                 }
     422             : 
     423        2157 :                 if (strcasecmp(fam, "ipv4") == 0) {
     424        1493 :                         return true;
     425             :                 }
     426             : 
     427         664 :                 return false;
     428             : #ifdef HAVE_IPV6
     429         528 :         case AF_INET6:
     430         528 :                 if (strcasecmp(fam, "ip") == 0) {
     431         312 :                         return true;
     432             :                 }
     433             : 
     434         216 :                 if (strcasecmp(fam, "ipv6") == 0) {
     435         108 :                         return true;
     436             :                 }
     437             : 
     438         108 :                 return false;
     439             : #endif
     440             :         }
     441             : 
     442         268 :         return false;
     443             : }
     444             : 
     445       43786 : int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
     446             :                                        const char *fam,
     447             :                                        const char *addr,
     448             :                                        uint16_t port,
     449             :                                        struct tsocket_address **_addr,
     450             :                                        const char *location)
     451             : {
     452             :         struct addrinfo hints;
     453       43786 :         struct addrinfo *result = NULL;
     454             :         char port_str[6];
     455             :         int ret;
     456             : 
     457       43786 :         ZERO_STRUCT(hints);
     458             :         /*
     459             :          * we use SOCKET_STREAM here to get just one result
     460             :          * back from getaddrinfo().
     461             :          */
     462       43786 :         hints.ai_socktype = SOCK_STREAM;
     463       43786 :         hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
     464             : 
     465       43786 :         if (strcasecmp(fam, "ip") == 0) {
     466       30256 :                 hints.ai_family = AF_UNSPEC;
     467       30256 :                 if (!addr) {
     468             : #ifdef HAVE_IPV6
     469        3375 :                         addr = "::";
     470             : #else
     471             :                         addr = "0.0.0.0";
     472             : #endif
     473             :                 }
     474       13530 :         } else if (strcasecmp(fam, "ipv4") == 0) {
     475        2025 :                 hints.ai_family = AF_INET;
     476        2025 :                 if (!addr) {
     477         664 :                         addr = "0.0.0.0";
     478             :                 }
     479             : #ifdef HAVE_IPV6
     480       11505 :         } else if (strcasecmp(fam, "ipv6") == 0) {
     481       11505 :                 hints.ai_family = AF_INET6;
     482       11505 :                 if (!addr) {
     483         108 :                         addr = "::";
     484             :                 }
     485             : #endif
     486             :         } else {
     487           0 :                 errno = EAFNOSUPPORT;
     488           0 :                 return -1;
     489             :         }
     490             : 
     491       43786 :         snprintf(port_str, sizeof(port_str), "%u", port);
     492             : 
     493       43786 :         ret = getaddrinfo(addr, port_str, &hints, &result);
     494       43786 :         if (ret != 0) {
     495           0 :                 switch (ret) {
     496           0 :                 case EAI_FAIL:
     497             :                 case EAI_NONAME:
     498             : #ifdef EAI_ADDRFAMILY
     499             :                 case EAI_ADDRFAMILY:
     500             : #endif
     501           0 :                         errno = EINVAL;
     502           0 :                         break;
     503             :                 }
     504           0 :                 ret = -1;
     505           0 :                 goto done;
     506             :         }
     507             : 
     508       43786 :         if (result->ai_socktype != SOCK_STREAM) {
     509           0 :                 errno = EINVAL;
     510           0 :                 ret = -1;
     511           0 :                 goto done;
     512             :         }
     513             : 
     514       82211 :         ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
     515       43786 :                                                   result->ai_addr,
     516       43786 :                                                   result->ai_addrlen,
     517             :                                                   _addr,
     518             :                                                   location);
     519             : 
     520       43786 : done:
     521       43786 :         if (result) {
     522       43786 :                 freeaddrinfo(result);
     523             :         }
     524       43786 :         return ret;
     525             : }
     526             : 
     527         237 : int _tsocket_address_inet_from_hostport_strings(TALLOC_CTX *mem_ctx,
     528             :                                                 const char *fam,
     529             :                                                 const char *host_port_addr,
     530             :                                                 uint16_t default_port,
     531             :                                                 struct tsocket_address **_addr,
     532             :                                                 const char *location)
     533             : {
     534         237 :         char *pl_sq = NULL;
     535         237 :         char *pr_sq = NULL;
     536         237 :         char *pl_period = NULL;
     537         237 :         char *port_sep = NULL;
     538         237 :         char *cport = NULL;
     539         237 :         char *buf = NULL;
     540         237 :         uint64_t port = 0;
     541             :         int ret;
     542         237 :         char *s_addr = NULL;
     543         237 :         uint16_t s_port = default_port;
     544             :         bool conv_ret;
     545         237 :         bool is_ipv6_by_squares = false;
     546             : 
     547         237 :         if (host_port_addr == NULL) {
     548             :                 /* got straight to next function if host_port_addr is NULL */
     549           0 :                 goto get_addr;
     550             :         }
     551         237 :         buf = talloc_strdup(mem_ctx, host_port_addr);
     552         237 :         if (buf == NULL) {
     553           0 :                 errno = ENOMEM;
     554           0 :                 return -1;
     555             :         }
     556         237 :         pl_period = strchr_m(buf, '.');
     557         237 :         port_sep = strrchr_m(buf, ':');
     558         237 :         pl_sq = strchr_m(buf, '[');
     559         237 :         pr_sq = strrchr_m(buf, ']');
     560             :         /* See if its IPv4 or IPv6 */
     561             :         /* Only parse IPv6 with squares with/without port, and IPv4 with port */
     562             :         /* Everything else, let tsocket_address_inet_from string() */
     563             :         /* find parsing errors */
     564             : #ifdef HAVE_IPV6
     565         237 :         is_ipv6_by_squares = (pl_sq != NULL && pr_sq != NULL && pr_sq > pl_sq);
     566             : #endif
     567         237 :         if (is_ipv6_by_squares) {
     568             :                 /* IPv6 possibly with port - squares detected */
     569          14 :                 port_sep = pr_sq + 1;
     570          14 :                 if (*port_sep == '\0') {
     571           0 :                         s_addr = pl_sq + 1;
     572           0 :                         *pr_sq = 0;
     573           0 :                         s_port = default_port;
     574           0 :                         goto get_addr;
     575             :                 }
     576          14 :                 if (*port_sep != ':') {
     577           0 :                         errno = EINVAL;
     578           0 :                         return -1;
     579             :                 }
     580          14 :                 cport = port_sep + 1;
     581          14 :                 conv_ret = conv_str_u64(cport, &port);
     582          14 :                 if (!conv_ret) {
     583           0 :                         errno = EINVAL;
     584           0 :                         return -1;
     585             :                 }
     586          14 :                 if (port > 65535) {
     587           0 :                         errno = EINVAL;
     588           0 :                         return -1;
     589             :                 }
     590          14 :                 s_port = (uint16_t)port;
     591          14 :                 *port_sep = 0;
     592          14 :                 *pr_sq = 0;
     593          14 :                 s_addr = pl_sq + 1;
     594          14 :                 *pl_sq = 0;
     595          14 :                 goto get_addr;
     596         223 :         } else if (pl_period != NULL && port_sep != NULL) {
     597             :                 /* IPv4 with port - more than one period in string */
     598           0 :                 cport = port_sep + 1;
     599           0 :                 conv_ret = conv_str_u64(cport, &port);
     600           0 :                 if (!conv_ret) {
     601           0 :                         errno = EINVAL;
     602           0 :                         return -1;
     603             :                 }
     604           0 :                 if (port > 65535) {
     605           0 :                         errno = EINVAL;
     606           0 :                         return -1;
     607             :                 }
     608           0 :                 s_port = (uint16_t)port;
     609           0 :                 *port_sep = 0;
     610           0 :                 s_addr = buf;
     611           0 :                 goto get_addr;
     612             :         } else {
     613             :                 /* Everything else, let tsocket_address_inet_from string() */
     614             :                 /* find parsing errors */
     615         223 :                 s_addr = buf;
     616         223 :                 s_port = default_port;
     617         223 :                 goto get_addr;
     618             :         }
     619         237 : get_addr:
     620         237 :         ret = _tsocket_address_inet_from_strings(
     621             :             mem_ctx, fam, s_addr, s_port, _addr, location);
     622             : 
     623         237 :         return ret;
     624             : }
     625             : 
     626      531945 : char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
     627             :                                        TALLOC_CTX *mem_ctx)
     628             : {
     629      531945 :         struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
     630             :                                            struct samba_sockaddr);
     631             :         char addr_str[INET6_ADDRSTRLEN+1];
     632             :         const char *str;
     633             : 
     634      531945 :         if (!bsda) {
     635           0 :                 errno = EINVAL;
     636           0 :                 return NULL;
     637             :         }
     638             : 
     639      531945 :         switch (bsda->u.sa.sa_family) {
     640      508681 :         case AF_INET:
     641      508681 :                 str = inet_ntop(bsda->u.in.sin_family,
     642      508681 :                                 &bsda->u.in.sin_addr,
     643             :                                 addr_str, sizeof(addr_str));
     644      508681 :                 break;
     645             : #ifdef HAVE_IPV6
     646       23264 :         case AF_INET6:
     647       23264 :                 str = inet_ntop(bsda->u.in6.sin6_family,
     648       23264 :                                 &bsda->u.in6.sin6_addr,
     649             :                                 addr_str, sizeof(addr_str));
     650       23264 :                 break;
     651             : #endif
     652           0 :         default:
     653           0 :                 errno = EINVAL;
     654           0 :                 return NULL;
     655             :         }
     656             : 
     657      531945 :         if (!str) {
     658           0 :                 return NULL;
     659             :         }
     660             : 
     661      531945 :         return talloc_strdup(mem_ctx, str);
     662             : }
     663             : 
     664      490565 : uint16_t tsocket_address_inet_port(const struct tsocket_address *addr)
     665             : {
     666      490565 :         struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
     667             :                                            struct samba_sockaddr);
     668      490565 :         uint16_t port = 0;
     669             : 
     670      490565 :         if (!bsda) {
     671           0 :                 errno = EINVAL;
     672           0 :                 return 0;
     673             :         }
     674             : 
     675      490565 :         switch (bsda->u.sa.sa_family) {
     676      479073 :         case AF_INET:
     677      479073 :                 port = ntohs(bsda->u.in.sin_port);
     678      479073 :                 break;
     679             : #ifdef HAVE_IPV6
     680       11492 :         case AF_INET6:
     681       11492 :                 port = ntohs(bsda->u.in6.sin6_port);
     682       11492 :                 break;
     683             : #endif
     684           0 :         default:
     685           0 :                 errno = EINVAL;
     686           0 :                 return 0;
     687             :         }
     688             : 
     689      490565 :         return port;
     690             : }
     691             : 
     692           0 : int tsocket_address_inet_set_port(struct tsocket_address *addr,
     693             :                                   uint16_t port)
     694             : {
     695           0 :         struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
     696             :                                            struct samba_sockaddr);
     697             : 
     698           0 :         if (!bsda) {
     699           0 :                 errno = EINVAL;
     700           0 :                 return -1;
     701             :         }
     702             : 
     703           0 :         switch (bsda->u.sa.sa_family) {
     704           0 :         case AF_INET:
     705           0 :                 bsda->u.in.sin_port = htons(port);
     706           0 :                 break;
     707             : #ifdef HAVE_IPV6
     708           0 :         case AF_INET6:
     709           0 :                 bsda->u.in6.sin6_port = htons(port);
     710           0 :                 break;
     711             : #endif
     712           0 :         default:
     713           0 :                 errno = EINVAL;
     714           0 :                 return -1;
     715             :         }
     716             : 
     717           0 :         return 0;
     718             : }
     719             : 
     720           0 : bool tsocket_address_is_unix(const struct tsocket_address *addr)
     721             : {
     722           0 :         struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
     723             :                                            struct samba_sockaddr);
     724             : 
     725           0 :         if (!bsda) {
     726           0 :                 return false;
     727             :         }
     728             : 
     729           0 :         switch (bsda->u.sa.sa_family) {
     730           0 :         case AF_UNIX:
     731           0 :                 return true;
     732             :         }
     733             : 
     734           0 :         return false;
     735             : }
     736             : 
     737        4800 : int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
     738             :                                     const char *path,
     739             :                                     struct tsocket_address **_addr,
     740             :                                     const char *location)
     741             : {
     742             :         struct sockaddr_un un;
     743        4800 :         void *p = &un;
     744             :         int ret;
     745             : 
     746        4800 :         if (!path) {
     747         269 :                 path = "";
     748             :         }
     749             : 
     750        4800 :         if (strlen(path) > sizeof(un.sun_path)-1) {
     751           0 :                 errno = ENAMETOOLONG;
     752           0 :                 return -1;
     753             :         }
     754             : 
     755        4800 :         ZERO_STRUCT(un);
     756        4800 :         un.sun_family = AF_UNIX;
     757        4800 :         strncpy(un.sun_path, path, sizeof(un.sun_path)-1);
     758             : 
     759        4800 :         ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
     760             :                                                  (struct sockaddr *)p,
     761             :                                                  sizeof(un),
     762             :                                                  _addr,
     763             :                                                  location);
     764             : 
     765        4800 :         return ret;
     766             : }
     767             : 
     768         431 : char *tsocket_address_unix_path(const struct tsocket_address *addr,
     769             :                                 TALLOC_CTX *mem_ctx)
     770             : {
     771         431 :         struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
     772             :                                            struct samba_sockaddr);
     773             :         const char *str;
     774             : 
     775         431 :         if (!bsda) {
     776           0 :                 errno = EINVAL;
     777           0 :                 return NULL;
     778             :         }
     779             : 
     780         431 :         switch (bsda->u.sa.sa_family) {
     781         431 :         case AF_UNIX:
     782         431 :                 str = bsda->u.un.sun_path;
     783         431 :                 break;
     784           0 :         default:
     785           0 :                 errno = EINVAL;
     786           0 :                 return NULL;
     787             :         }
     788             : 
     789         431 :         return talloc_strdup(mem_ctx, str);
     790             : }
     791             : 
     792      487780 : static char *tsocket_address_bsd_string(const struct tsocket_address *addr,
     793             :                                         TALLOC_CTX *mem_ctx)
     794             : {
     795      487780 :         struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
     796             :                                            struct samba_sockaddr);
     797             :         char *str;
     798             :         char *addr_str;
     799      487780 :         const char *prefix = NULL;
     800             :         uint16_t port;
     801             : 
     802      487780 :         switch (bsda->u.sa.sa_family) {
     803       18465 :         case AF_UNIX:
     804       18465 :                 return talloc_asprintf(mem_ctx, "unix:%s",
     805       18465 :                                        bsda->u.un.sun_path);
     806      458097 :         case AF_INET:
     807      458097 :                 prefix = "ipv4";
     808      458097 :                 break;
     809             : #ifdef HAVE_IPV6
     810       11218 :         case AF_INET6:
     811       11218 :                 prefix = "ipv6";
     812       11218 :                 break;
     813             : #endif
     814           0 :         default:
     815           0 :                 errno = EINVAL;
     816           0 :                 return NULL;
     817             :         }
     818             : 
     819      469315 :         addr_str = tsocket_address_inet_addr_string(addr, mem_ctx);
     820      469315 :         if (!addr_str) {
     821           0 :                 return NULL;
     822             :         }
     823             : 
     824      469315 :         port = tsocket_address_inet_port(addr);
     825             : 
     826      469315 :         str = talloc_asprintf(mem_ctx, "%s:%s:%u",
     827             :                               prefix, addr_str, port);
     828      469315 :         talloc_free(addr_str);
     829             : 
     830      469315 :         return str;
     831             : }
     832             : 
     833      119923 : static struct tsocket_address *tsocket_address_bsd_copy(const struct tsocket_address *addr,
     834             :                                                          TALLOC_CTX *mem_ctx,
     835             :                                                          const char *location)
     836             : {
     837      119923 :         struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
     838             :                                            struct samba_sockaddr);
     839             :         struct tsocket_address *copy;
     840             :         int ret;
     841             : 
     842      211384 :         ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
     843      119923 :                                                  &bsda->u.sa,
     844      119923 :                                                  bsda->sa_socklen,
     845             :                                                  &copy,
     846             :                                                  location);
     847      119923 :         if (ret != 0) {
     848           0 :                 return NULL;
     849             :         }
     850             : 
     851      119923 :         return copy;
     852             : }
     853             : 
     854             : static const struct tsocket_address_ops tsocket_address_bsd_ops = {
     855             :         .name           = "bsd",
     856             :         .string         = tsocket_address_bsd_string,
     857             :         .copy           = tsocket_address_bsd_copy,
     858             : };
     859             : 
     860             : struct tdgram_bsd {
     861             :         int fd;
     862             : 
     863             :         void *event_ptr;
     864             :         struct tevent_fd *fde;
     865             :         bool optimize_recvfrom;
     866             :         bool netlink;
     867             : 
     868             :         void *readable_private;
     869             :         void (*readable_handler)(void *private_data);
     870             :         void *writeable_private;
     871             :         void (*writeable_handler)(void *private_data);
     872             : };
     873             : 
     874           0 : bool tdgram_bsd_optimize_recvfrom(struct tdgram_context *dgram,
     875             :                                   bool on)
     876             : {
     877           0 :         struct tdgram_bsd *bsds =
     878           0 :                 talloc_get_type(_tdgram_context_data(dgram),
     879             :                 struct tdgram_bsd);
     880             :         bool old;
     881             : 
     882           0 :         if (bsds == NULL) {
     883             :                 /* not a bsd socket */
     884           0 :                 return false;
     885             :         }
     886             : 
     887           0 :         old = bsds->optimize_recvfrom;
     888           0 :         bsds->optimize_recvfrom = on;
     889             : 
     890           0 :         return old;
     891             : }
     892             : 
     893       54237 : static void tdgram_bsd_fde_handler(struct tevent_context *ev,
     894             :                                    struct tevent_fd *fde,
     895             :                                    uint16_t flags,
     896             :                                    void *private_data)
     897             : {
     898       54237 :         struct tdgram_bsd *bsds = talloc_get_type_abort(private_data,
     899             :                                   struct tdgram_bsd);
     900             : 
     901       54237 :         if (flags & TEVENT_FD_WRITE) {
     902           0 :                 bsds->writeable_handler(bsds->writeable_private);
     903           0 :                 return;
     904             :         }
     905       54237 :         if (flags & TEVENT_FD_READ) {
     906       54237 :                 if (!bsds->readable_handler) {
     907           0 :                         TEVENT_FD_NOT_READABLE(bsds->fde);
     908           0 :                         return;
     909             :                 }
     910       54237 :                 bsds->readable_handler(bsds->readable_private);
     911       54237 :                 return;
     912             :         }
     913             : }
     914             : 
     915      104188 : static int tdgram_bsd_set_readable_handler(struct tdgram_bsd *bsds,
     916             :                                            struct tevent_context *ev,
     917             :                                            void (*handler)(void *private_data),
     918             :                                            void *private_data)
     919             : {
     920      104188 :         if (ev == NULL) {
     921       52268 :                 if (handler) {
     922           0 :                         errno = EINVAL;
     923           0 :                         return -1;
     924             :                 }
     925       52268 :                 if (!bsds->readable_handler) {
     926           0 :                         return 0;
     927             :                 }
     928       52268 :                 bsds->readable_handler = NULL;
     929       52268 :                 bsds->readable_private = NULL;
     930             : 
     931       52268 :                 return 0;
     932             :         }
     933             : 
     934             :         /* read and write must use the same tevent_context */
     935       51920 :         if (bsds->event_ptr != ev) {
     936        2988 :                 if (bsds->readable_handler || bsds->writeable_handler) {
     937           0 :                         errno = EINVAL;
     938           0 :                         return -1;
     939             :                 }
     940        2988 :                 bsds->event_ptr = NULL;
     941        2988 :                 TALLOC_FREE(bsds->fde);
     942             :         }
     943             : 
     944       51920 :         if (tevent_fd_get_flags(bsds->fde) == 0) {
     945        3291 :                 TALLOC_FREE(bsds->fde);
     946             : 
     947        3291 :                 bsds->fde = tevent_add_fd(ev, bsds,
     948             :                                           bsds->fd, TEVENT_FD_READ,
     949             :                                           tdgram_bsd_fde_handler,
     950             :                                           bsds);
     951        3291 :                 if (!bsds->fde) {
     952           0 :                         errno = ENOMEM;
     953           0 :                         return -1;
     954             :                 }
     955             : 
     956             :                 /* cache the event context we're running on */
     957        3291 :                 bsds->event_ptr = ev;
     958       48629 :         } else if (!bsds->readable_handler) {
     959       48629 :                 TEVENT_FD_READABLE(bsds->fde);
     960             :         }
     961             : 
     962       51920 :         bsds->readable_handler = handler;
     963       51920 :         bsds->readable_private = private_data;
     964             : 
     965       51920 :         return 0;
     966             : }
     967             : 
     968       51148 : static int tdgram_bsd_set_writeable_handler(struct tdgram_bsd *bsds,
     969             :                                             struct tevent_context *ev,
     970             :                                             void (*handler)(void *private_data),
     971             :                                             void *private_data)
     972             : {
     973       51148 :         if (ev == NULL) {
     974       51148 :                 if (handler) {
     975           0 :                         errno = EINVAL;
     976           0 :                         return -1;
     977             :                 }
     978       51148 :                 if (!bsds->writeable_handler) {
     979       51148 :                         return 0;
     980             :                 }
     981           0 :                 bsds->writeable_handler = NULL;
     982           0 :                 bsds->writeable_private = NULL;
     983           0 :                 TEVENT_FD_NOT_WRITEABLE(bsds->fde);
     984             : 
     985           0 :                 return 0;
     986             :         }
     987             : 
     988             :         /* read and write must use the same tevent_context */
     989           0 :         if (bsds->event_ptr != ev) {
     990           0 :                 if (bsds->readable_handler || bsds->writeable_handler) {
     991           0 :                         errno = EINVAL;
     992           0 :                         return -1;
     993             :                 }
     994           0 :                 bsds->event_ptr = NULL;
     995           0 :                 TALLOC_FREE(bsds->fde);
     996             :         }
     997             : 
     998           0 :         if (tevent_fd_get_flags(bsds->fde) == 0) {
     999           0 :                 TALLOC_FREE(bsds->fde);
    1000             : 
    1001           0 :                 bsds->fde = tevent_add_fd(ev, bsds,
    1002             :                                           bsds->fd, TEVENT_FD_WRITE,
    1003             :                                           tdgram_bsd_fde_handler,
    1004             :                                           bsds);
    1005           0 :                 if (!bsds->fde) {
    1006           0 :                         errno = ENOMEM;
    1007           0 :                         return -1;
    1008             :                 }
    1009             : 
    1010             :                 /* cache the event context we're running on */
    1011           0 :                 bsds->event_ptr = ev;
    1012           0 :         } else if (!bsds->writeable_handler) {
    1013           0 :                 TEVENT_FD_WRITEABLE(bsds->fde);
    1014             :         }
    1015             : 
    1016           0 :         bsds->writeable_handler = handler;
    1017           0 :         bsds->writeable_private = private_data;
    1018             : 
    1019           0 :         return 0;
    1020             : }
    1021             : 
    1022             : struct tdgram_bsd_recvfrom_state {
    1023             :         struct tdgram_context *dgram;
    1024             :         bool first_try;
    1025             :         uint8_t *buf;
    1026             :         size_t len;
    1027             :         struct tsocket_address *src;
    1028             : };
    1029             : 
    1030       52268 : static int tdgram_bsd_recvfrom_destructor(struct tdgram_bsd_recvfrom_state *state)
    1031             : {
    1032       52268 :         struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
    1033             :                                   struct tdgram_bsd);
    1034             : 
    1035       52268 :         tdgram_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
    1036             : 
    1037       52268 :         return 0;
    1038             : }
    1039             : 
    1040             : static void tdgram_bsd_recvfrom_handler(void *private_data);
    1041             : 
    1042       51920 : static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx,
    1043             :                                         struct tevent_context *ev,
    1044             :                                         struct tdgram_context *dgram)
    1045             : {
    1046             :         struct tevent_req *req;
    1047             :         struct tdgram_bsd_recvfrom_state *state;
    1048       51920 :         struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
    1049             :         int ret;
    1050             : 
    1051       51920 :         req = tevent_req_create(mem_ctx, &state,
    1052             :                                 struct tdgram_bsd_recvfrom_state);
    1053       51920 :         if (!req) {
    1054           0 :                 return NULL;
    1055             :         }
    1056             : 
    1057       51920 :         state->dgram = dgram;
    1058       51920 :         state->first_try= true;
    1059       51920 :         state->buf   = NULL;
    1060       51920 :         state->len   = 0;
    1061       51920 :         state->src   = NULL;
    1062             : 
    1063       51920 :         talloc_set_destructor(state, tdgram_bsd_recvfrom_destructor);
    1064             : 
    1065       51920 :         if (bsds->fd == -1) {
    1066           0 :                 tevent_req_error(req, ENOTCONN);
    1067           0 :                 goto post;
    1068             :         }
    1069             : 
    1070             : 
    1071             :         /*
    1072             :          * this is a fast path, not waiting for the
    1073             :          * socket to become explicit readable gains
    1074             :          * about 10%-20% performance in benchmark tests.
    1075             :          */
    1076       51920 :         if (bsds->optimize_recvfrom) {
    1077             :                 /*
    1078             :                  * We only do the optimization on
    1079             :                  * recvfrom if the caller asked for it.
    1080             :                  *
    1081             :                  * This is needed because in most cases
    1082             :                  * we prefer to flush send buffers before
    1083             :                  * receiving incoming requests.
    1084             :                  */
    1085           0 :                 tdgram_bsd_recvfrom_handler(req);
    1086           0 :                 if (!tevent_req_is_in_progress(req)) {
    1087           0 :                         goto post;
    1088             :                 }
    1089             :         }
    1090             : 
    1091       51920 :         ret = tdgram_bsd_set_readable_handler(bsds, ev,
    1092             :                                               tdgram_bsd_recvfrom_handler,
    1093             :                                               req);
    1094       51920 :         if (ret == -1) {
    1095           0 :                 tevent_req_error(req, errno);
    1096           0 :                 goto post;
    1097             :         }
    1098             : 
    1099       51920 :         return req;
    1100             : 
    1101           0 :  post:
    1102           0 :         tevent_req_post(req, ev);
    1103           0 :         return req;
    1104             : }
    1105             : 
    1106       54237 : static void tdgram_bsd_recvfrom_handler(void *private_data)
    1107             : {
    1108       54237 :         struct tevent_req *req = talloc_get_type_abort(private_data,
    1109             :                                  struct tevent_req);
    1110       54237 :         struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
    1111             :                                         struct tdgram_bsd_recvfrom_state);
    1112       54237 :         struct tdgram_context *dgram = state->dgram;
    1113       54237 :         struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
    1114       54237 :         struct samba_sockaddr *bsda = NULL;
    1115             :         ssize_t ret;
    1116             :         int err;
    1117             :         bool retry;
    1118             : 
    1119       54237 :         if (bsds->netlink) {
    1120           0 :                 ret = tsocket_bsd_netlink_pending(bsds->fd);
    1121             :         } else {
    1122       54237 :                 ret = tsocket_bsd_pending(bsds->fd);
    1123             :         }
    1124             : 
    1125       54237 :         if (state->first_try && ret == 0) {
    1126         313 :                 state->first_try = false;
    1127             :                 /* retry later */
    1128        3539 :                 return;
    1129             :         }
    1130       53924 :         state->first_try = false;
    1131             : 
    1132       53924 :         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
    1133       53924 :         if (retry) {
    1134             :                 /* retry later */
    1135           0 :                 return;
    1136             :         }
    1137       53924 :         if (tevent_req_error(req, err)) {
    1138           0 :                 return;
    1139             :         }
    1140             : 
    1141             :         /* note that 'ret' can be 0 here */
    1142       53924 :         state->buf = talloc_array(state, uint8_t, ret);
    1143       53924 :         if (tevent_req_nomem(state->buf, req)) {
    1144           0 :                 return;
    1145             :         }
    1146       53924 :         state->len = ret;
    1147             : 
    1148       53924 :         state->src = tsocket_address_create(state,
    1149             :                                             &tsocket_address_bsd_ops,
    1150             :                                             &bsda,
    1151             :                                             struct samba_sockaddr,
    1152             :                                             __location__ "bsd_recvfrom");
    1153       53924 :         if (tevent_req_nomem(state->src, req)) {
    1154           0 :                 return;
    1155             :         }
    1156             : 
    1157       53924 :         ZERO_STRUCTP(bsda);
    1158       53924 :         bsda->sa_socklen = sizeof(bsda->u.ss);
    1159             : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
    1160             :         bsda->u.sa.sa_len = bsda->sa_socklen;
    1161             : #endif
    1162             : 
    1163      106544 :         ret = recvfrom(bsds->fd, state->buf, state->len, 0,
    1164      106544 :                        &bsda->u.sa, &bsda->sa_socklen);
    1165       53924 :         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
    1166       53924 :         if (retry) {
    1167             :                 /* retry later */
    1168        2910 :                 return;
    1169             :         }
    1170       51014 :         if (tevent_req_error(req, err)) {
    1171           0 :                 return;
    1172             :         }
    1173             : 
    1174             :         /*
    1175             :          * Some systems (FreeBSD, see bug #7115) return too much
    1176             :          * bytes in tsocket_bsd_pending()/ioctl(fd, FIONREAD, ...),
    1177             :          * the return value includes some IP/UDP header bytes,
    1178             :          * while recvfrom() just returns the payload.
    1179             :          */
    1180       51014 :         state->buf = talloc_realloc(state, state->buf, uint8_t, ret);
    1181       51014 :         if (tevent_req_nomem(state->buf, req)) {
    1182           4 :                 return;
    1183             :         }
    1184       51010 :         state->len = ret;
    1185             : 
    1186       51010 :         tevent_req_done(req);
    1187             : }
    1188             : 
    1189       51014 : static ssize_t tdgram_bsd_recvfrom_recv(struct tevent_req *req,
    1190             :                                         int *perrno,
    1191             :                                         TALLOC_CTX *mem_ctx,
    1192             :                                         uint8_t **buf,
    1193             :                                         struct tsocket_address **src)
    1194             : {
    1195       51014 :         struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
    1196             :                                         struct tdgram_bsd_recvfrom_state);
    1197             :         ssize_t ret;
    1198             : 
    1199       51014 :         ret = tsocket_simple_int_recv(req, perrno);
    1200       51014 :         if (ret == 0) {
    1201       51010 :                 *buf = talloc_move(mem_ctx, &state->buf);
    1202       51010 :                 ret = state->len;
    1203       51010 :                 if (src) {
    1204       51010 :                         *src = talloc_move(mem_ctx, &state->src);
    1205             :                 }
    1206             :         }
    1207             : 
    1208       51014 :         tevent_req_received(req);
    1209       51014 :         return ret;
    1210             : }
    1211             : 
    1212             : struct tdgram_bsd_sendto_state {
    1213             :         struct tdgram_context *dgram;
    1214             : 
    1215             :         const uint8_t *buf;
    1216             :         size_t len;
    1217             :         const struct tsocket_address *dst;
    1218             : 
    1219             :         ssize_t ret;
    1220             : };
    1221             : 
    1222       51148 : static int tdgram_bsd_sendto_destructor(struct tdgram_bsd_sendto_state *state)
    1223             : {
    1224       51148 :         struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
    1225             :                                   struct tdgram_bsd);
    1226             : 
    1227       51148 :         tdgram_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
    1228             : 
    1229       51148 :         return 0;
    1230             : }
    1231             : 
    1232             : static void tdgram_bsd_sendto_handler(void *private_data);
    1233             : 
    1234       51148 : static struct tevent_req *tdgram_bsd_sendto_send(TALLOC_CTX *mem_ctx,
    1235             :                                                  struct tevent_context *ev,
    1236             :                                                  struct tdgram_context *dgram,
    1237             :                                                  const uint8_t *buf,
    1238             :                                                  size_t len,
    1239             :                                                  const struct tsocket_address *dst)
    1240             : {
    1241             :         struct tevent_req *req;
    1242             :         struct tdgram_bsd_sendto_state *state;
    1243       51148 :         struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
    1244             :         int ret;
    1245             : 
    1246       51148 :         req = tevent_req_create(mem_ctx, &state,
    1247             :                                 struct tdgram_bsd_sendto_state);
    1248       51148 :         if (!req) {
    1249           0 :                 return NULL;
    1250             :         }
    1251             : 
    1252       51148 :         state->dgram = dgram;
    1253       51148 :         state->buf   = buf;
    1254       51148 :         state->len   = len;
    1255       51148 :         state->dst   = dst;
    1256       51148 :         state->ret   = -1;
    1257             : 
    1258       51148 :         talloc_set_destructor(state, tdgram_bsd_sendto_destructor);
    1259             : 
    1260       51148 :         if (bsds->fd == -1) {
    1261           0 :                 tevent_req_error(req, ENOTCONN);
    1262           0 :                 goto post;
    1263             :         }
    1264             : 
    1265             :         /*
    1266             :          * this is a fast path, not waiting for the
    1267             :          * socket to become explicit writeable gains
    1268             :          * about 10%-20% performance in benchmark tests.
    1269             :          */
    1270       51148 :         tdgram_bsd_sendto_handler(req);
    1271       51148 :         if (!tevent_req_is_in_progress(req)) {
    1272       51148 :                 goto post;
    1273             :         }
    1274             : 
    1275           0 :         ret = tdgram_bsd_set_writeable_handler(bsds, ev,
    1276             :                                                tdgram_bsd_sendto_handler,
    1277             :                                                req);
    1278           0 :         if (ret == -1) {
    1279           0 :                 tevent_req_error(req, errno);
    1280           0 :                 goto post;
    1281             :         }
    1282             : 
    1283           0 :         return req;
    1284             : 
    1285       51148 :  post:
    1286       51148 :         tevent_req_post(req, ev);
    1287       51148 :         return req;
    1288             : }
    1289             : 
    1290       51148 : static void tdgram_bsd_sendto_handler(void *private_data)
    1291             : {
    1292       51148 :         struct tevent_req *req = talloc_get_type_abort(private_data,
    1293             :                                  struct tevent_req);
    1294       51148 :         struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
    1295             :                                         struct tdgram_bsd_sendto_state);
    1296       51148 :         struct tdgram_context *dgram = state->dgram;
    1297       51148 :         struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
    1298       51148 :         struct sockaddr *sa = NULL;
    1299       51148 :         socklen_t sa_socklen = 0;
    1300             :         ssize_t ret;
    1301             :         int err;
    1302             :         bool retry;
    1303             : 
    1304       51148 :         if (state->dst) {
    1305       47720 :                 struct samba_sockaddr *bsda =
    1306       48883 :                         talloc_get_type(state->dst->private_data,
    1307             :                         struct samba_sockaddr);
    1308             : 
    1309       48883 :                 sa = &bsda->u.sa;
    1310       48883 :                 sa_socklen = bsda->sa_socklen;
    1311             :         }
    1312             : 
    1313       51148 :         ret = sendto(bsds->fd, state->buf, state->len, 0, sa, sa_socklen);
    1314       51148 :         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
    1315       51148 :         if (retry) {
    1316             :                 /* retry later */
    1317          34 :                 return;
    1318             :         }
    1319             : 
    1320       51148 :         if (err == EMSGSIZE) {
    1321             :                 /* round up in 1K increments */
    1322           0 :                 int bufsize = ((state->len + 1023) & (~1023));
    1323             : 
    1324           0 :                 ret = setsockopt(bsds->fd, SOL_SOCKET, SO_SNDBUF, &bufsize,
    1325             :                                  sizeof(bufsize));
    1326           0 :                 if (ret == 0) {
    1327             :                         /*
    1328             :                          * We do the retry here, rather then via the
    1329             :                          * handler, as we only want to retry once for
    1330             :                          * this condition, so if there is a mismatch
    1331             :                          * between what setsockopt() accepts and what can
    1332             :                          * actually be sent, we do not end up in a
    1333             :                          * loop.
    1334             :                          */
    1335             : 
    1336           0 :                         ret = sendto(bsds->fd, state->buf, state->len,
    1337             :                                      0, sa, sa_socklen);
    1338           0 :                         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
    1339           0 :                         if (retry) { /* retry later */
    1340           0 :                                 return;
    1341             :                         }
    1342             :                 }
    1343             :         }
    1344             : 
    1345       51148 :         if (tevent_req_error(req, err)) {
    1346          34 :                 return;
    1347             :         }
    1348             : 
    1349       51114 :         state->ret = ret;
    1350             : 
    1351       51114 :         tevent_req_done(req);
    1352             : }
    1353             : 
    1354       51148 : static ssize_t tdgram_bsd_sendto_recv(struct tevent_req *req, int *perrno)
    1355             : {
    1356       51148 :         struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
    1357             :                                         struct tdgram_bsd_sendto_state);
    1358             :         ssize_t ret;
    1359             : 
    1360       51148 :         ret = tsocket_simple_int_recv(req, perrno);
    1361       51148 :         if (ret == 0) {
    1362       51114 :                 ret = state->ret;
    1363             :         }
    1364             : 
    1365       51148 :         tevent_req_received(req);
    1366       51148 :         return ret;
    1367             : }
    1368             : 
    1369             : struct tdgram_bsd_disconnect_state {
    1370             :         uint8_t __dummy;
    1371             : };
    1372             : 
    1373           0 : static struct tevent_req *tdgram_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
    1374             :                                                      struct tevent_context *ev,
    1375             :                                                      struct tdgram_context *dgram)
    1376             : {
    1377           0 :         struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
    1378             :         struct tevent_req *req;
    1379             :         struct tdgram_bsd_disconnect_state *state;
    1380             :         int ret;
    1381             :         int err;
    1382             :         bool dummy;
    1383             : 
    1384           0 :         req = tevent_req_create(mem_ctx, &state,
    1385             :                                 struct tdgram_bsd_disconnect_state);
    1386           0 :         if (req == NULL) {
    1387           0 :                 return NULL;
    1388             :         }
    1389             : 
    1390           0 :         if (bsds->fd == -1) {
    1391           0 :                 tevent_req_error(req, ENOTCONN);
    1392           0 :                 goto post;
    1393             :         }
    1394             : 
    1395           0 :         TALLOC_FREE(bsds->fde);
    1396           0 :         ret = close(bsds->fd);
    1397           0 :         bsds->fd = -1;
    1398           0 :         err = tsocket_bsd_error_from_errno(ret, errno, &dummy);
    1399           0 :         if (tevent_req_error(req, err)) {
    1400           0 :                 goto post;
    1401             :         }
    1402             : 
    1403           0 :         tevent_req_done(req);
    1404           0 : post:
    1405           0 :         tevent_req_post(req, ev);
    1406           0 :         return req;
    1407             : }
    1408             : 
    1409           0 : static int tdgram_bsd_disconnect_recv(struct tevent_req *req,
    1410             :                                       int *perrno)
    1411             : {
    1412             :         int ret;
    1413             : 
    1414           0 :         ret = tsocket_simple_int_recv(req, perrno);
    1415             : 
    1416           0 :         tevent_req_received(req);
    1417           0 :         return ret;
    1418             : }
    1419             : 
    1420             : static const struct tdgram_context_ops tdgram_bsd_ops = {
    1421             :         .name                   = "bsd",
    1422             : 
    1423             :         .recvfrom_send          = tdgram_bsd_recvfrom_send,
    1424             :         .recvfrom_recv          = tdgram_bsd_recvfrom_recv,
    1425             : 
    1426             :         .sendto_send            = tdgram_bsd_sendto_send,
    1427             :         .sendto_recv            = tdgram_bsd_sendto_recv,
    1428             : 
    1429             :         .disconnect_send        = tdgram_bsd_disconnect_send,
    1430             :         .disconnect_recv        = tdgram_bsd_disconnect_recv,
    1431             : };
    1432             : 
    1433        3333 : static int tdgram_bsd_destructor(struct tdgram_bsd *bsds)
    1434             : {
    1435        3333 :         TALLOC_FREE(bsds->fde);
    1436        3333 :         if (bsds->fd != -1) {
    1437        3333 :                 close(bsds->fd);
    1438        3333 :                 bsds->fd = -1;
    1439             :         }
    1440        3333 :         return 0;
    1441             : }
    1442             : 
    1443        2917 : static int tdgram_bsd_dgram_socket(const struct tsocket_address *local,
    1444             :                                    const struct tsocket_address *remote,
    1445             :                                    bool broadcast,
    1446             :                                    TALLOC_CTX *mem_ctx,
    1447             :                                    struct tdgram_context **_dgram,
    1448             :                                    const char *location)
    1449             : {
    1450        2502 :         struct samba_sockaddr *lbsda =
    1451        2917 :                 talloc_get_type_abort(local->private_data,
    1452             :                 struct samba_sockaddr);
    1453        2917 :         struct samba_sockaddr *rbsda = NULL;
    1454             :         struct tdgram_context *dgram;
    1455             :         struct tdgram_bsd *bsds;
    1456             :         int fd;
    1457             :         int ret;
    1458        2917 :         bool do_bind = false;
    1459        2917 :         bool do_reuseaddr = false;
    1460        2917 :         bool do_ipv6only = false;
    1461        2917 :         bool is_inet = false;
    1462        2917 :         int sa_fam = lbsda->u.sa.sa_family;
    1463             : 
    1464        2917 :         if (remote) {
    1465        1949 :                 rbsda = talloc_get_type_abort(remote->private_data,
    1466             :                         struct samba_sockaddr);
    1467             :         }
    1468             : 
    1469        2917 :         switch (lbsda->u.sa.sa_family) {
    1470           0 :         case AF_UNIX:
    1471           0 :                 if (broadcast) {
    1472           0 :                         errno = EINVAL;
    1473           0 :                         return -1;
    1474             :                 }
    1475           0 :                 if (lbsda->u.un.sun_path[0] != 0) {
    1476           0 :                         do_reuseaddr = true;
    1477           0 :                         do_bind = true;
    1478             :                 }
    1479           0 :                 break;
    1480        1288 :         case AF_INET:
    1481        1288 :                 if (lbsda->u.in.sin_port != 0) {
    1482         356 :                         do_reuseaddr = true;
    1483         356 :                         do_bind = true;
    1484             :                 }
    1485        1288 :                 if (lbsda->u.in.sin_addr.s_addr != INADDR_ANY) {
    1486         180 :                         do_bind = true;
    1487             :                 }
    1488        1288 :                 is_inet = true;
    1489        1288 :                 break;
    1490             : #ifdef HAVE_IPV6
    1491        1629 :         case AF_INET6:
    1492        1629 :                 if (lbsda->u.in6.sin6_port != 0) {
    1493         344 :                         do_reuseaddr = true;
    1494         344 :                         do_bind = true;
    1495             :                 }
    1496        1629 :                 if (memcmp(&in6addr_any,
    1497        1629 :                            &lbsda->u.in6.sin6_addr,
    1498             :                            sizeof(in6addr_any)) != 0) {
    1499         168 :                         do_bind = true;
    1500             :                 }
    1501        1629 :                 is_inet = true;
    1502        1629 :                 do_ipv6only = true;
    1503        1629 :                 break;
    1504             : #endif
    1505           0 :         default:
    1506           0 :                 errno = EINVAL;
    1507           0 :                 return -1;
    1508             :         }
    1509             : 
    1510        2917 :         if (!do_bind && is_inet && rbsda) {
    1511        1949 :                 sa_fam = rbsda->u.sa.sa_family;
    1512        1949 :                 switch (sa_fam) {
    1513         888 :                 case AF_INET:
    1514         888 :                         do_ipv6only = false;
    1515         888 :                         break;
    1516             : #ifdef HAVE_IPV6
    1517        1061 :                 case AF_INET6:
    1518        1061 :                         do_ipv6only = true;
    1519        1061 :                         break;
    1520             : #endif
    1521             :                 }
    1522             :         }
    1523             : 
    1524        2917 :         fd = socket(sa_fam, SOCK_DGRAM, 0);
    1525        2917 :         if (fd < 0) {
    1526           0 :                 return -1;
    1527             :         }
    1528             : 
    1529        2917 :         fd = tsocket_bsd_common_prepare_fd(fd, true);
    1530        2917 :         if (fd < 0) {
    1531           0 :                 return -1;
    1532             :         }
    1533             : 
    1534        2917 :         dgram = tdgram_context_create(mem_ctx,
    1535             :                                       &tdgram_bsd_ops,
    1536             :                                       &bsds,
    1537             :                                       struct tdgram_bsd,
    1538             :                                       location);
    1539        2917 :         if (!dgram) {
    1540           0 :                 int saved_errno = errno;
    1541           0 :                 close(fd);
    1542           0 :                 errno = saved_errno;
    1543           0 :                 return -1;
    1544             :         }
    1545        2917 :         ZERO_STRUCTP(bsds);
    1546        2917 :         bsds->fd = fd;
    1547        2917 :         talloc_set_destructor(bsds, tdgram_bsd_destructor);
    1548             : 
    1549             : #ifdef HAVE_IPV6
    1550        2917 :         if (do_ipv6only) {
    1551        1405 :                 int val = 1;
    1552             : 
    1553        1405 :                 ret = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
    1554             :                                  (const void *)&val, sizeof(val));
    1555        1405 :                 if (ret == -1) {
    1556           0 :                         int saved_errno = errno;
    1557           0 :                         talloc_free(dgram);
    1558           0 :                         errno = saved_errno;
    1559           0 :                         return -1;
    1560             :                 }
    1561             :         }
    1562             : #endif
    1563             : 
    1564        2917 :         if (broadcast) {
    1565         268 :                 int val = 1;
    1566             : 
    1567         268 :                 ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
    1568             :                                  (const void *)&val, sizeof(val));
    1569         268 :                 if (ret == -1) {
    1570           0 :                         int saved_errno = errno;
    1571           0 :                         talloc_free(dgram);
    1572           0 :                         errno = saved_errno;
    1573           0 :                         return -1;
    1574             :                 }
    1575             :         }
    1576             : 
    1577        2917 :         if (do_reuseaddr) {
    1578         700 :                 int val = 1;
    1579             : 
    1580         700 :                 ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
    1581             :                                  (const void *)&val, sizeof(val));
    1582         700 :                 if (ret == -1) {
    1583           0 :                         int saved_errno = errno;
    1584           0 :                         talloc_free(dgram);
    1585           0 :                         errno = saved_errno;
    1586           0 :                         return -1;
    1587             :                 }
    1588             :         }
    1589             : 
    1590        2917 :         if (do_bind) {
    1591         700 :                 ret = bind(fd, &lbsda->u.sa, lbsda->sa_socklen);
    1592         700 :                 if (ret == -1) {
    1593           0 :                         int saved_errno = errno;
    1594           0 :                         talloc_free(dgram);
    1595           0 :                         errno = saved_errno;
    1596           0 :                         return -1;
    1597             :                 }
    1598             :         }
    1599             : 
    1600        2917 :         if (rbsda) {
    1601        1949 :                 if (rbsda->u.sa.sa_family != sa_fam) {
    1602           0 :                         talloc_free(dgram);
    1603           0 :                         errno = EINVAL;
    1604           0 :                         return -1;
    1605             :                 }
    1606             : 
    1607        1949 :                 ret = connect(fd, &rbsda->u.sa, rbsda->sa_socklen);
    1608        1949 :                 if (ret == -1) {
    1609           0 :                         int saved_errno = errno;
    1610           0 :                         talloc_free(dgram);
    1611           0 :                         errno = saved_errno;
    1612           0 :                         return -1;
    1613             :                 }
    1614             :         }
    1615             : 
    1616        2917 :         *_dgram = dgram;
    1617        2917 :         return 0;
    1618             : }
    1619             : 
    1620          68 : int _tdgram_bsd_existing_socket(TALLOC_CTX *mem_ctx,
    1621             :                                 int fd,
    1622             :                                 struct tdgram_context **_dgram,
    1623             :                                 const char *location)
    1624             : {
    1625             :         struct tdgram_context *dgram;
    1626             :         struct tdgram_bsd *bsds;
    1627             : #ifdef HAVE_LINUX_RTNETLINK_H
    1628             :         int result;
    1629             :         struct sockaddr sa;
    1630          68 :         socklen_t sa_len = sizeof(struct sockaddr);
    1631             : #endif
    1632             : 
    1633          68 :         dgram = tdgram_context_create(mem_ctx,
    1634             :                                       &tdgram_bsd_ops,
    1635             :                                       &bsds,
    1636             :                                       struct tdgram_bsd,
    1637             :                                       location);
    1638          68 :         if (!dgram) {
    1639           0 :                 return -1;
    1640             :         }
    1641          68 :         ZERO_STRUCTP(bsds);
    1642          68 :         bsds->fd = fd;
    1643          68 :         talloc_set_destructor(bsds, tdgram_bsd_destructor);
    1644             : 
    1645          68 :         *_dgram = dgram;
    1646             : 
    1647             : #ifdef HAVE_LINUX_RTNETLINK_H
    1648             :         /*
    1649             :          * Try to determine the protocol family and remember if it's
    1650             :          * AF_NETLINK. We don't care if this fails.
    1651             :          */
    1652          68 :         result = getsockname(fd, &sa, &sa_len);
    1653          68 :         if (result == 0 && sa.sa_family == AF_NETLINK) {
    1654          68 :                 bsds->netlink = true;
    1655             :         }
    1656             : #endif
    1657             : 
    1658          68 :         return 0;
    1659             : }
    1660             : 
    1661        2649 : int _tdgram_inet_udp_socket(const struct tsocket_address *local,
    1662             :                             const struct tsocket_address *remote,
    1663             :                             TALLOC_CTX *mem_ctx,
    1664             :                             struct tdgram_context **dgram,
    1665             :                             const char *location)
    1666             : {
    1667        2328 :         struct samba_sockaddr *lbsda =
    1668        2649 :                 talloc_get_type_abort(local->private_data,
    1669             :                 struct samba_sockaddr);
    1670             :         int ret;
    1671             : 
    1672        2649 :         switch (lbsda->u.sa.sa_family) {
    1673        1020 :         case AF_INET:
    1674        1020 :                 break;
    1675             : #ifdef HAVE_IPV6
    1676        1629 :         case AF_INET6:
    1677        1629 :                 break;
    1678             : #endif
    1679           0 :         default:
    1680           0 :                 errno = EINVAL;
    1681           0 :                 return -1;
    1682             :         }
    1683             : 
    1684        2649 :         ret = tdgram_bsd_dgram_socket(local, remote, false,
    1685             :                                       mem_ctx, dgram, location);
    1686             : 
    1687        2649 :         return ret;
    1688             : }
    1689             : 
    1690         268 : int _tdgram_inet_udp_broadcast_socket(const struct tsocket_address *local,
    1691             :                                       TALLOC_CTX *mem_ctx,
    1692             :                                       struct tdgram_context **dgram,
    1693             :                                       const char *location)
    1694             : {
    1695         174 :         struct samba_sockaddr *lbsda =
    1696         268 :                 talloc_get_type_abort(local->private_data,
    1697             :                 struct samba_sockaddr);
    1698             :         int ret;
    1699             : 
    1700         268 :         switch (lbsda->u.sa.sa_family) {
    1701         268 :         case AF_INET:
    1702         268 :                 break;
    1703             : #ifdef HAVE_IPV6
    1704           0 :         case AF_INET6:
    1705             :                 /* only ipv4 */
    1706           0 :                 errno = EINVAL;
    1707           0 :                 return -1;
    1708             : #endif
    1709           0 :         default:
    1710           0 :                 errno = EINVAL;
    1711           0 :                 return -1;
    1712             :         }
    1713             : 
    1714         268 :         ret = tdgram_bsd_dgram_socket(local, NULL, true,
    1715             :                                       mem_ctx, dgram, location);
    1716             : 
    1717         268 :         return ret;
    1718             : }
    1719             : 
    1720           0 : int _tdgram_unix_socket(const struct tsocket_address *local,
    1721             :                         const struct tsocket_address *remote,
    1722             :                         TALLOC_CTX *mem_ctx,
    1723             :                         struct tdgram_context **dgram,
    1724             :                         const char *location)
    1725             : {
    1726           0 :         struct samba_sockaddr *lbsda =
    1727           0 :                 talloc_get_type_abort(local->private_data,
    1728             :                 struct samba_sockaddr);
    1729             :         int ret;
    1730             : 
    1731           0 :         switch (lbsda->u.sa.sa_family) {
    1732           0 :         case AF_UNIX:
    1733           0 :                 break;
    1734           0 :         default:
    1735           0 :                 errno = EINVAL;
    1736           0 :                 return -1;
    1737             :         }
    1738             : 
    1739           0 :         ret = tdgram_bsd_dgram_socket(local, remote, false,
    1740             :                                       mem_ctx, dgram, location);
    1741             : 
    1742           0 :         return ret;
    1743             : }
    1744             : 
    1745             : struct tstream_bsd {
    1746             :         int fd;
    1747             :         int error;
    1748             : 
    1749             :         void *event_ptr;
    1750             :         struct tevent_fd *fde;
    1751             :         bool optimize_readv;
    1752             : 
    1753             :         void *readable_private;
    1754             :         void (*readable_handler)(void *private_data);
    1755             :         void *writeable_private;
    1756             :         void (*writeable_handler)(void *private_data);
    1757             : 
    1758             :         struct tevent_context *error_ctx;
    1759             :         struct tevent_timer *error_timer;
    1760             : };
    1761             : 
    1762     3807892 : bool tstream_bsd_optimize_readv(struct tstream_context *stream,
    1763             :                                 bool on)
    1764             : {
    1765     3065302 :         struct tstream_bsd *bsds =
    1766     3807892 :                 talloc_get_type(_tstream_context_data(stream),
    1767             :                 struct tstream_bsd);
    1768             :         bool old;
    1769             : 
    1770     3807892 :         if (bsds == NULL) {
    1771             :                 /* not a bsd socket */
    1772      783106 :                 return false;
    1773             :         }
    1774             : 
    1775     3024786 :         old = bsds->optimize_readv;
    1776     3024786 :         bsds->optimize_readv = on;
    1777             : 
    1778     3024786 :         return old;
    1779             : }
    1780             : 
    1781           0 : static void tstream_bsd_error_timer(struct tevent_context *ev,
    1782             :                                     struct tevent_timer *te,
    1783             :                                     struct timeval current_time,
    1784             :                                     void *private_data)
    1785             : {
    1786           0 :         struct tstream_bsd *bsds =
    1787           0 :                 talloc_get_type(private_data,
    1788             :                 struct tstream_bsd);
    1789             : 
    1790           0 :         TALLOC_FREE(bsds->error_timer);
    1791             : 
    1792             :         /*
    1793             :          * Turn on TEVENT_FD_READABLE() again
    1794             :          * if we have a writeable_handler that
    1795             :          * wants to monitor the connection
    1796             :          * for errors.
    1797             :          */
    1798           0 :         if (bsds->writeable_handler != NULL) {
    1799           0 :                 TEVENT_FD_READABLE(bsds->fde);
    1800             :         }
    1801           0 : }
    1802             : 
    1803    12924411 : static void tstream_bsd_fde_handler(struct tevent_context *ev,
    1804             :                                     struct tevent_fd *fde,
    1805             :                                     uint16_t flags,
    1806             :                                     void *private_data)
    1807             : {
    1808    12924411 :         struct tstream_bsd *bsds = talloc_get_type_abort(private_data,
    1809             :                                    struct tstream_bsd);
    1810             : 
    1811    12924411 :         if (flags & TEVENT_FD_WRITE) {
    1812     4769435 :                 bsds->writeable_handler(bsds->writeable_private);
    1813     4769435 :                 return;
    1814             :         }
    1815     8154976 :         if (flags & TEVENT_FD_READ) {
    1816     8154976 :                 if (!bsds->readable_handler) {
    1817             :                         struct timeval recheck_time;
    1818             : 
    1819             :                         /*
    1820             :                          * In order to avoid cpu-spinning
    1821             :                          * we no longer want to get TEVENT_FD_READ
    1822             :                          */
    1823        6769 :                         TEVENT_FD_NOT_READABLE(bsds->fde);
    1824             : 
    1825        6769 :                         if (!bsds->writeable_handler) {
    1826        6769 :                                 return;
    1827             :                         }
    1828             : 
    1829             :                         /*
    1830             :                          * If we have a writeable handler we
    1831             :                          * want that to report connection errors
    1832             :                          * early.
    1833             :                          *
    1834             :                          * So we check if the socket is in an
    1835             :                          * error state.
    1836             :                          */
    1837           0 :                         if (bsds->error == 0) {
    1838           0 :                                 int ret = tsocket_bsd_error(bsds->fd);
    1839             : 
    1840           0 :                                 if (ret == -1) {
    1841           0 :                                         bsds->error = errno;
    1842             :                                 }
    1843             :                         }
    1844             : 
    1845           0 :                         if (bsds->error != 0) {
    1846             :                                 /*
    1847             :                                  * Let the writeable handler report the error
    1848             :                                  */
    1849           0 :                                 bsds->writeable_handler(bsds->writeable_private);
    1850           0 :                                 return;
    1851             :                         }
    1852             : 
    1853             :                         /*
    1854             :                          * Here we called TEVENT_FD_NOT_READABLE() without
    1855             :                          * calling into the writeable handler.
    1856             :                          *
    1857             :                          * So we may have to wait for the kernels tcp stack
    1858             :                          * to report TEVENT_FD_WRITE in order to let
    1859             :                          * make progress and turn on TEVENT_FD_READABLE()
    1860             :                          * again.
    1861             :                          *
    1862             :                          * As a fallback we use a timer that turns on
    1863             :                          * TEVENT_FD_READABLE() again after a timeout of
    1864             :                          * 1 second.
    1865             :                          */
    1866             : 
    1867           0 :                         if (bsds->error_timer != NULL) {
    1868           0 :                                 return;
    1869             :                         }
    1870             : 
    1871           0 :                         recheck_time = timeval_current_ofs(1, 0);
    1872           0 :                         bsds->error_timer = tevent_add_timer(bsds->error_ctx,
    1873             :                                                              bsds,
    1874             :                                                              recheck_time,
    1875             :                                                              tstream_bsd_error_timer,
    1876             :                                                              bsds);
    1877           0 :                         if (bsds->error_timer == NULL) {
    1878           0 :                                 bsds->error = ENOMEM;
    1879             :                                 /*
    1880             :                                  * Let the writeable handler report the error
    1881             :                                  */
    1882           0 :                                 bsds->writeable_handler(bsds->writeable_private);
    1883           0 :                                 return;
    1884             :                         }
    1885           0 :                         return;
    1886             :                 }
    1887     8148207 :                 bsds->readable_handler(bsds->readable_private);
    1888     8147906 :                 return;
    1889             :         }
    1890             : }
    1891             : 
    1892    10297550 : static int tstream_bsd_set_readable_handler(struct tstream_bsd *bsds,
    1893             :                                             struct tevent_context *ev,
    1894             :                                             void (*handler)(void *private_data),
    1895             :                                             void *private_data)
    1896             : {
    1897    10297550 :         if (ev == NULL) {
    1898     5765367 :                 if (handler) {
    1899           0 :                         errno = EINVAL;
    1900           0 :                         return -1;
    1901             :                 }
    1902     5765367 :                 if (!bsds->readable_handler) {
    1903     1232025 :                         return 0;
    1904             :                 }
    1905     4533342 :                 bsds->readable_handler = NULL;
    1906     4533342 :                 bsds->readable_private = NULL;
    1907             : 
    1908     4533342 :                 return 0;
    1909             :         }
    1910             : 
    1911             :         /* read and write must use the same tevent_context */
    1912     4532183 :         if (bsds->event_ptr != ev) {
    1913      130267 :                 if (bsds->readable_handler || bsds->writeable_handler) {
    1914           0 :                         errno = EINVAL;
    1915           0 :                         return -1;
    1916             :                 }
    1917      130267 :                 bsds->event_ptr = NULL;
    1918      130267 :                 TALLOC_FREE(bsds->fde);
    1919             :         }
    1920             : 
    1921     4532183 :         if (tevent_fd_get_flags(bsds->fde) == 0) {
    1922      138735 :                 TALLOC_FREE(bsds->fde);
    1923             : 
    1924      138735 :                 bsds->fde = tevent_add_fd(ev, bsds,
    1925             :                                           bsds->fd, TEVENT_FD_READ,
    1926             :                                           tstream_bsd_fde_handler,
    1927             :                                           bsds);
    1928      138735 :                 if (!bsds->fde) {
    1929           0 :                         errno = ENOMEM;
    1930           0 :                         return -1;
    1931             :                 }
    1932             : 
    1933             :                 /* cache the event context we're running on */
    1934      138735 :                 bsds->event_ptr = ev;
    1935     4393448 :         } else if (!bsds->readable_handler) {
    1936     4393448 :                 TEVENT_FD_READABLE(bsds->fde);
    1937             :         }
    1938             : 
    1939     4532183 :         TALLOC_FREE(bsds->error_timer);
    1940             : 
    1941     4532183 :         bsds->readable_handler = handler;
    1942     4532183 :         bsds->readable_private = private_data;
    1943             : 
    1944     4532183 :         return 0;
    1945             : }
    1946             : 
    1947     2047328 : static int tstream_bsd_set_writeable_handler(struct tstream_bsd *bsds,
    1948             :                                              struct tevent_context *ev,
    1949             :                                              void (*handler)(void *private_data),
    1950             :                                              void *private_data)
    1951             : {
    1952     2047328 :         if (ev == NULL) {
    1953     1689818 :                 if (handler) {
    1954           0 :                         errno = EINVAL;
    1955           0 :                         return -1;
    1956             :                 }
    1957     1689818 :                 if (!bsds->writeable_handler) {
    1958     1332308 :                         return 0;
    1959             :                 }
    1960      357510 :                 bsds->writeable_handler = NULL;
    1961      357510 :                 bsds->writeable_private = NULL;
    1962      357510 :                 TEVENT_FD_NOT_WRITEABLE(bsds->fde);
    1963      357510 :                 TALLOC_FREE(bsds->error_timer);
    1964      357510 :                 bsds->error_ctx = NULL;
    1965      357510 :                 return 0;
    1966             :         }
    1967             : 
    1968             :         /* read and write must use the same tevent_context */
    1969      357510 :         if (bsds->event_ptr != ev) {
    1970        4715 :                 if (bsds->readable_handler || bsds->writeable_handler) {
    1971           0 :                         errno = EINVAL;
    1972           0 :                         return -1;
    1973             :                 }
    1974        4715 :                 bsds->event_ptr = NULL;
    1975        4715 :                 TALLOC_FREE(bsds->fde);
    1976        4715 :                 TALLOC_FREE(bsds->error_timer);
    1977        4715 :                 bsds->error_ctx = NULL;
    1978             :         }
    1979             : 
    1980      357510 :         if (tevent_fd_get_flags(bsds->fde) == 0) {
    1981        4715 :                 TALLOC_FREE(bsds->fde);
    1982             : 
    1983        4715 :                 bsds->fde = tevent_add_fd(ev, bsds,
    1984             :                                           bsds->fd,
    1985             :                                           TEVENT_FD_READ | TEVENT_FD_WRITE,
    1986             :                                           tstream_bsd_fde_handler,
    1987             :                                           bsds);
    1988        4715 :                 if (!bsds->fde) {
    1989           0 :                         errno = ENOMEM;
    1990           0 :                         return -1;
    1991             :                 }
    1992             : 
    1993             :                 /* cache the event context we're running on */
    1994        4715 :                 bsds->event_ptr = ev;
    1995      352795 :         } else if (!bsds->writeable_handler) {
    1996      352795 :                 uint16_t flags = tevent_fd_get_flags(bsds->fde);
    1997      352795 :                 flags |= TEVENT_FD_READ | TEVENT_FD_WRITE;
    1998      352795 :                 tevent_fd_set_flags(bsds->fde, flags);
    1999             :         }
    2000             : 
    2001      357510 :         bsds->writeable_handler = handler;
    2002      357510 :         bsds->writeable_private = private_data;
    2003      357510 :         bsds->error_ctx = ev;
    2004             : 
    2005      357510 :         return 0;
    2006             : }
    2007             : 
    2008           0 : static ssize_t tstream_bsd_pending_bytes(struct tstream_context *stream)
    2009             : {
    2010           0 :         struct tstream_bsd *bsds = tstream_context_data(stream,
    2011             :                                    struct tstream_bsd);
    2012             :         ssize_t ret;
    2013             : 
    2014           0 :         if (bsds->fd == -1) {
    2015           0 :                 errno = ENOTCONN;
    2016           0 :                 return -1;
    2017             :         }
    2018             : 
    2019           0 :         if (bsds->error != 0) {
    2020           0 :                 errno = bsds->error;
    2021           0 :                 return -1;
    2022             :         }
    2023             : 
    2024           0 :         ret = tsocket_bsd_pending(bsds->fd);
    2025           0 :         if (ret == -1) {
    2026             :                 /*
    2027             :                  * remember the error and don't
    2028             :                  * allow further requests
    2029             :                  */
    2030           0 :                 bsds->error = errno;
    2031             :         }
    2032             : 
    2033           0 :         return ret;
    2034             : }
    2035             : 
    2036             : struct tstream_bsd_readv_state {
    2037             :         struct tstream_context *stream;
    2038             : 
    2039             :         struct iovec *vector;
    2040             :         size_t count;
    2041             : 
    2042             :         int ret;
    2043             : };
    2044             : 
    2045     5765367 : static int tstream_bsd_readv_destructor(struct tstream_bsd_readv_state *state)
    2046             : {
    2047     5765367 :         struct tstream_bsd *bsds = tstream_context_data(state->stream,
    2048             :                                    struct tstream_bsd);
    2049             : 
    2050     5765367 :         tstream_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
    2051             : 
    2052     5765367 :         return 0;
    2053             : }
    2054             : 
    2055             : static void tstream_bsd_readv_handler(void *private_data);
    2056             : 
    2057     5764208 : static struct tevent_req *tstream_bsd_readv_send(TALLOC_CTX *mem_ctx,
    2058             :                                         struct tevent_context *ev,
    2059             :                                         struct tstream_context *stream,
    2060             :                                         struct iovec *vector,
    2061             :                                         size_t count)
    2062             : {
    2063             :         struct tevent_req *req;
    2064             :         struct tstream_bsd_readv_state *state;
    2065     5764208 :         struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
    2066             :         int ret;
    2067             : 
    2068     5764208 :         req = tevent_req_create(mem_ctx, &state,
    2069             :                                 struct tstream_bsd_readv_state);
    2070     5764208 :         if (!req) {
    2071           0 :                 return NULL;
    2072             :         }
    2073             : 
    2074     5764208 :         state->stream        = stream;
    2075             :         /* we make a copy of the vector so that we can modify it */
    2076     5764208 :         state->vector        = talloc_array(state, struct iovec, count);
    2077     5764208 :         if (tevent_req_nomem(state->vector, req)) {
    2078           0 :                 goto post;
    2079             :         }
    2080     5764208 :         memcpy(state->vector, vector, sizeof(struct iovec)*count);
    2081     5764208 :         state->count = count;
    2082     5764208 :         state->ret   = 0;
    2083             : 
    2084     5764208 :         talloc_set_destructor(state, tstream_bsd_readv_destructor);
    2085             : 
    2086     5764208 :         if (bsds->fd == -1) {
    2087           0 :                 tevent_req_error(req, ENOTCONN);
    2088           0 :                 goto post;
    2089             :         }
    2090             : 
    2091             :         /*
    2092             :          * this is a fast path, not waiting for the
    2093             :          * socket to become explicit readable gains
    2094             :          * about 10%-20% performance in benchmark tests.
    2095             :          */
    2096     5764208 :         if (bsds->optimize_readv) {
    2097             :                 /*
    2098             :                  * We only do the optimization on
    2099             :                  * readv if the caller asked for it.
    2100             :                  *
    2101             :                  * This is needed because in most cases
    2102             :                  * we prefer to flush send buffers before
    2103             :                  * receiving incoming requests.
    2104             :                  */
    2105     1512393 :                 tstream_bsd_readv_handler(req);
    2106     1512393 :                 if (!tevent_req_is_in_progress(req)) {
    2107     1232025 :                         goto post;
    2108             :                 }
    2109             :         }
    2110             : 
    2111     4532183 :         ret = tstream_bsd_set_readable_handler(bsds, ev,
    2112             :                                               tstream_bsd_readv_handler,
    2113             :                                               req);
    2114     4532183 :         if (ret == -1) {
    2115           0 :                 tevent_req_error(req, errno);
    2116           0 :                 goto post;
    2117             :         }
    2118             : 
    2119     4532183 :         return req;
    2120             : 
    2121     1232025 :  post:
    2122     1232025 :         tevent_req_post(req, ev);
    2123     1232025 :         return req;
    2124             : }
    2125             : 
    2126     9660600 : static void tstream_bsd_readv_handler(void *private_data)
    2127             : {
    2128     9660600 :         struct tevent_req *req = talloc_get_type_abort(private_data,
    2129             :                                  struct tevent_req);
    2130     9660600 :         struct tstream_bsd_readv_state *state = tevent_req_data(req,
    2131             :                                         struct tstream_bsd_readv_state);
    2132     9660600 :         struct tstream_context *stream = state->stream;
    2133     9660600 :         struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
    2134             :         int ret;
    2135             :         int err;
    2136             :         int _count;
    2137             :         bool ok, retry;
    2138             : 
    2139     9660600 :         if (bsds->error != 0) {
    2140           0 :                 tevent_req_error(req, bsds->error);
    2141      808306 :                 return;
    2142             :         }
    2143             : 
    2144     9660600 :         ret = readv(bsds->fd, state->vector, state->count);
    2145     9660600 :         if (ret == 0) {
    2146             :                 /* propagate end of file */
    2147       91204 :                 bsds->error = EPIPE;
    2148       91204 :                 tevent_req_error(req, EPIPE);
    2149       90903 :                 return;
    2150             :         }
    2151     9569396 :         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
    2152     9569396 :         if (retry) {
    2153             :                 /* retry later */
    2154         846 :                 return;
    2155             :         }
    2156     9568550 :         if (err != 0) {
    2157             :                 /*
    2158             :                  * remember the error and don't
    2159             :                  * allow further requests
    2160             :                  */
    2161           0 :                 bsds->error = err;
    2162             :         }
    2163     9568550 :         if (tevent_req_error(req, err)) {
    2164           0 :                 return;
    2165             :         }
    2166             : 
    2167     9568550 :         state->ret += ret;
    2168             : 
    2169     9568550 :         _count = state->count; /* tstream has size_t count, readv has int */
    2170     9568550 :         ok = iov_advance(&state->vector, &_count, ret);
    2171     9568550 :         state->count = _count;
    2172             : 
    2173     9568550 :         if (!ok) {
    2174           0 :                 tevent_req_error(req, EINVAL);
    2175           0 :                 return;
    2176             :         }
    2177             : 
    2178     9568550 :         if (state->count > 0) {
    2179             :                 /* we have more to read */
    2180     3896056 :                 return;
    2181             :         }
    2182             : 
    2183     5672494 :         tevent_req_done(req);
    2184             : }
    2185             : 
    2186     5763698 : static int tstream_bsd_readv_recv(struct tevent_req *req,
    2187             :                                   int *perrno)
    2188             : {
    2189     5763698 :         struct tstream_bsd_readv_state *state = tevent_req_data(req,
    2190             :                                         struct tstream_bsd_readv_state);
    2191             :         int ret;
    2192             : 
    2193     5763698 :         ret = tsocket_simple_int_recv(req, perrno);
    2194     5763698 :         if (ret == 0) {
    2195     5672494 :                 ret = state->ret;
    2196             :         }
    2197             : 
    2198     5763698 :         tevent_req_received(req);
    2199     5763698 :         return ret;
    2200             : }
    2201             : 
    2202             : struct tstream_bsd_writev_state {
    2203             :         struct tstream_context *stream;
    2204             : 
    2205             :         struct iovec *vector;
    2206             :         size_t count;
    2207             : 
    2208             :         int ret;
    2209             : };
    2210             : 
    2211     1689818 : static int tstream_bsd_writev_destructor(struct tstream_bsd_writev_state *state)
    2212             : {
    2213     1689818 :         struct tstream_bsd *bsds = tstream_context_data(state->stream,
    2214             :                                   struct tstream_bsd);
    2215             : 
    2216     1689818 :         tstream_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
    2217             : 
    2218     1689818 :         return 0;
    2219             : }
    2220             : 
    2221             : static void tstream_bsd_writev_handler(void *private_data);
    2222             : 
    2223     1689818 : static struct tevent_req *tstream_bsd_writev_send(TALLOC_CTX *mem_ctx,
    2224             :                                                  struct tevent_context *ev,
    2225             :                                                  struct tstream_context *stream,
    2226             :                                                  const struct iovec *vector,
    2227             :                                                  size_t count)
    2228             : {
    2229             :         struct tevent_req *req;
    2230             :         struct tstream_bsd_writev_state *state;
    2231     1689818 :         struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
    2232             :         int ret;
    2233             : 
    2234     1689818 :         req = tevent_req_create(mem_ctx, &state,
    2235             :                                 struct tstream_bsd_writev_state);
    2236     1689818 :         if (!req) {
    2237           0 :                 return NULL;
    2238             :         }
    2239             : 
    2240     1689818 :         state->stream        = stream;
    2241             :         /* we make a copy of the vector so that we can modify it */
    2242     1689818 :         state->vector        = talloc_array(state, struct iovec, count);
    2243     1689818 :         if (tevent_req_nomem(state->vector, req)) {
    2244           0 :                 goto post;
    2245             :         }
    2246     1689818 :         memcpy(state->vector, vector, sizeof(struct iovec)*count);
    2247     1689818 :         state->count = count;
    2248     1689818 :         state->ret   = 0;
    2249             : 
    2250     1689818 :         talloc_set_destructor(state, tstream_bsd_writev_destructor);
    2251             : 
    2252     1689818 :         if (bsds->fd == -1) {
    2253           0 :                 tevent_req_error(req, ENOTCONN);
    2254           0 :                 goto post;
    2255             :         }
    2256             : 
    2257             :         /*
    2258             :          * this is a fast path, not waiting for the
    2259             :          * socket to become explicit writeable gains
    2260             :          * about 10%-20% performance in benchmark tests.
    2261             :          */
    2262     1689818 :         tstream_bsd_writev_handler(req);
    2263     1689818 :         if (!tevent_req_is_in_progress(req)) {
    2264     1332308 :                 goto post;
    2265             :         }
    2266             : 
    2267      357510 :         ret = tstream_bsd_set_writeable_handler(bsds, ev,
    2268             :                                                tstream_bsd_writev_handler,
    2269             :                                                req);
    2270      357510 :         if (ret == -1) {
    2271           0 :                 tevent_req_error(req, errno);
    2272           0 :                 goto post;
    2273             :         }
    2274             : 
    2275      357510 :         return req;
    2276             : 
    2277     1332308 :  post:
    2278     1332308 :         tevent_req_post(req, ev);
    2279     1332308 :         return req;
    2280             : }
    2281             : 
    2282     6459253 : static void tstream_bsd_writev_handler(void *private_data)
    2283             : {
    2284     6459253 :         struct tevent_req *req = talloc_get_type_abort(private_data,
    2285             :                                  struct tevent_req);
    2286     6459253 :         struct tstream_bsd_writev_state *state = tevent_req_data(req,
    2287             :                                         struct tstream_bsd_writev_state);
    2288     6459253 :         struct tstream_context *stream = state->stream;
    2289     6459253 :         struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
    2290             :         ssize_t ret;
    2291             :         int err;
    2292             :         int _count;
    2293             :         bool ok, retry;
    2294             : 
    2295     6459253 :         if (bsds->error != 0) {
    2296           0 :                 tevent_req_error(req, bsds->error);
    2297      801958 :                 return;
    2298             :         }
    2299             : 
    2300     6459253 :         ret = writev(bsds->fd, state->vector, state->count);
    2301     6459253 :         if (ret == 0) {
    2302             :                 /* propagate end of file */
    2303           0 :                 bsds->error = EPIPE;
    2304           0 :                 tevent_req_error(req, EPIPE);
    2305           0 :                 return;
    2306             :         }
    2307     6459253 :         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
    2308     6459253 :         if (retry) {
    2309             :                 /*
    2310             :                  * retry later...
    2311             :                  *
    2312             :                  * make sure we also wait readable again
    2313             :                  * in order to notice errors early
    2314             :                  */
    2315         133 :                 TEVENT_FD_READABLE(bsds->fde);
    2316         133 :                 TALLOC_FREE(bsds->error_timer);
    2317         133 :                 return;
    2318             :         }
    2319     6459120 :         if (err != 0) {
    2320             :                 /*
    2321             :                  * remember the error and don't
    2322             :                  * allow further requests
    2323             :                  */
    2324           1 :                 bsds->error = err;
    2325             :         }
    2326     6459120 :         if (tevent_req_error(req, err)) {
    2327           1 :                 return;
    2328             :         }
    2329             : 
    2330     6459119 :         state->ret += ret;
    2331             : 
    2332     6459119 :         _count = state->count; /* tstream has size_t count, writev has int */
    2333     6459119 :         ok = iov_advance(&state->vector, &_count, ret);
    2334     6459119 :         state->count = _count;
    2335             : 
    2336     6459119 :         if (!ok) {
    2337           0 :                 tevent_req_error(req, EINVAL);
    2338           0 :                 return;
    2339             :         }
    2340             : 
    2341     6459119 :         if (state->count > 0) {
    2342             :                 /*
    2343             :                  * we have more to write
    2344             :                  *
    2345             :                  * make sure we also wait readable again
    2346             :                  * in order to notice errors early
    2347             :                  */
    2348     4769302 :                 TEVENT_FD_READABLE(bsds->fde);
    2349     4769302 :                 return;
    2350             :         }
    2351             : 
    2352     1689817 :         tevent_req_done(req);
    2353             : }
    2354             : 
    2355     1689804 : static int tstream_bsd_writev_recv(struct tevent_req *req, int *perrno)
    2356             : {
    2357     1689804 :         struct tstream_bsd_writev_state *state = tevent_req_data(req,
    2358             :                                         struct tstream_bsd_writev_state);
    2359             :         int ret;
    2360             : 
    2361     1689804 :         ret = tsocket_simple_int_recv(req, perrno);
    2362     1689804 :         if (ret == 0) {
    2363     1689803 :                 ret = state->ret;
    2364             :         }
    2365             : 
    2366     1689804 :         tevent_req_received(req);
    2367     1689804 :         return ret;
    2368             : }
    2369             : 
    2370             : struct tstream_bsd_disconnect_state {
    2371             :         void *__dummy;
    2372             : };
    2373             : 
    2374       31063 : static struct tevent_req *tstream_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
    2375             :                                                      struct tevent_context *ev,
    2376             :                                                      struct tstream_context *stream)
    2377             : {
    2378       31063 :         struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
    2379             :         struct tevent_req *req;
    2380             :         struct tstream_bsd_disconnect_state *state;
    2381             :         int ret;
    2382             :         int err;
    2383             :         bool dummy;
    2384             : 
    2385       31063 :         req = tevent_req_create(mem_ctx, &state,
    2386             :                                 struct tstream_bsd_disconnect_state);
    2387       31063 :         if (req == NULL) {
    2388           0 :                 return NULL;
    2389             :         }
    2390             : 
    2391       31063 :         if (bsds->fd == -1) {
    2392           0 :                 tevent_req_error(req, ENOTCONN);
    2393           0 :                 goto post;
    2394             :         }
    2395             : 
    2396       31063 :         TALLOC_FREE(bsds->error_timer);
    2397       31063 :         bsds->error_ctx = NULL;
    2398       31063 :         TALLOC_FREE(bsds->fde);
    2399       31063 :         ret = close(bsds->fd);
    2400       31063 :         bsds->fd = -1;
    2401       31063 :         err = tsocket_bsd_error_from_errno(ret, errno, &dummy);
    2402       31063 :         if (tevent_req_error(req, err)) {
    2403           0 :                 goto post;
    2404             :         }
    2405             : 
    2406       31063 :         tevent_req_done(req);
    2407       31063 : post:
    2408       31063 :         tevent_req_post(req, ev);
    2409       31063 :         return req;
    2410             : }
    2411             : 
    2412       20396 : static int tstream_bsd_disconnect_recv(struct tevent_req *req,
    2413             :                                       int *perrno)
    2414             : {
    2415             :         int ret;
    2416             : 
    2417       20396 :         ret = tsocket_simple_int_recv(req, perrno);
    2418             : 
    2419       20396 :         tevent_req_received(req);
    2420       20396 :         return ret;
    2421             : }
    2422             : 
    2423             : static const struct tstream_context_ops tstream_bsd_ops = {
    2424             :         .name                   = "bsd",
    2425             : 
    2426             :         .pending_bytes          = tstream_bsd_pending_bytes,
    2427             : 
    2428             :         .readv_send             = tstream_bsd_readv_send,
    2429             :         .readv_recv             = tstream_bsd_readv_recv,
    2430             : 
    2431             :         .writev_send            = tstream_bsd_writev_send,
    2432             :         .writev_recv            = tstream_bsd_writev_recv,
    2433             : 
    2434             :         .disconnect_send        = tstream_bsd_disconnect_send,
    2435             :         .disconnect_recv        = tstream_bsd_disconnect_recv,
    2436             : };
    2437             : 
    2438      132253 : static int tstream_bsd_destructor(struct tstream_bsd *bsds)
    2439             : {
    2440      132253 :         TALLOC_FREE(bsds->error_timer);
    2441      132253 :         bsds->error_ctx = NULL;
    2442      132253 :         TALLOC_FREE(bsds->fde);
    2443      132253 :         if (bsds->fd != -1) {
    2444      101190 :                 close(bsds->fd);
    2445      101190 :                 bsds->fd = -1;
    2446             :         }
    2447      132253 :         return 0;
    2448             : }
    2449             : 
    2450      131113 : int _tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
    2451             :                                  int fd,
    2452             :                                  struct tstream_context **_stream,
    2453             :                                  const char *location)
    2454             : {
    2455             :         struct tstream_context *stream;
    2456             :         struct tstream_bsd *bsds;
    2457             : 
    2458      131113 :         stream = tstream_context_create(mem_ctx,
    2459             :                                         &tstream_bsd_ops,
    2460             :                                         &bsds,
    2461             :                                         struct tstream_bsd,
    2462             :                                         location);
    2463      131113 :         if (!stream) {
    2464           0 :                 return -1;
    2465             :         }
    2466      131113 :         ZERO_STRUCTP(bsds);
    2467      131113 :         bsds->fd = fd;
    2468      131113 :         talloc_set_destructor(bsds, tstream_bsd_destructor);
    2469             : 
    2470      131113 :         *_stream = stream;
    2471      131113 :         return 0;
    2472             : }
    2473             : 
    2474             : struct tstream_bsd_connect_state {
    2475             :         int fd;
    2476             :         struct tevent_fd *fde;
    2477             :         struct tstream_conext *stream;
    2478             :         struct tsocket_address *local;
    2479             : };
    2480             : 
    2481        4453 : static int tstream_bsd_connect_destructor(struct tstream_bsd_connect_state *state)
    2482             : {
    2483        4453 :         TALLOC_FREE(state->fde);
    2484        4453 :         if (state->fd != -1) {
    2485         252 :                 close(state->fd);
    2486         252 :                 state->fd = -1;
    2487             :         }
    2488             : 
    2489        4453 :         return 0;
    2490             : }
    2491             : 
    2492             : static void tstream_bsd_connect_fde_handler(struct tevent_context *ev,
    2493             :                                             struct tevent_fd *fde,
    2494             :                                             uint16_t flags,
    2495             :                                             void *private_data);
    2496             : 
    2497        4453 : static struct tevent_req *tstream_bsd_connect_send(TALLOC_CTX *mem_ctx,
    2498             :                                         struct tevent_context *ev,
    2499             :                                         int sys_errno,
    2500             :                                         const struct tsocket_address *local,
    2501             :                                         const struct tsocket_address *remote)
    2502             : {
    2503             :         struct tevent_req *req;
    2504             :         struct tstream_bsd_connect_state *state;
    2505        3919 :         struct samba_sockaddr *lbsda =
    2506        4453 :                 talloc_get_type_abort(local->private_data,
    2507             :                 struct samba_sockaddr);
    2508        4453 :         struct samba_sockaddr *lrbsda = NULL;
    2509        3919 :         struct samba_sockaddr *rbsda =
    2510        4453 :                 talloc_get_type_abort(remote->private_data,
    2511             :                 struct samba_sockaddr);
    2512             :         int ret;
    2513        4453 :         bool do_bind = false;
    2514        4453 :         bool do_reuseaddr = false;
    2515        4453 :         bool do_ipv6only = false;
    2516        4453 :         bool is_inet = false;
    2517        4453 :         int sa_fam = lbsda->u.sa.sa_family;
    2518             : 
    2519        4453 :         req = tevent_req_create(mem_ctx, &state,
    2520             :                                 struct tstream_bsd_connect_state);
    2521        4453 :         if (!req) {
    2522           0 :                 return NULL;
    2523             :         }
    2524        4453 :         state->fd = -1;
    2525        4453 :         state->fde = NULL;
    2526             : 
    2527        4453 :         talloc_set_destructor(state, tstream_bsd_connect_destructor);
    2528             : 
    2529             :         /* give the wrappers a chance to report an error */
    2530        4453 :         if (sys_errno != 0) {
    2531           0 :                 tevent_req_error(req, sys_errno);
    2532           0 :                 goto post;
    2533             :         }
    2534             : 
    2535        4453 :         switch (lbsda->u.sa.sa_family) {
    2536        1660 :         case AF_UNIX:
    2537        1660 :                 if (lbsda->u.un.sun_path[0] != 0) {
    2538           0 :                         do_reuseaddr = true;
    2539           0 :                         do_bind = true;
    2540             :                 }
    2541        1660 :                 break;
    2542         679 :         case AF_INET:
    2543         679 :                 if (lbsda->u.in.sin_port != 0) {
    2544           0 :                         do_reuseaddr = true;
    2545           0 :                         do_bind = true;
    2546             :                 }
    2547         679 :                 if (lbsda->u.in.sin_addr.s_addr != INADDR_ANY) {
    2548         679 :                         do_bind = true;
    2549             :                 }
    2550         679 :                 is_inet = true;
    2551         679 :                 break;
    2552             : #ifdef HAVE_IPV6
    2553        2114 :         case AF_INET6:
    2554        2114 :                 if (lbsda->u.in6.sin6_port != 0) {
    2555           0 :                         do_reuseaddr = true;
    2556           0 :                         do_bind = true;
    2557             :                 }
    2558        2114 :                 if (memcmp(&in6addr_any,
    2559        2114 :                            &lbsda->u.in6.sin6_addr,
    2560             :                            sizeof(in6addr_any)) != 0) {
    2561           0 :                         do_bind = true;
    2562             :                 }
    2563        2114 :                 is_inet = true;
    2564        2114 :                 do_ipv6only = true;
    2565        2114 :                 break;
    2566             : #endif
    2567           0 :         default:
    2568           0 :                 tevent_req_error(req, EINVAL);
    2569           0 :                 goto post;
    2570             :         }
    2571             : 
    2572        4453 :         if (!do_bind && is_inet) {
    2573        2114 :                 sa_fam = rbsda->u.sa.sa_family;
    2574        2114 :                 switch (sa_fam) {
    2575           0 :                 case AF_INET:
    2576           0 :                         do_ipv6only = false;
    2577           0 :                         break;
    2578             : #ifdef HAVE_IPV6
    2579        2114 :                 case AF_INET6:
    2580        2114 :                         do_ipv6only = true;
    2581        2114 :                         break;
    2582             : #endif
    2583             :                 }
    2584             :         }
    2585             : 
    2586        4453 :         if (is_inet) {
    2587        2793 :                 state->local = tsocket_address_create(state,
    2588             :                                                       &tsocket_address_bsd_ops,
    2589             :                                                       &lrbsda,
    2590             :                                                       struct samba_sockaddr,
    2591             :                                                       __location__ "bsd_connect");
    2592        2793 :                 if (tevent_req_nomem(state->local, req)) {
    2593           0 :                         goto post;
    2594             :                 }
    2595             : 
    2596        2793 :                 ZERO_STRUCTP(lrbsda);
    2597        2793 :                 lrbsda->sa_socklen = sizeof(lrbsda->u.ss);
    2598             : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
    2599             :                 lrbsda->u.sa.sa_len = lrbsda->sa_socklen;
    2600             : #endif
    2601             :         }
    2602             : 
    2603        4453 :         state->fd = socket(sa_fam, SOCK_STREAM, 0);
    2604        4453 :         if (state->fd == -1) {
    2605           0 :                 tevent_req_error(req, errno);
    2606           0 :                 goto post;
    2607             :         }
    2608             : 
    2609        4453 :         state->fd = tsocket_bsd_common_prepare_fd(state->fd, true);
    2610        4453 :         if (state->fd == -1) {
    2611           0 :                 tevent_req_error(req, errno);
    2612           0 :                 goto post;
    2613             :         }
    2614             : 
    2615             : #ifdef HAVE_IPV6
    2616        4453 :         if (do_ipv6only) {
    2617        2114 :                 int val = 1;
    2618             : 
    2619        2114 :                 ret = setsockopt(state->fd, IPPROTO_IPV6, IPV6_V6ONLY,
    2620             :                                  (const void *)&val, sizeof(val));
    2621        2114 :                 if (ret == -1) {
    2622           0 :                         tevent_req_error(req, errno);
    2623           0 :                         goto post;
    2624             :                 }
    2625             :         }
    2626             : #endif
    2627             : 
    2628        4453 :         if (do_reuseaddr) {
    2629           0 :                 int val = 1;
    2630             : 
    2631           0 :                 ret = setsockopt(state->fd, SOL_SOCKET, SO_REUSEADDR,
    2632             :                                  (const void *)&val, sizeof(val));
    2633           0 :                 if (ret == -1) {
    2634           0 :                         tevent_req_error(req, errno);
    2635           0 :                         goto post;
    2636             :                 }
    2637             :         }
    2638             : 
    2639        4453 :         if (do_bind) {
    2640         679 :                 ret = bind(state->fd, &lbsda->u.sa, lbsda->sa_socklen);
    2641         679 :                 if (ret == -1) {
    2642           0 :                         tevent_req_error(req, errno);
    2643           0 :                         goto post;
    2644             :                 }
    2645             :         }
    2646             : 
    2647        4453 :         if (rbsda->u.sa.sa_family != sa_fam) {
    2648           0 :                 tevent_req_error(req, EINVAL);
    2649           0 :                 goto post;
    2650             :         }
    2651             : 
    2652        4453 :         ret = connect(state->fd, &rbsda->u.sa, rbsda->sa_socklen);
    2653        4453 :         if (ret == -1) {
    2654         252 :                 if (errno == EINPROGRESS) {
    2655           0 :                         goto async;
    2656             :                 }
    2657         252 :                 tevent_req_error(req, errno);
    2658         252 :                 goto post;
    2659             :         }
    2660             : 
    2661        4201 :         if (!state->local) {
    2662        1408 :                 tevent_req_done(req);
    2663        1408 :                 goto post;
    2664             :         }
    2665             : 
    2666        2793 :         if (lrbsda != NULL) {
    2667        5586 :                 ret = getsockname(state->fd,
    2668        2793 :                                   &lrbsda->u.sa,
    2669        2793 :                                   &lrbsda->sa_socklen);
    2670        2793 :                 if (ret == -1) {
    2671           0 :                         tevent_req_error(req, errno);
    2672           0 :                         goto post;
    2673             :                 }
    2674             :         }
    2675             : 
    2676        2793 :         tevent_req_done(req);
    2677        2793 :         goto post;
    2678             : 
    2679           0 :  async:
    2680             : 
    2681             :         /*
    2682             :          * Note for historic reasons TEVENT_FD_WRITE is not enough
    2683             :          * to get notified for POLLERR or EPOLLHUP even if they
    2684             :          * come together with POLLOUT. That means we need to
    2685             :          * use TEVENT_FD_READ in addition until we have
    2686             :          * TEVENT_FD_ERROR.
    2687             :          */
    2688           0 :         state->fde = tevent_add_fd(ev, state,
    2689             :                                    state->fd,
    2690             :                                    TEVENT_FD_READ | TEVENT_FD_WRITE,
    2691             :                                    tstream_bsd_connect_fde_handler,
    2692             :                                    req);
    2693           0 :         if (tevent_req_nomem(state->fde, req)) {
    2694           0 :                 goto post;
    2695             :         }
    2696             : 
    2697           0 :         return req;
    2698             : 
    2699        4453 :  post:
    2700        4453 :         tevent_req_post(req, ev);
    2701        4453 :         return req;
    2702             : }
    2703             : 
    2704           0 : static void tstream_bsd_connect_fde_handler(struct tevent_context *ev,
    2705             :                                             struct tevent_fd *fde,
    2706             :                                             uint16_t flags,
    2707             :                                             void *private_data)
    2708             : {
    2709           0 :         struct tevent_req *req = talloc_get_type_abort(private_data,
    2710             :                                  struct tevent_req);
    2711           0 :         struct tstream_bsd_connect_state *state = tevent_req_data(req,
    2712             :                                         struct tstream_bsd_connect_state);
    2713           0 :         struct samba_sockaddr *lrbsda = NULL;
    2714             :         int ret;
    2715           0 :         int error=0;
    2716           0 :         socklen_t len = sizeof(error);
    2717             :         int err;
    2718             :         bool retry;
    2719             : 
    2720           0 :         ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR, &error, &len);
    2721           0 :         if (ret == 0) {
    2722           0 :                 if (error != 0) {
    2723           0 :                         errno = error;
    2724           0 :                         ret = -1;
    2725             :                 }
    2726             :         }
    2727           0 :         err = tsocket_bsd_error_from_errno(ret, errno, &retry);
    2728           0 :         if (retry) {
    2729             :                 /* retry later */
    2730           0 :                 return;
    2731             :         }
    2732           0 :         if (tevent_req_error(req, err)) {
    2733           0 :                 return;
    2734             :         }
    2735             : 
    2736           0 :         if (!state->local) {
    2737           0 :                 tevent_req_done(req);
    2738           0 :                 return;
    2739             :         }
    2740             : 
    2741           0 :         lrbsda = talloc_get_type_abort(state->local->private_data,
    2742             :                                        struct samba_sockaddr);
    2743             : 
    2744           0 :         ret = getsockname(state->fd, &lrbsda->u.sa, &lrbsda->sa_socklen);
    2745           0 :         if (ret == -1) {
    2746           0 :                 tevent_req_error(req, errno);
    2747           0 :                 return;
    2748             :         }
    2749             : 
    2750           0 :         tevent_req_done(req);
    2751             : }
    2752             : 
    2753        4453 : static int tstream_bsd_connect_recv(struct tevent_req *req,
    2754             :                                     int *perrno,
    2755             :                                     TALLOC_CTX *mem_ctx,
    2756             :                                     struct tstream_context **stream,
    2757             :                                     struct tsocket_address **local,
    2758             :                                     const char *location)
    2759             : {
    2760        4453 :         struct tstream_bsd_connect_state *state = tevent_req_data(req,
    2761             :                                         struct tstream_bsd_connect_state);
    2762             :         int ret;
    2763             : 
    2764        4453 :         ret = tsocket_simple_int_recv(req, perrno);
    2765        4453 :         if (ret == 0) {
    2766        4201 :                 ret = _tstream_bsd_existing_socket(mem_ctx,
    2767             :                                                    state->fd,
    2768             :                                                    stream,
    2769             :                                                    location);
    2770        4201 :                 if (ret == -1) {
    2771           0 :                         *perrno = errno;
    2772           0 :                         goto done;
    2773             :                 }
    2774        4201 :                 TALLOC_FREE(state->fde);
    2775        4201 :                 state->fd = -1;
    2776             : 
    2777        4201 :                 if (local) {
    2778           0 :                         *local = talloc_move(mem_ctx, &state->local);
    2779             :                 }
    2780             :         }
    2781             : 
    2782        8372 : done:
    2783        4453 :         tevent_req_received(req);
    2784        4453 :         return ret;
    2785             : }
    2786             : 
    2787        2793 : struct tevent_req * tstream_inet_tcp_connect_send(TALLOC_CTX *mem_ctx,
    2788             :                                         struct tevent_context *ev,
    2789             :                                         const struct tsocket_address *local,
    2790             :                                         const struct tsocket_address *remote)
    2791             : {
    2792        2793 :         struct samba_sockaddr *lbsda =
    2793        2793 :                 talloc_get_type_abort(local->private_data,
    2794             :                 struct samba_sockaddr);
    2795             :         struct tevent_req *req;
    2796        2793 :         int sys_errno = 0;
    2797             : 
    2798        2793 :         switch (lbsda->u.sa.sa_family) {
    2799         679 :         case AF_INET:
    2800         679 :                 break;
    2801             : #ifdef HAVE_IPV6
    2802        2114 :         case AF_INET6:
    2803        2114 :                 break;
    2804             : #endif
    2805           0 :         default:
    2806           0 :                 sys_errno = EINVAL;
    2807           0 :                 break;
    2808             :         }
    2809             : 
    2810        2793 :         req = tstream_bsd_connect_send(mem_ctx, ev, sys_errno, local, remote);
    2811             : 
    2812        2793 :         return req;
    2813             : }
    2814             : 
    2815        2793 : int _tstream_inet_tcp_connect_recv(struct tevent_req *req,
    2816             :                                    int *perrno,
    2817             :                                    TALLOC_CTX *mem_ctx,
    2818             :                                    struct tstream_context **stream,
    2819             :                                    struct tsocket_address **local,
    2820             :                                    const char *location)
    2821             : {
    2822        2793 :         return tstream_bsd_connect_recv(req, perrno,
    2823             :                                         mem_ctx, stream, local,
    2824             :                                         location);
    2825             : }
    2826             : 
    2827        1660 : struct tevent_req * tstream_unix_connect_send(TALLOC_CTX *mem_ctx,
    2828             :                                         struct tevent_context *ev,
    2829             :                                         const struct tsocket_address *local,
    2830             :                                         const struct tsocket_address *remote)
    2831             : {
    2832        1126 :         struct samba_sockaddr *lbsda =
    2833        1660 :                 talloc_get_type_abort(local->private_data,
    2834             :                 struct samba_sockaddr);
    2835             :         struct tevent_req *req;
    2836        1660 :         int sys_errno = 0;
    2837             : 
    2838        1660 :         switch (lbsda->u.sa.sa_family) {
    2839        1660 :         case AF_UNIX:
    2840        1660 :                 break;
    2841           0 :         default:
    2842           0 :                 sys_errno = EINVAL;
    2843           0 :                 break;
    2844             :         }
    2845             : 
    2846        1660 :         req = tstream_bsd_connect_send(mem_ctx, ev, sys_errno, local, remote);
    2847             : 
    2848        1660 :         return req;
    2849             : }
    2850             : 
    2851        1660 : int _tstream_unix_connect_recv(struct tevent_req *req,
    2852             :                                       int *perrno,
    2853             :                                       TALLOC_CTX *mem_ctx,
    2854             :                                       struct tstream_context **stream,
    2855             :                                       const char *location)
    2856             : {
    2857        1660 :         return tstream_bsd_connect_recv(req, perrno,
    2858             :                                         mem_ctx, stream, NULL,
    2859             :                                         location);
    2860             : }
    2861             : 
    2862           0 : int _tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
    2863             :                              struct tstream_context **_stream1,
    2864             :                              TALLOC_CTX *mem_ctx2,
    2865             :                              struct tstream_context **_stream2,
    2866             :                              const char *location)
    2867             : {
    2868             :         int ret;
    2869             :         int fds[2];
    2870             :         int fd1;
    2871             :         int fd2;
    2872           0 :         struct tstream_context *stream1 = NULL;
    2873           0 :         struct tstream_context *stream2 = NULL;
    2874             : 
    2875           0 :         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
    2876           0 :         if (ret == -1) {
    2877           0 :                 return -1;
    2878             :         }
    2879           0 :         fd1 = fds[0];
    2880           0 :         fd2 = fds[1];
    2881             : 
    2882           0 :         fd1 = tsocket_bsd_common_prepare_fd(fd1, true);
    2883           0 :         if (fd1 == -1) {
    2884           0 :                 int sys_errno = errno;
    2885           0 :                 close(fd2);
    2886           0 :                 errno = sys_errno;
    2887           0 :                 return -1;
    2888             :         }
    2889             : 
    2890           0 :         fd2 = tsocket_bsd_common_prepare_fd(fd2, true);
    2891           0 :         if (fd2 == -1) {
    2892           0 :                 int sys_errno = errno;
    2893           0 :                 close(fd1);
    2894           0 :                 errno = sys_errno;
    2895           0 :                 return -1;
    2896             :         }
    2897             : 
    2898           0 :         ret = _tstream_bsd_existing_socket(mem_ctx1,
    2899             :                                            fd1,
    2900             :                                            &stream1,
    2901             :                                            location);
    2902           0 :         if (ret == -1) {
    2903           0 :                 int sys_errno = errno;
    2904           0 :                 close(fd1);
    2905           0 :                 close(fd2);
    2906           0 :                 errno = sys_errno;
    2907           0 :                 return -1;
    2908             :         }
    2909             : 
    2910           0 :         ret = _tstream_bsd_existing_socket(mem_ctx2,
    2911             :                                            fd2,
    2912             :                                            &stream2,
    2913             :                                            location);
    2914           0 :         if (ret == -1) {
    2915           0 :                 int sys_errno = errno;
    2916           0 :                 talloc_free(stream1);
    2917           0 :                 close(fd2);
    2918           0 :                 errno = sys_errno;
    2919           0 :                 return -1;
    2920             :         }
    2921             : 
    2922           0 :         *_stream1 = stream1;
    2923           0 :         *_stream2 = stream2;
    2924           0 :         return 0;
    2925             : }
    2926             : 

Generated by: LCOV version 1.13