LCOV - code coverage report
Current view: top level - lib/async_req - async_sock.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 231 315 73.3 %
Date: 2024-06-13 04:01:37 Functions: 21 22 95.5 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    async socket syscalls
       4             :    Copyright (C) Volker Lendecke 2008
       5             : 
       6             :      ** NOTE! The following LGPL license applies to the async_sock
       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             :    Library General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU Lesser General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "replace.h"
      25             : #include "system/network.h"
      26             : #include "system/filesys.h"
      27             : #include <talloc.h>
      28             : #include <tevent.h>
      29             : #include "lib/async_req/async_sock.h"
      30             : #include "lib/util/iov_buf.h"
      31             : #include "lib/util/util_net.h"
      32             : 
      33             : /* Note: lib/util/ is currently GPL */
      34             : #include "lib/util/tevent_unix.h"
      35             : #include "lib/util/samba_util.h"
      36             : 
      37             : struct async_connect_state {
      38             :         int fd;
      39             :         struct tevent_fd *fde;
      40             :         int result;
      41             :         long old_sockflags;
      42             :         socklen_t address_len;
      43             :         struct sockaddr_storage address;
      44             : 
      45             :         void (*before_connect)(void *private_data);
      46             :         void (*after_connect)(void *private_data);
      47             :         void *private_data;
      48             : };
      49             : 
      50             : static void async_connect_cleanup(struct tevent_req *req,
      51             :                                   enum tevent_req_state req_state);
      52             : static void async_connect_connected(struct tevent_context *ev,
      53             :                                     struct tevent_fd *fde, uint16_t flags,
      54             :                                     void *priv);
      55             : 
      56             : /**
      57             :  * @brief async version of connect(2)
      58             :  * @param[in] mem_ctx   The memory context to hang the result off
      59             :  * @param[in] ev        The event context to work from
      60             :  * @param[in] fd        The socket to recv from
      61             :  * @param[in] address   Where to connect?
      62             :  * @param[in] address_len Length of *address
      63             :  * @retval The async request
      64             :  *
      65             :  * This function sets the socket into non-blocking state to be able to call
      66             :  * connect in an async state. This will be reset when the request is finished.
      67             :  */
      68             : 
      69        6135 : struct tevent_req *async_connect_send(
      70             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd,
      71             :         const struct sockaddr *address, socklen_t address_len,
      72             :         void (*before_connect)(void *private_data),
      73             :         void (*after_connect)(void *private_data),
      74             :         void *private_data)
      75             : {
      76             :         struct tevent_req *req;
      77             :         struct async_connect_state *state;
      78             :         int ret;
      79             : 
      80        6135 :         req = tevent_req_create(mem_ctx, &state, struct async_connect_state);
      81        6135 :         if (req == NULL) {
      82           0 :                 return NULL;
      83             :         }
      84             : 
      85             :         /**
      86             :          * We have to set the socket to nonblocking for async connect(2). Keep
      87             :          * the old sockflags around.
      88             :          */
      89             : 
      90        6135 :         state->fd = fd;
      91        6135 :         state->before_connect = before_connect;
      92        6135 :         state->after_connect = after_connect;
      93        6135 :         state->private_data = private_data;
      94             : 
      95        6135 :         state->old_sockflags = fcntl(fd, F_GETFL, 0);
      96        6135 :         if (state->old_sockflags == -1) {
      97           0 :                 tevent_req_error(req, errno);
      98           0 :                 return tevent_req_post(req, ev);
      99             :         }
     100             : 
     101        6135 :         tevent_req_set_cleanup_fn(req, async_connect_cleanup);
     102             : 
     103        6135 :         state->address_len = address_len;
     104        6135 :         if (address_len > sizeof(state->address)) {
     105           0 :                 tevent_req_error(req, EINVAL);
     106           0 :                 return tevent_req_post(req, ev);
     107             :         }
     108        6135 :         memcpy(&state->address, address, address_len);
     109             : 
     110        6135 :         ret = set_blocking(fd, false);
     111        6135 :         if (ret == -1) {
     112           0 :                 tevent_req_error(req, errno);
     113           0 :                 return tevent_req_post(req, ev);
     114             :         }
     115             : 
     116        6135 :         if (state->before_connect != NULL) {
     117        3536 :                 state->before_connect(state->private_data);
     118             :         }
     119             : 
     120        6135 :         state->result = connect(fd, address, address_len);
     121             : 
     122        6135 :         if (state->after_connect != NULL) {
     123        3536 :                 state->after_connect(state->private_data);
     124             :         }
     125             : 
     126        6135 :         if (state->result == 0) {
     127        6118 :                 tevent_req_done(req);
     128        6118 :                 return tevent_req_post(req, ev);
     129             :         }
     130             : 
     131             :         /*
     132             :          * The only errno indicating that an initial connect is still
     133             :          * in flight is EINPROGRESS.
     134             :          *
     135             :          * This allows callers like open_socket_out_send() to reuse
     136             :          * fds and call us with an fd for which the connect is still
     137             :          * in flight. The proper thing to do for callers would be
     138             :          * closing the fd and starting from scratch with a fresh
     139             :          * socket.
     140             :          */
     141             : 
     142          17 :         if (errno != EINPROGRESS) {
     143          17 :                 tevent_req_error(req, errno);
     144          17 :                 return tevent_req_post(req, ev);
     145             :         }
     146             : 
     147             :         /*
     148             :          * Note for historic reasons TEVENT_FD_WRITE is not enough
     149             :          * to get notified for POLLERR or EPOLLHUP even if they
     150             :          * come together with POLLOUT. That means we need to
     151             :          * use TEVENT_FD_READ in addition until we have
     152             :          * TEVENT_FD_ERROR.
     153             :          */
     154           0 :         state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ|TEVENT_FD_WRITE,
     155             :                                    async_connect_connected, req);
     156           0 :         if (state->fde == NULL) {
     157           0 :                 tevent_req_error(req, ENOMEM);
     158           0 :                 return tevent_req_post(req, ev);
     159             :         }
     160           0 :         return req;
     161             : }
     162             : 
     163       12270 : static void async_connect_cleanup(struct tevent_req *req,
     164             :                                   enum tevent_req_state req_state)
     165             : {
     166        8666 :         struct async_connect_state *state =
     167       12270 :                 tevent_req_data(req, struct async_connect_state);
     168             : 
     169       12270 :         TALLOC_FREE(state->fde);
     170       12270 :         if (state->fd != -1) {
     171             :                 int ret;
     172             : 
     173        6135 :                 ret = fcntl(state->fd, F_SETFL, state->old_sockflags);
     174        6135 :                 if (ret == -1) {
     175           0 :                         abort();
     176             :                 }
     177             : 
     178        6135 :                 state->fd = -1;
     179             :         }
     180       12270 : }
     181             : 
     182             : /**
     183             :  * fde event handler for connect(2)
     184             :  * @param[in] ev        The event context that sent us here
     185             :  * @param[in] fde       The file descriptor event associated with the connect
     186             :  * @param[in] flags     Indicate read/writeability of the socket
     187             :  * @param[in] priv      private data, "struct async_req *" in this case
     188             :  */
     189             : 
     190           0 : static void async_connect_connected(struct tevent_context *ev,
     191             :                                     struct tevent_fd *fde, uint16_t flags,
     192             :                                     void *priv)
     193             : {
     194           0 :         struct tevent_req *req = talloc_get_type_abort(
     195             :                 priv, struct tevent_req);
     196           0 :         struct async_connect_state *state =
     197           0 :                 tevent_req_data(req, struct async_connect_state);
     198             :         int ret;
     199           0 :         int socket_error = 0;
     200           0 :         socklen_t slen = sizeof(socket_error);
     201             : 
     202           0 :         ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
     203             :                          &socket_error, &slen);
     204             : 
     205           0 :         if (ret != 0) {
     206             :                 /*
     207             :                  * According to Stevens this is the Solaris behaviour
     208             :                  * in case the connection encountered an error:
     209             :                  * getsockopt() fails, error is in errno
     210             :                  */
     211           0 :                 tevent_req_error(req, errno);
     212           0 :                 return;
     213             :         }
     214             : 
     215           0 :         if (socket_error != 0) {
     216             :                 /*
     217             :                  * Berkeley derived implementations (including) Linux
     218             :                  * return the pending error via socket_error.
     219             :                  */
     220           0 :                 tevent_req_error(req, socket_error);
     221           0 :                 return;
     222             :         }
     223             : 
     224           0 :         tevent_req_done(req);
     225           0 :         return;
     226             : }
     227             : 
     228        6135 : int async_connect_recv(struct tevent_req *req, int *perrno)
     229             : {
     230        6135 :         int err = tevent_req_simple_recv_unix(req);
     231             : 
     232        6135 :         if (err != 0) {
     233          17 :                 *perrno = err;
     234          17 :                 return -1;
     235             :         }
     236             : 
     237        6118 :         return 0;
     238             : }
     239             : 
     240             : struct writev_state {
     241             :         struct tevent_context *ev;
     242             :         struct tevent_queue_entry *queue_entry;
     243             :         int fd;
     244             :         struct tevent_fd *fde;
     245             :         struct iovec *iov;
     246             :         int count;
     247             :         size_t total_size;
     248             :         uint16_t flags;
     249             :         bool err_on_readability;
     250             : };
     251             : 
     252             : static void writev_cleanup(struct tevent_req *req,
     253             :                            enum tevent_req_state req_state);
     254             : static bool writev_cancel(struct tevent_req *req);
     255             : static void writev_trigger(struct tevent_req *req, void *private_data);
     256             : static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
     257             :                            uint16_t flags, void *private_data);
     258             : 
     259     1060632 : struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     260             :                                struct tevent_queue *queue, int fd,
     261             :                                bool err_on_readability,
     262             :                                struct iovec *iov, int count)
     263             : {
     264             :         struct tevent_req *req;
     265             :         struct writev_state *state;
     266             : 
     267     1060632 :         req = tevent_req_create(mem_ctx, &state, struct writev_state);
     268     1060632 :         if (req == NULL) {
     269           0 :                 return NULL;
     270             :         }
     271     1060632 :         state->ev = ev;
     272     1060632 :         state->fd = fd;
     273     1060632 :         state->total_size = 0;
     274     1060632 :         state->count = count;
     275     1060632 :         state->iov = (struct iovec *)talloc_memdup(
     276             :                 state, iov, sizeof(struct iovec) * count);
     277     1060632 :         if (tevent_req_nomem(state->iov, req)) {
     278           0 :                 return tevent_req_post(req, ev);
     279             :         }
     280     1060632 :         state->flags = TEVENT_FD_WRITE|TEVENT_FD_READ;
     281     1060632 :         state->err_on_readability = err_on_readability;
     282             : 
     283     1060632 :         tevent_req_set_cleanup_fn(req, writev_cleanup);
     284     1060632 :         tevent_req_set_cancel_fn(req, writev_cancel);
     285             : 
     286     1060632 :         if (queue == NULL) {
     287       17576 :                 state->fde = tevent_add_fd(state->ev, state, state->fd,
     288             :                                     state->flags, writev_handler, req);
     289       17576 :                 if (tevent_req_nomem(state->fde, req)) {
     290           0 :                         return tevent_req_post(req, ev);
     291             :                 }
     292       17576 :                 return req;
     293             :         }
     294             : 
     295             :         /*
     296             :          * writev_trigger tries a nonblocking write. If that succeeds,
     297             :          * we can't directly notify the callback to call
     298             :          * writev_recv. The callback would TALLOC_FREE(req) after
     299             :          * calling writev_recv even before writev_trigger can inspect
     300             :          * it for success.
     301             :          */
     302     1043056 :         tevent_req_defer_callback(req, ev);
     303             : 
     304     1043056 :         state->queue_entry = tevent_queue_add_optimize_empty(
     305             :                 queue, ev, req, writev_trigger, NULL);
     306     1043056 :         if (tevent_req_nomem(state->queue_entry, req)) {
     307           0 :                 return tevent_req_post(req, ev);
     308             :         }
     309     1043056 :         if (!tevent_req_is_in_progress(req)) {
     310     1026463 :                 return tevent_req_post(req, ev);
     311             :         }
     312       16593 :         return req;
     313             : }
     314             : 
     315     2121262 : static void writev_cleanup(struct tevent_req *req,
     316             :                            enum tevent_req_state req_state)
     317             : {
     318     2121262 :         struct writev_state *state = tevent_req_data(req, struct writev_state);
     319             : 
     320     2121262 :         TALLOC_FREE(state->queue_entry);
     321     2121262 :         TALLOC_FREE(state->fde);
     322     2121262 : }
     323             : 
     324        3674 : static bool writev_cancel(struct tevent_req *req)
     325             : {
     326        3674 :         struct writev_state *state = tevent_req_data(req, struct writev_state);
     327             : 
     328        3674 :         if (state->total_size > 0) {
     329             :                 /*
     330             :                  * We've already started to write :-(
     331             :                  */
     332        3471 :                 return false;
     333             :         }
     334             : 
     335         203 :         TALLOC_FREE(state->queue_entry);
     336         203 :         TALLOC_FREE(state->fde);
     337             : 
     338         203 :         tevent_req_defer_callback(req, state->ev);
     339         203 :         tevent_req_error(req, ECANCELED);
     340         203 :         return true;
     341             : }
     342             : 
     343     1211232 : static void writev_do(struct tevent_req *req, struct writev_state *state)
     344             : {
     345             :         ssize_t written;
     346             :         bool ok;
     347             : 
     348     1211232 :         written = writev(state->fd, state->iov, state->count);
     349     1211232 :         if ((written == -1) &&
     350           0 :             ((errno == EINTR) ||
     351           0 :              (errno == EAGAIN) ||
     352           0 :              (errno == EWOULDBLOCK))) {
     353             :                 /* retry after going through the tevent loop */
     354           0 :                 return;
     355             :         }
     356     1211232 :         if (written == -1) {
     357           0 :                 tevent_req_error(req, errno);
     358           0 :                 return;
     359             :         }
     360     1211232 :         if (written == 0) {
     361           0 :                 tevent_req_error(req, EPIPE);
     362           0 :                 return;
     363             :         }
     364     1211232 :         state->total_size += written;
     365             : 
     366     1211232 :         ok = iov_advance(&state->iov, &state->count, written);
     367     1211232 :         if (!ok) {
     368           0 :                 tevent_req_error(req, EIO);
     369           0 :                 return;
     370             :         }
     371             : 
     372     1211232 :         if (state->count == 0) {
     373     1060428 :                 tevent_req_done(req);
     374     1060428 :                 return;
     375             :         }
     376             : }
     377             : 
     378     1042853 : static void writev_trigger(struct tevent_req *req, void *private_data)
     379             : {
     380     1042853 :         struct writev_state *state = tevent_req_data(req, struct writev_state);
     381             : 
     382     1042853 :         state->queue_entry = NULL;
     383             : 
     384     1042853 :         writev_do(req, state);
     385     1042853 :         if (!tevent_req_is_in_progress(req)) {
     386     1027434 :                 return;
     387             :         }
     388             : 
     389       15419 :         state->fde = tevent_add_fd(state->ev, state, state->fd, state->flags,
     390             :                             writev_handler, req);
     391       15419 :         if (tevent_req_nomem(state->fde, req)) {
     392           0 :                 return;
     393             :         }
     394             : }
     395             : 
     396      168379 : static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
     397             :                            uint16_t flags, void *private_data)
     398             : {
     399      168379 :         struct tevent_req *req = talloc_get_type_abort(
     400             :                 private_data, struct tevent_req);
     401      122344 :         struct writev_state *state =
     402      168379 :                 tevent_req_data(req, struct writev_state);
     403             : 
     404      168379 :         if ((state->flags & TEVENT_FD_READ) && (flags & TEVENT_FD_READ)) {
     405             :                 int ret, value;
     406             : 
     407          26 :                 if (state->err_on_readability) {
     408             :                         /* Readable and the caller wants an error on read. */
     409           0 :                         tevent_req_error(req, EPIPE);
     410           0 :                         return;
     411             :                 }
     412             : 
     413             :                 /* Might be an error. Check if there are bytes to read */
     414          26 :                 ret = ioctl(state->fd, FIONREAD, &value);
     415             :                 /* FIXME - should we also check
     416             :                    for ret == 0 and value == 0 here ? */
     417          26 :                 if (ret == -1) {
     418             :                         /* There's an error. */
     419           0 :                         tevent_req_error(req, EPIPE);
     420           0 :                         return;
     421             :                 }
     422             :                 /* A request for TEVENT_FD_READ will succeed from now and
     423             :                    forevermore until the bytes are read so if there was
     424             :                    an error we'll wait until we do read, then get it in
     425             :                    the read callback function. Until then, remove TEVENT_FD_READ
     426             :                    from the flags we're waiting for. */
     427          26 :                 state->flags &= ~TEVENT_FD_READ;
     428          26 :                 TEVENT_FD_NOT_READABLE(fde);
     429             : 
     430             :                 /* If not writable, we're done. */
     431          26 :                 if (!(flags & TEVENT_FD_WRITE)) {
     432           0 :                         return;
     433             :                 }
     434             :         }
     435             : 
     436      168379 :         writev_do(req, state);
     437             : }
     438             : 
     439     1060428 : ssize_t writev_recv(struct tevent_req *req, int *perrno)
     440             : {
     441      977918 :         struct writev_state *state =
     442     1060428 :                 tevent_req_data(req, struct writev_state);
     443             :         ssize_t ret;
     444             : 
     445     1060428 :         if (tevent_req_is_unix_error(req, perrno)) {
     446           0 :                 tevent_req_received(req);
     447           0 :                 return -1;
     448             :         }
     449     1060428 :         ret = state->total_size;
     450     1060428 :         tevent_req_received(req);
     451     1060428 :         return ret;
     452             : }
     453             : 
     454             : struct read_packet_state {
     455             :         int fd;
     456             :         struct tevent_fd *fde;
     457             :         uint8_t *buf;
     458             :         size_t nread;
     459             :         ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
     460             :         void *private_data;
     461             : };
     462             : 
     463             : static void read_packet_cleanup(struct tevent_req *req,
     464             :                                  enum tevent_req_state req_state);
     465             : static void read_packet_handler(struct tevent_context *ev,
     466             :                                 struct tevent_fd *fde,
     467             :                                 uint16_t flags, void *private_data);
     468             : 
     469     1170966 : struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
     470             :                                     struct tevent_context *ev,
     471             :                                     int fd, size_t initial,
     472             :                                     ssize_t (*more)(uint8_t *buf,
     473             :                                                     size_t buflen,
     474             :                                                     void *private_data),
     475             :                                     void *private_data)
     476             : {
     477             :         struct tevent_req *req;
     478             :         struct read_packet_state *state;
     479             : 
     480     1170966 :         req = tevent_req_create(mem_ctx, &state, struct read_packet_state);
     481     1170966 :         if (req == NULL) {
     482           0 :                 return NULL;
     483             :         }
     484     1170966 :         state->fd = fd;
     485     1170966 :         state->nread = 0;
     486     1170966 :         state->more = more;
     487     1170966 :         state->private_data = private_data;
     488             : 
     489     1170966 :         tevent_req_set_cleanup_fn(req, read_packet_cleanup);
     490             : 
     491     1170966 :         state->buf = talloc_array(state, uint8_t, initial);
     492     1170966 :         if (tevent_req_nomem(state->buf, req)) {
     493           0 :                 return tevent_req_post(req, ev);
     494             :         }
     495             : 
     496     1170966 :         state->fde = tevent_add_fd(ev, state, fd,
     497             :                                    TEVENT_FD_READ, read_packet_handler,
     498             :                                    req);
     499     1170966 :         if (tevent_req_nomem(state->fde, req)) {
     500           0 :                 return tevent_req_post(req, ev);
     501             :         }
     502     1170966 :         return req;
     503             : }
     504             : 
     505     2307542 : static void read_packet_cleanup(struct tevent_req *req,
     506             :                            enum tevent_req_state req_state)
     507             : {
     508     2112623 :         struct read_packet_state *state =
     509     2307542 :                 tevent_req_data(req, struct read_packet_state);
     510             : 
     511     2307542 :         TALLOC_FREE(state->fde);
     512     2307542 : }
     513             : 
     514     2378959 : static void read_packet_handler(struct tevent_context *ev,
     515             :                                 struct tevent_fd *fde,
     516             :                                 uint16_t flags, void *private_data)
     517             : {
     518     2378959 :         struct tevent_req *req = talloc_get_type_abort(
     519             :                 private_data, struct tevent_req);
     520     2152973 :         struct read_packet_state *state =
     521     2378959 :                 tevent_req_data(req, struct read_packet_state);
     522     2378959 :         size_t total = talloc_get_size(state->buf);
     523             :         ssize_t nread, more;
     524             :         uint8_t *tmp;
     525             : 
     526     2378959 :         nread = recv(state->fd, state->buf+state->nread, total-state->nread,
     527             :                      0);
     528     2378959 :         if ((nread == -1) && (errno == ENOTSOCK)) {
     529          22 :                 nread = read(state->fd, state->buf+state->nread,
     530          22 :                              total-state->nread);
     531             :         }
     532     2378959 :         if ((nread == -1) && (errno == EINTR)) {
     533             :                 /* retry */
     534           0 :                 return;
     535             :         }
     536     2378959 :         if (nread == -1) {
     537           2 :                 tevent_req_error(req, errno);
     538           2 :                 return;
     539             :         }
     540     2378957 :         if (nread == 0) {
     541        8374 :                 tevent_req_error(req, EPIPE);
     542        8374 :                 return;
     543             :         }
     544             : 
     545     2370583 :         state->nread += nread;
     546     2370583 :         if (state->nread < total) {
     547             :                 /* Come back later */
     548      105548 :                 return;
     549             :         }
     550             : 
     551             :         /*
     552             :          * We got what was initially requested. See if "more" asks for -- more.
     553             :          */
     554     2265035 :         if (state->more == NULL) {
     555             :                 /* Nobody to ask, this is a async read_data */
     556          22 :                 tevent_req_done(req);
     557          22 :                 return;
     558             :         }
     559             : 
     560     2265013 :         more = state->more(state->buf, total, state->private_data);
     561     2265013 :         if (more == -1) {
     562             :                 /* We got an invalid packet, tell the caller */
     563           0 :                 tevent_req_error(req, EIO);
     564           0 :                 return;
     565             :         }
     566     2265013 :         if (more == 0) {
     567             :                 /* We're done, full packet received */
     568     1128211 :                 tevent_req_done(req);
     569     1128211 :                 return;
     570             :         }
     571             : 
     572     1136802 :         if (total + more < total) {
     573           0 :                 tevent_req_error(req, EMSGSIZE);
     574           0 :                 return;
     575             :         }
     576             : 
     577     1136802 :         tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
     578     1136802 :         if (tevent_req_nomem(tmp, req)) {
     579           0 :                 return;
     580             :         }
     581     1136802 :         state->buf = tmp;
     582             : }
     583             : 
     584     1136609 : ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     585             :                          uint8_t **pbuf, int *perrno)
     586             : {
     587     1039642 :         struct read_packet_state *state =
     588     1136609 :                 tevent_req_data(req, struct read_packet_state);
     589             : 
     590     1136609 :         if (tevent_req_is_unix_error(req, perrno)) {
     591        8376 :                 tevent_req_received(req);
     592        8376 :                 return -1;
     593             :         }
     594     1128233 :         *pbuf = talloc_move(mem_ctx, &state->buf);
     595     1128233 :         tevent_req_received(req);
     596     1128233 :         return talloc_get_size(*pbuf);
     597             : }
     598             : 
     599             : struct wait_for_read_state {
     600             :         struct tevent_fd *fde;
     601             :         int fd;
     602             :         bool check_errors;
     603             : };
     604             : 
     605             : static void wait_for_read_cleanup(struct tevent_req *req,
     606             :                                   enum tevent_req_state req_state);
     607             : static void wait_for_read_done(struct tevent_context *ev,
     608             :                                struct tevent_fd *fde,
     609             :                                uint16_t flags,
     610             :                                void *private_data);
     611             : 
     612       74434 : struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
     613             :                                       struct tevent_context *ev, int fd,
     614             :                                       bool check_errors)
     615             : {
     616             :         struct tevent_req *req;
     617             :         struct wait_for_read_state *state;
     618             : 
     619       74434 :         req = tevent_req_create(mem_ctx, &state, struct wait_for_read_state);
     620       74434 :         if (req == NULL) {
     621           0 :                 return NULL;
     622             :         }
     623             : 
     624       74434 :         tevent_req_set_cleanup_fn(req, wait_for_read_cleanup);
     625             : 
     626       74434 :         state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
     627             :                                    wait_for_read_done, req);
     628       74434 :         if (tevent_req_nomem(state->fde, req)) {
     629           0 :                 return tevent_req_post(req, ev);
     630             :         }
     631             : 
     632       74434 :         state->fd = fd;
     633       74434 :         state->check_errors = check_errors;
     634       74434 :         return req;
     635             : }
     636             : 
     637       74952 : static void wait_for_read_cleanup(struct tevent_req *req,
     638             :                                   enum tevent_req_state req_state)
     639             : {
     640       45697 :         struct wait_for_read_state *state =
     641       74952 :                 tevent_req_data(req, struct wait_for_read_state);
     642             : 
     643       74952 :         TALLOC_FREE(state->fde);
     644       74952 : }
     645             : 
     646         544 : static void wait_for_read_done(struct tevent_context *ev,
     647             :                                struct tevent_fd *fde,
     648             :                                uint16_t flags,
     649             :                                void *private_data)
     650             : {
     651         544 :         struct tevent_req *req = talloc_get_type_abort(
     652             :                 private_data, struct tevent_req);
     653         368 :         struct wait_for_read_state *state =
     654         544 :             tevent_req_data(req, struct wait_for_read_state);
     655             :         int ret, available;
     656             : 
     657         544 :         if ((flags & TEVENT_FD_READ) == 0) {
     658         544 :                 return;
     659             :         }
     660             : 
     661         544 :         if (!state->check_errors) {
     662         544 :                 tevent_req_done(req);
     663         544 :                 return;
     664             :         }
     665             : 
     666           0 :         ret = ioctl(state->fd, FIONREAD, &available);
     667             : 
     668           0 :         if ((ret == -1) && (errno == EINTR)) {
     669             :                 /* come back later */
     670           0 :                 return;
     671             :         }
     672             : 
     673           0 :         if (ret == -1) {
     674           0 :                 tevent_req_error(req, errno);
     675           0 :                 return;
     676             :         }
     677             : 
     678           0 :         if (available == 0) {
     679           0 :                 tevent_req_error(req, EPIPE);
     680           0 :                 return;
     681             :         }
     682             : 
     683           0 :         tevent_req_done(req);
     684             : }
     685             : 
     686         544 : bool wait_for_read_recv(struct tevent_req *req, int *perr)
     687             : {
     688         544 :         int err = tevent_req_simple_recv_unix(req);
     689             : 
     690         544 :         if (err != 0) {
     691           0 :                 *perr = err;
     692           0 :                 return false;
     693             :         }
     694             : 
     695         544 :         return true;
     696             : }
     697             : 
     698             : struct accept_state {
     699             :         struct tevent_fd *fde;
     700             :         int listen_sock;
     701             :         struct samba_sockaddr addr;
     702             :         int sock;
     703             : };
     704             : 
     705             : static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
     706             :                            uint16_t flags, void *private_data);
     707             : 
     708        1505 : struct tevent_req *accept_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     709             :                                int listen_sock)
     710             : {
     711             :         struct tevent_req *req;
     712             :         struct accept_state *state;
     713             : 
     714        1505 :         req = tevent_req_create(mem_ctx, &state, struct accept_state);
     715        1505 :         if (req == NULL) {
     716           0 :                 return NULL;
     717             :         }
     718             : 
     719        1505 :         state->listen_sock = listen_sock;
     720             : 
     721        1505 :         state->fde = tevent_add_fd(ev, state, listen_sock, TEVENT_FD_READ,
     722             :                                    accept_handler, req);
     723        1505 :         if (tevent_req_nomem(state->fde, req)) {
     724           0 :                 return tevent_req_post(req, ev);
     725             :         }
     726        1505 :         return req;
     727             : }
     728             : 
     729         817 : static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
     730             :                            uint16_t flags, void *private_data)
     731             : {
     732         817 :         struct tevent_req *req = talloc_get_type_abort(
     733             :                 private_data, struct tevent_req);
     734         817 :         struct accept_state *state = tevent_req_data(req, struct accept_state);
     735             :         int ret;
     736             : 
     737         817 :         TALLOC_FREE(state->fde);
     738             : 
     739         817 :         if ((flags & TEVENT_FD_READ) == 0) {
     740           0 :                 tevent_req_error(req, EIO);
     741           0 :                 return;
     742             :         }
     743             : 
     744         817 :         state->addr.sa_socklen = sizeof(state->addr.u);
     745             : 
     746        1265 :         ret = accept(state->listen_sock,
     747         817 :                      &state->addr.u.sa,
     748             :                      &state->addr.sa_socklen);
     749         817 :         if ((ret == -1) && (errno == EINTR)) {
     750             :                 /* retry */
     751           0 :                 return;
     752             :         }
     753         817 :         if (ret == -1) {
     754           0 :                 tevent_req_error(req, errno);
     755           0 :                 return;
     756             :         }
     757         817 :         smb_set_close_on_exec(ret);
     758         817 :         state->sock = ret;
     759         817 :         tevent_req_done(req);
     760             : }
     761             : 
     762         817 : int accept_recv(struct tevent_req *req,
     763             :                 int *listen_sock,
     764             :                 struct samba_sockaddr *paddr,
     765             :                 int *perr)
     766             : {
     767         817 :         struct accept_state *state = tevent_req_data(req, struct accept_state);
     768         817 :         int sock = state->sock;
     769             :         int err;
     770             : 
     771         817 :         if (tevent_req_is_unix_error(req, &err)) {
     772           0 :                 if (perr != NULL) {
     773           0 :                         *perr = err;
     774             :                 }
     775           0 :                 tevent_req_received(req);
     776           0 :                 return -1;
     777             :         }
     778         817 :         if (listen_sock != NULL) {
     779         817 :                 *listen_sock = state->listen_sock;
     780             :         }
     781         817 :         if (paddr != NULL) {
     782         817 :                 *paddr = state->addr;
     783             :         }
     784         817 :         tevent_req_received(req);
     785         817 :         return sock;
     786             : }

Generated by: LCOV version 1.13