LCOV - code coverage report
Current view: top level - lib/tsocket - tsocket_bsd.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 780 1190 65.5 %
Date: 2021-09-23 10:06:22 Functions: 55 64 85.9 %

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

Generated by: LCOV version 1.13