LCOV - code coverage report
Current view: top level - lib/tsocket - tsocket_bsd.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 932 1382 67.4 %
Date: 2024-02-28 12:06:22 Functions: 56 65 86.2 %

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

Generated by: LCOV version 1.14