LCOV - code coverage report
Current view: top level - lib/async_req - async_sock.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 256 331 77.3 %
Date: 2023-11-21 12:31:41 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       65901 : 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         620 :         struct tevent_req *req;
      77         620 :         struct async_connect_state *state;
      78         620 :         int ret;
      79             : 
      80       65901 :         req = tevent_req_create(mem_ctx, &state, struct async_connect_state);
      81       65901 :         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       65901 :         state->fd = fd;
      91       65901 :         state->before_connect = before_connect;
      92       65901 :         state->after_connect = after_connect;
      93       65901 :         state->private_data = private_data;
      94             : 
      95       65901 :         state->old_sockflags = fcntl(fd, F_GETFL, 0);
      96       65901 :         if (state->old_sockflags == -1) {
      97           0 :                 tevent_req_error(req, errno);
      98           0 :                 return tevent_req_post(req, ev);
      99             :         }
     100             : 
     101       65901 :         tevent_req_set_cleanup_fn(req, async_connect_cleanup);
     102             : 
     103       65901 :         state->address_len = address_len;
     104       65901 :         if (address_len > sizeof(state->address)) {
     105           0 :                 tevent_req_error(req, EINVAL);
     106           0 :                 return tevent_req_post(req, ev);
     107             :         }
     108       65901 :         memcpy(&state->address, address, address_len);
     109             : 
     110       65901 :         ret = set_blocking(fd, false);
     111       65901 :         if (ret == -1) {
     112           0 :                 tevent_req_error(req, errno);
     113           0 :                 return tevent_req_post(req, ev);
     114             :         }
     115             : 
     116       65901 :         if (state->before_connect != NULL) {
     117       47747 :                 state->before_connect(state->private_data);
     118             :         }
     119             : 
     120       65901 :         state->result = connect(fd, address, address_len);
     121             : 
     122       65901 :         if (state->after_connect != NULL) {
     123       47747 :                 state->after_connect(state->private_data);
     124             :         }
     125             : 
     126       65901 :         if (state->result == 0) {
     127       65629 :                 tevent_req_done(req);
     128       65629 :                 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         272 :         if (errno != EINPROGRESS) {
     143         272 :                 tevent_req_error(req, errno);
     144         272 :                 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,
     155             :                                    TEVENT_FD_ERROR|TEVENT_FD_WRITE,
     156             :                                    async_connect_connected, req);
     157           0 :         if (state->fde == NULL) {
     158           0 :                 tevent_req_error(req, ENOMEM);
     159           0 :                 return tevent_req_post(req, ev);
     160             :         }
     161           0 :         return req;
     162             : }
     163             : 
     164      131802 : static void async_connect_cleanup(struct tevent_req *req,
     165             :                                   enum tevent_req_state req_state)
     166             : {
     167        1240 :         struct async_connect_state *state =
     168      131802 :                 tevent_req_data(req, struct async_connect_state);
     169             : 
     170      131802 :         TALLOC_FREE(state->fde);
     171      131802 :         if (state->fd != -1) {
     172         620 :                 int ret;
     173             : 
     174       65901 :                 ret = fcntl(state->fd, F_SETFL, state->old_sockflags);
     175       65901 :                 if (ret == -1) {
     176           0 :                         abort();
     177             :                 }
     178             : 
     179       65901 :                 state->fd = -1;
     180             :         }
     181      131802 : }
     182             : 
     183             : /**
     184             :  * fde event handler for connect(2)
     185             :  * @param[in] ev        The event context that sent us here
     186             :  * @param[in] fde       The file descriptor event associated with the connect
     187             :  * @param[in] flags     Indicate read/writeability of the socket
     188             :  * @param[in] priv      private data, "struct async_req *" in this case
     189             :  */
     190             : 
     191           0 : static void async_connect_connected(struct tevent_context *ev,
     192             :                                     struct tevent_fd *fde, uint16_t flags,
     193             :                                     void *priv)
     194             : {
     195           0 :         struct tevent_req *req = talloc_get_type_abort(
     196             :                 priv, struct tevent_req);
     197           0 :         struct async_connect_state *state =
     198           0 :                 tevent_req_data(req, struct async_connect_state);
     199           0 :         int ret;
     200           0 :         int socket_error = 0;
     201           0 :         socklen_t slen = sizeof(socket_error);
     202             : 
     203           0 :         ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
     204             :                          &socket_error, &slen);
     205             : 
     206           0 :         if (ret != 0) {
     207             :                 /*
     208             :                  * According to Stevens this is the Solaris behaviour
     209             :                  * in case the connection encountered an error:
     210             :                  * getsockopt() fails, error is in errno
     211             :                  */
     212           0 :                 tevent_req_error(req, errno);
     213           0 :                 return;
     214             :         }
     215             : 
     216           0 :         if (socket_error != 0) {
     217             :                 /*
     218             :                  * Berkeley derived implementations (including) Linux
     219             :                  * return the pending error via socket_error.
     220             :                  */
     221           0 :                 tevent_req_error(req, socket_error);
     222           0 :                 return;
     223             :         }
     224             : 
     225           0 :         tevent_req_done(req);
     226           0 :         return;
     227             : }
     228             : 
     229       65901 : int async_connect_recv(struct tevent_req *req, int *perrno)
     230             : {
     231       65901 :         int err = tevent_req_simple_recv_unix(req);
     232             : 
     233       65901 :         if (err != 0) {
     234         272 :                 *perrno = err;
     235         272 :                 return -1;
     236             :         }
     237             : 
     238       65009 :         return 0;
     239             : }
     240             : 
     241             : struct writev_state {
     242             :         struct tevent_context *ev;
     243             :         struct tevent_queue_entry *queue_entry;
     244             :         int fd;
     245             :         struct tevent_fd *fde;
     246             :         struct iovec *iov;
     247             :         int count;
     248             :         size_t total_size;
     249             :         uint16_t flags;
     250             :         bool err_on_readability;
     251             : };
     252             : 
     253             : static void writev_cleanup(struct tevent_req *req,
     254             :                            enum tevent_req_state req_state);
     255             : static bool writev_cancel(struct tevent_req *req);
     256             : static void writev_trigger(struct tevent_req *req, void *private_data);
     257             : static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
     258             :                            uint16_t flags, void *private_data);
     259             : 
     260     3159315 : struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     261             :                                struct tevent_queue *queue, int fd,
     262             :                                bool err_on_readability,
     263             :                                struct iovec *iov, int count)
     264             : {
     265       20419 :         struct tevent_req *req;
     266       20419 :         struct writev_state *state;
     267             : 
     268     3159315 :         req = tevent_req_create(mem_ctx, &state, struct writev_state);
     269     3159315 :         if (req == NULL) {
     270           0 :                 return NULL;
     271             :         }
     272     3159315 :         state->ev = ev;
     273     3159315 :         state->fd = fd;
     274     3159315 :         state->total_size = 0;
     275     3159315 :         state->count = count;
     276     3159315 :         state->iov = (struct iovec *)talloc_memdup(
     277             :                 state, iov, sizeof(struct iovec) * count);
     278     3159315 :         if (tevent_req_nomem(state->iov, req)) {
     279           0 :                 return tevent_req_post(req, ev);
     280             :         }
     281     3159315 :         state->flags = TEVENT_FD_WRITE | TEVENT_FD_ERROR;
     282     3159315 :         if (err_on_readability) {
     283      342427 :                 state->flags |= TEVENT_FD_READ;
     284             :         }
     285             : 
     286     3159315 :         tevent_req_set_cleanup_fn(req, writev_cleanup);
     287     3159315 :         tevent_req_set_cancel_fn(req, writev_cancel);
     288             : 
     289     3159315 :         if (queue == NULL) {
     290      122042 :                 state->fde = tevent_add_fd(state->ev, state, state->fd,
     291             :                                     state->flags, writev_handler, req);
     292      122042 :                 if (tevent_req_nomem(state->fde, req)) {
     293           0 :                         return tevent_req_post(req, ev);
     294             :                 }
     295      122042 :                 return req;
     296             :         }
     297             : 
     298             :         /*
     299             :          * writev_trigger tries a nonblocking write. If that succeeds,
     300             :          * we can't directly notify the callback to call
     301             :          * writev_recv. The callback would TALLOC_FREE(req) after
     302             :          * calling writev_recv even before writev_trigger can inspect
     303             :          * it for success.
     304             :          */
     305     3037273 :         tevent_req_defer_callback(req, ev);
     306             : 
     307     3037273 :         state->queue_entry = tevent_queue_add_optimize_empty(
     308             :                 queue, ev, req, writev_trigger, NULL);
     309     3037273 :         if (tevent_req_nomem(state->queue_entry, req)) {
     310           0 :                 return tevent_req_post(req, ev);
     311             :         }
     312     3037273 :         if (!tevent_req_is_in_progress(req)) {
     313     2995098 :                 return tevent_req_post(req, ev);
     314             :         }
     315       41186 :         return req;
     316             : }
     317             : 
     318     6318630 : static void writev_cleanup(struct tevent_req *req,
     319             :                            enum tevent_req_state req_state)
     320             : {
     321     6318630 :         struct writev_state *state = tevent_req_data(req, struct writev_state);
     322             : 
     323     6318630 :         TALLOC_FREE(state->queue_entry);
     324     6318630 :         TALLOC_FREE(state->fde);
     325     6318630 : }
     326             : 
     327        6978 : static bool writev_cancel(struct tevent_req *req)
     328             : {
     329        6978 :         struct writev_state *state = tevent_req_data(req, struct writev_state);
     330             : 
     331        6978 :         if (state->total_size > 0) {
     332             :                 /*
     333             :                  * We've already started to write :-(
     334             :                  */
     335        6086 :                 return false;
     336             :         }
     337             : 
     338         505 :         TALLOC_FREE(state->queue_entry);
     339         505 :         TALLOC_FREE(state->fde);
     340             : 
     341         505 :         tevent_req_defer_callback(req, state->ev);
     342         505 :         tevent_req_error(req, ECANCELED);
     343         505 :         return true;
     344             : }
     345             : 
     346     3681424 : static void writev_do(struct tevent_req *req, struct writev_state *state)
     347             : {
     348       23236 :         ssize_t written;
     349       23236 :         bool ok;
     350             : 
     351     3681424 :         written = writev(state->fd, state->iov, state->count);
     352     3681424 :         if ((written == -1) &&
     353           2 :             ((errno == EINTR) ||
     354           2 :              (errno == EAGAIN) ||
     355           2 :              (errno == EWOULDBLOCK))) {
     356             :                 /* retry after going through the tevent loop */
     357           0 :                 return;
     358             :         }
     359     3681424 :         if (written == -1) {
     360           2 :                 tevent_req_error(req, errno);
     361           2 :                 return;
     362             :         }
     363     3681422 :         if (written == 0) {
     364           0 :                 tevent_req_error(req, EPIPE);
     365           0 :                 return;
     366             :         }
     367     3681422 :         state->total_size += written;
     368             : 
     369     3681422 :         ok = iov_advance(&state->iov, &state->count, written);
     370     3681422 :         if (!ok) {
     371           0 :                 tevent_req_error(req, EIO);
     372           0 :                 return;
     373             :         }
     374             : 
     375     3681422 :         if (state->count == 0) {
     376     3158808 :                 tevent_req_done(req);
     377     3158808 :                 return;
     378             :         }
     379             : }
     380             : 
     381     3036768 : static void writev_trigger(struct tevent_req *req, void *private_data)
     382             : {
     383     3036768 :         struct writev_state *state = tevent_req_data(req, struct writev_state);
     384             : 
     385     3036768 :         state->queue_entry = NULL;
     386             : 
     387     3036768 :         writev_do(req, state);
     388     3036768 :         if (!tevent_req_is_in_progress(req)) {
     389     2982679 :                 return;
     390             :         }
     391             : 
     392       34657 :         state->fde = tevent_add_fd(state->ev, state, state->fd, state->flags,
     393             :                             writev_handler, req);
     394       34657 :         if (tevent_req_nomem(state->fde, req)) {
     395           0 :                 return;
     396             :         }
     397             : }
     398             : 
     399      644656 : static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
     400             :                            uint16_t flags, void *private_data)
     401             : {
     402      644656 :         struct tevent_req *req = talloc_get_type_abort(
     403             :                 private_data, struct tevent_req);
     404        2892 :         struct writev_state *state =
     405      644656 :                 tevent_req_data(req, struct writev_state);
     406             : 
     407      644656 :         if (flags & TEVENT_FD_ERROR) {
     408             :                 /*
     409             :                  * There's an error, for legacy reasons
     410             :                  * we just use EPIPE instead of a more
     411             :                  * detailed error using
     412             :                  * samba_socket_poll_or_sock_error().
     413             :                  */
     414           0 :                 tevent_req_error(req, EPIPE);
     415           0 :                 return;
     416             :         }
     417             : 
     418      644656 :         if (flags & TEVENT_FD_READ) {
     419             :                 /* Readable and the caller wants an error on read. */
     420           0 :                 tevent_req_error(req, EPIPE);
     421           0 :                 return;
     422             :         }
     423             : 
     424      644656 :         writev_do(req, state);
     425             : }
     426             : 
     427     3158810 : ssize_t writev_recv(struct tevent_req *req, int *perrno)
     428             : {
     429       20344 :         struct writev_state *state =
     430     3158810 :                 tevent_req_data(req, struct writev_state);
     431       20344 :         ssize_t ret;
     432             : 
     433     3158810 :         if (tevent_req_is_unix_error(req, perrno)) {
     434           2 :                 tevent_req_received(req);
     435           2 :                 return -1;
     436             :         }
     437     3158808 :         ret = state->total_size;
     438     3158808 :         tevent_req_received(req);
     439     3158808 :         return ret;
     440             : }
     441             : 
     442             : struct read_packet_state {
     443             :         int fd;
     444             :         struct tevent_fd *fde;
     445             :         uint8_t *buf;
     446             :         size_t nread;
     447             :         ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
     448             :         void *private_data;
     449             : };
     450             : 
     451             : static void read_packet_cleanup(struct tevent_req *req,
     452             :                                  enum tevent_req_state req_state);
     453             : static void read_packet_handler(struct tevent_context *ev,
     454             :                                 struct tevent_fd *fde,
     455             :                                 uint16_t flags, void *private_data);
     456             : 
     457     3390344 : struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
     458             :                                     struct tevent_context *ev,
     459             :                                     int fd, size_t initial,
     460             :                                     ssize_t (*more)(uint8_t *buf,
     461             :                                                     size_t buflen,
     462             :                                                     void *private_data),
     463             :                                     void *private_data)
     464             : {
     465       24513 :         struct tevent_req *req;
     466       24513 :         struct read_packet_state *state;
     467             : 
     468     3390344 :         req = tevent_req_create(mem_ctx, &state, struct read_packet_state);
     469     3390344 :         if (req == NULL) {
     470           0 :                 return NULL;
     471             :         }
     472     3390344 :         state->fd = fd;
     473     3390344 :         state->nread = 0;
     474     3390344 :         state->more = more;
     475     3390344 :         state->private_data = private_data;
     476             : 
     477     3390344 :         tevent_req_set_cleanup_fn(req, read_packet_cleanup);
     478             : 
     479     3390344 :         state->buf = talloc_array(state, uint8_t, initial);
     480     3390344 :         if (tevent_req_nomem(state->buf, req)) {
     481           0 :                 return tevent_req_post(req, ev);
     482             :         }
     483             : 
     484     3390344 :         state->fde = tevent_add_fd(ev, state, fd,
     485             :                                    TEVENT_FD_READ, read_packet_handler,
     486             :                                    req);
     487     3390344 :         if (tevent_req_nomem(state->fde, req)) {
     488           0 :                 return tevent_req_post(req, ev);
     489             :         }
     490     3365831 :         return req;
     491             : }
     492             : 
     493     6686028 : static void read_packet_cleanup(struct tevent_req *req,
     494             :                            enum tevent_req_state req_state)
     495             : {
     496       47354 :         struct read_packet_state *state =
     497     6686028 :                 tevent_req_data(req, struct read_packet_state);
     498             : 
     499     6686028 :         TALLOC_FREE(state->fde);
     500     6686028 : }
     501             : 
     502     7079082 : static void read_packet_handler(struct tevent_context *ev,
     503             :                                 struct tevent_fd *fde,
     504             :                                 uint16_t flags, void *private_data)
     505             : {
     506     7079082 :         struct tevent_req *req = talloc_get_type_abort(
     507             :                 private_data, struct tevent_req);
     508       46100 :         struct read_packet_state *state =
     509     7079082 :                 tevent_req_data(req, struct read_packet_state);
     510     7079082 :         size_t total = talloc_get_size(state->buf);
     511       46100 :         ssize_t nread, more;
     512       46100 :         uint8_t *tmp;
     513             : 
     514     7079082 :         nread = recv(state->fd, state->buf+state->nread, total-state->nread,
     515             :                      0);
     516     7079082 :         if ((nread == -1) && (errno == ENOTSOCK)) {
     517       46268 :                 nread = read(state->fd, state->buf+state->nread,
     518         168 :                              total-state->nread);
     519             :         }
     520     7079082 :         if ((nread == -1) && (errno == EINTR)) {
     521             :                 /* retry */
     522           0 :                 return;
     523             :         }
     524     7079082 :         if (nread == -1) {
     525           6 :                 tevent_req_error(req, errno);
     526           6 :                 return;
     527             :         }
     528     7079076 :         if (nread == 0) {
     529        8125 :                 tevent_req_error(req, EPIPE);
     530        8125 :                 return;
     531             :         }
     532             : 
     533     7070951 :         state->nread += nread;
     534     7070951 :         if (state->nread < total) {
     535             :                 /* Come back later */
     536      512701 :                 return;
     537             :         }
     538             : 
     539             :         /*
     540             :          * We got what was initially requested. See if "more" asks for -- more.
     541             :          */
     542     6557832 :         if (state->more == NULL) {
     543             :                 /* Nobody to ask, this is a async read_data */
     544       26108 :                 tevent_req_done(req);
     545       26108 :                 return;
     546             :         }
     547             : 
     548     6531724 :         more = state->more(state->buf, total, state->private_data);
     549     6531724 :         if (more == -1) {
     550             :                 /* We got an invalid packet, tell the caller */
     551           0 :                 tevent_req_error(req, EIO);
     552           0 :                 return;
     553             :         }
     554     6531724 :         if (more == 0) {
     555             :                 /* We're done, full packet received */
     556     3261480 :                 tevent_req_done(req);
     557     3261480 :                 return;
     558             :         }
     559             : 
     560     3270244 :         if (total + more < total) {
     561           0 :                 tevent_req_error(req, EMSGSIZE);
     562           0 :                 return;
     563             :         }
     564             : 
     565     3270244 :         tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
     566     3270244 :         if (tevent_req_nomem(tmp, req)) {
     567           0 :                 return;
     568             :         }
     569     3270244 :         state->buf = tmp;
     570             : }
     571             : 
     572     3295719 : ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     573             :                          uint8_t **pbuf, int *perrno)
     574             : {
     575       22841 :         struct read_packet_state *state =
     576     3295719 :                 tevent_req_data(req, struct read_packet_state);
     577             : 
     578     3295719 :         if (tevent_req_is_unix_error(req, perrno)) {
     579        8131 :                 tevent_req_received(req);
     580        8131 :                 return -1;
     581             :         }
     582     3287588 :         *pbuf = talloc_move(mem_ctx, &state->buf);
     583     3287588 :         tevent_req_received(req);
     584     3287588 :         return talloc_get_size(*pbuf);
     585             : }
     586             : 
     587             : struct wait_for_read_state {
     588             :         struct tevent_fd *fde;
     589             :         int fd;
     590             :         bool check_errors;
     591             : };
     592             : 
     593             : static void wait_for_read_cleanup(struct tevent_req *req,
     594             :                                   enum tevent_req_state req_state);
     595             : static void wait_for_read_done(struct tevent_context *ev,
     596             :                                struct tevent_fd *fde,
     597             :                                uint16_t flags,
     598             :                                void *private_data);
     599             : 
     600      265277 : struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
     601             :                                       struct tevent_context *ev, int fd,
     602             :                                       bool check_errors)
     603             : {
     604           5 :         struct tevent_req *req;
     605           5 :         struct wait_for_read_state *state;
     606             : 
     607      265277 :         req = tevent_req_create(mem_ctx, &state, struct wait_for_read_state);
     608      265277 :         if (req == NULL) {
     609           0 :                 return NULL;
     610             :         }
     611             : 
     612      265277 :         tevent_req_set_cleanup_fn(req, wait_for_read_cleanup);
     613             : 
     614      265277 :         state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
     615             :                                    wait_for_read_done, req);
     616      265277 :         if (tevent_req_nomem(state->fde, req)) {
     617           0 :                 return tevent_req_post(req, ev);
     618             :         }
     619             : 
     620      265277 :         state->fd = fd;
     621      265277 :         state->check_errors = check_errors;
     622      265277 :         return req;
     623             : }
     624             : 
     625      266726 : static void wait_for_read_cleanup(struct tevent_req *req,
     626             :                                   enum tevent_req_state req_state)
     627             : {
     628           5 :         struct wait_for_read_state *state =
     629      266726 :                 tevent_req_data(req, struct wait_for_read_state);
     630             : 
     631      266726 :         TALLOC_FREE(state->fde);
     632      266726 : }
     633             : 
     634        1454 : static void wait_for_read_done(struct tevent_context *ev,
     635             :                                struct tevent_fd *fde,
     636             :                                uint16_t flags,
     637             :                                void *private_data)
     638             : {
     639        1454 :         struct tevent_req *req = talloc_get_type_abort(
     640             :                 private_data, struct tevent_req);
     641           5 :         struct wait_for_read_state *state =
     642        1454 :             tevent_req_data(req, struct wait_for_read_state);
     643           5 :         int ret, available;
     644             : 
     645        1454 :         if ((flags & TEVENT_FD_READ) == 0) {
     646        1454 :                 return;
     647             :         }
     648             : 
     649        1454 :         if (!state->check_errors) {
     650        1448 :                 tevent_req_done(req);
     651        1448 :                 return;
     652             :         }
     653             : 
     654           6 :         ret = ioctl(state->fd, FIONREAD, &available);
     655             : 
     656           6 :         if ((ret == -1) && (errno == EINTR)) {
     657             :                 /* come back later */
     658           0 :                 return;
     659             :         }
     660             : 
     661           6 :         if (ret == -1) {
     662           0 :                 tevent_req_error(req, errno);
     663           0 :                 return;
     664             :         }
     665             : 
     666           6 :         if (available == 0) {
     667           6 :                 tevent_req_error(req, EPIPE);
     668           6 :                 return;
     669             :         }
     670             : 
     671           0 :         tevent_req_done(req);
     672             : }
     673             : 
     674        1443 : bool wait_for_read_recv(struct tevent_req *req, int *perr)
     675             : {
     676        1443 :         int err = tevent_req_simple_recv_unix(req);
     677             : 
     678        1443 :         if (err != 0) {
     679           0 :                 *perr = err;
     680           0 :                 return false;
     681             :         }
     682             : 
     683        1443 :         return true;
     684             : }
     685             : 
     686             : struct accept_state {
     687             :         struct tevent_fd *fde;
     688             :         int listen_sock;
     689             :         struct samba_sockaddr addr;
     690             :         int sock;
     691             : };
     692             : 
     693             : static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
     694             :                            uint16_t flags, void *private_data);
     695             : 
     696       44630 : struct tevent_req *accept_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     697             :                                int listen_sock)
     698             : {
     699           0 :         struct tevent_req *req;
     700           0 :         struct accept_state *state;
     701             : 
     702       44630 :         req = tevent_req_create(mem_ctx, &state, struct accept_state);
     703       44630 :         if (req == NULL) {
     704           0 :                 return NULL;
     705             :         }
     706             : 
     707       44630 :         state->listen_sock = listen_sock;
     708             : 
     709       44630 :         state->fde = tevent_add_fd(ev, state, listen_sock, TEVENT_FD_READ,
     710             :                                    accept_handler, req);
     711       44630 :         if (tevent_req_nomem(state->fde, req)) {
     712           0 :                 return tevent_req_post(req, ev);
     713             :         }
     714       44630 :         return req;
     715             : }
     716             : 
     717       43003 : static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
     718             :                            uint16_t flags, void *private_data)
     719             : {
     720       43003 :         struct tevent_req *req = talloc_get_type_abort(
     721             :                 private_data, struct tevent_req);
     722       43003 :         struct accept_state *state = tevent_req_data(req, struct accept_state);
     723           0 :         int ret;
     724             : 
     725       43003 :         TALLOC_FREE(state->fde);
     726             : 
     727       43003 :         if ((flags & TEVENT_FD_READ) == 0) {
     728           0 :                 tevent_req_error(req, EIO);
     729           0 :                 return;
     730             :         }
     731             : 
     732       43003 :         state->addr.sa_socklen = sizeof(state->addr.u);
     733             : 
     734       43003 :         ret = accept(state->listen_sock,
     735       43003 :                      &state->addr.u.sa,
     736             :                      &state->addr.sa_socklen);
     737       43003 :         if ((ret == -1) && (errno == EINTR)) {
     738             :                 /* retry */
     739           0 :                 return;
     740             :         }
     741       43003 :         if (ret == -1) {
     742           0 :                 tevent_req_error(req, errno);
     743           0 :                 return;
     744             :         }
     745       43003 :         smb_set_close_on_exec(ret);
     746       43003 :         state->sock = ret;
     747       43003 :         tevent_req_done(req);
     748             : }
     749             : 
     750       43003 : int accept_recv(struct tevent_req *req,
     751             :                 int *listen_sock,
     752             :                 struct samba_sockaddr *paddr,
     753             :                 int *perr)
     754             : {
     755       43003 :         struct accept_state *state = tevent_req_data(req, struct accept_state);
     756       43003 :         int sock = state->sock;
     757           0 :         int err;
     758             : 
     759       43003 :         if (tevent_req_is_unix_error(req, &err)) {
     760           0 :                 if (perr != NULL) {
     761           0 :                         *perr = err;
     762             :                 }
     763           0 :                 tevent_req_received(req);
     764           0 :                 return -1;
     765             :         }
     766       43003 :         if (listen_sock != NULL) {
     767       43003 :                 *listen_sock = state->listen_sock;
     768             :         }
     769       43003 :         if (paddr != NULL) {
     770       43003 :                 *paddr = state->addr;
     771             :         }
     772       43003 :         tevent_req_received(req);
     773       43003 :         return sock;
     774             : }

Generated by: LCOV version 1.14