LCOV - code coverage report
Current view: top level - lib/tsocket - tsocket_bsd.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 817 1329 61.5 %
Date: 2024-02-14 10:14:15 Functions: 56 68 82.4 %

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

Generated by: LCOV version 1.14