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

Generated by: LCOV version 1.14