Remove unused recvall
[Samba.git] / lib / async_req / async_sock.c
blob86f89c159a6708b104eaa891fa050a1ac06f2ee2
1 /*
2 Unix SMB/CIFS implementation.
3 async socket syscalls
4 Copyright (C) Volker Lendecke 2008
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "lib/talloc/talloc.h"
22 #include "lib/tevent/tevent.h"
23 #include "lib/async_req/async_req.h"
24 #include "lib/async_req/async_sock.h"
25 #include "lib/util/tevent_unix.h"
26 #include <fcntl.h>
28 #ifndef TALLOC_FREE
29 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
30 #endif
32 /**
33 * Discriminator for async_syscall_state
35 enum async_syscall_type {
36 ASYNC_SYSCALL_SEND,
37 ASYNC_SYSCALL_RECV,
38 ASYNC_SYSCALL_CONNECT
41 /**
42 * Holder for syscall arguments and the result
45 struct async_syscall_state {
46 enum async_syscall_type syscall_type;
47 struct tevent_fd *fde;
49 union {
50 struct param_send {
51 int fd;
52 const void *buffer;
53 size_t length;
54 int flags;
55 } param_send;
56 struct param_recv {
57 int fd;
58 void *buffer;
59 size_t length;
60 int flags;
61 } param_recv;
62 struct param_connect {
63 /**
64 * connect needs to be done on a nonblocking
65 * socket. Keep the old flags around
67 long old_sockflags;
68 int fd;
69 const struct sockaddr *address;
70 socklen_t address_len;
71 } param_connect;
72 } param;
74 union {
75 ssize_t result_ssize_t;
76 size_t result_size_t;
77 int result_int;
78 } result;
79 int sys_errno;
82 /**
83 * @brief Map async_req states to unix-style errnos
84 * @param[in] req The async req to get the state from
85 * @param[out] err Pointer to take the unix-style errno
87 * @return true if the async_req is in an error state, false otherwise
90 bool async_req_is_errno(struct async_req *req, int *err)
92 enum async_req_state state;
93 uint64_t error;
95 if (!async_req_is_error(req, &state, &error)) {
96 return false;
99 switch (state) {
100 case ASYNC_REQ_USER_ERROR:
101 *err = (int)error;
102 break;
103 case ASYNC_REQ_TIMED_OUT:
104 #ifdef ETIMEDOUT
105 *err = ETIMEDOUT;
106 #else
107 *err = EAGAIN;
108 #endif
109 break;
110 case ASYNC_REQ_NO_MEMORY:
111 *err = ENOMEM;
112 break;
113 default:
114 *err = EIO;
115 break;
117 return true;
120 int async_req_simple_recv_errno(struct async_req *req)
122 int err;
124 if (async_req_is_errno(req, &err)) {
125 return err;
128 return 0;
132 * @brief Create a new async syscall req
133 * @param[in] mem_ctx The memory context to hang the result off
134 * @param[in] ev The event context to work from
135 * @param[in] type Which syscall will this be
136 * @param[in] pstate Where to put the newly created private_data state
137 * @retval The new request
139 * This is a helper function to prepare a new struct async_req with an
140 * associated struct async_syscall_state. The async_syscall_state will be put
141 * into the async_req as private_data.
144 static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx,
145 struct tevent_context *ev,
146 enum async_syscall_type type,
147 struct async_syscall_state **pstate)
149 struct async_req *result;
150 struct async_syscall_state *state;
152 if (!async_req_setup(mem_ctx, &result, &state,
153 struct async_syscall_state)) {
154 return NULL;
156 state->syscall_type = type;
158 result->private_data = state;
160 *pstate = state;
162 return result;
166 * @brief Create a new async syscall req based on a fd
167 * @param[in] mem_ctx The memory context to hang the result off
168 * @param[in] ev The event context to work from
169 * @param[in] type Which syscall will this be
170 * @param[in] fd The file descriptor we work on
171 * @param[in] fde_flags TEVENT_FD_READ/WRITE -- what are we interested in?
172 * @param[in] fde_cb The callback function for the file descriptor event
173 * @param[in] pstate Where to put the newly created private_data state
174 * @retval The new request
176 * This is a helper function to prepare a new struct async_req with an
177 * associated struct async_syscall_state and an associated file descriptor
178 * event.
181 static struct async_req *async_fde_syscall_new(
182 TALLOC_CTX *mem_ctx,
183 struct tevent_context *ev,
184 enum async_syscall_type type,
185 int fd,
186 uint16_t fde_flags,
187 void (*fde_cb)(struct tevent_context *ev,
188 struct tevent_fd *fde, uint16_t flags,
189 void *priv),
190 struct async_syscall_state **pstate)
192 struct async_req *result;
193 struct async_syscall_state *state;
195 result = async_syscall_new(mem_ctx, ev, type, &state);
196 if (result == NULL) {
197 return NULL;
200 state->fde = tevent_add_fd(ev, state, fd, fde_flags, fde_cb, result);
201 if (state->fde == NULL) {
202 TALLOC_FREE(result);
203 return NULL;
205 *pstate = state;
206 return result;
210 * Retrieve a ssize_t typed result from an async syscall
211 * @param[in] req The syscall that has just finished
212 * @param[out] perrno Where to put the syscall's errno
213 * @retval The return value from the asynchronously called syscall
216 ssize_t async_syscall_result_ssize_t(struct async_req *req, int *perrno)
218 struct async_syscall_state *state = talloc_get_type_abort(
219 req->private_data, struct async_syscall_state);
221 *perrno = state->sys_errno;
222 return state->result.result_ssize_t;
226 * Retrieve a size_t typed result from an async syscall
227 * @param[in] req The syscall that has just finished
228 * @param[out] perrno Where to put the syscall's errno
229 * @retval The return value from the asynchronously called syscall
232 size_t async_syscall_result_size_t(struct async_req *req, int *perrno)
234 struct async_syscall_state *state = talloc_get_type_abort(
235 req->private_data, struct async_syscall_state);
237 *perrno = state->sys_errno;
238 return state->result.result_size_t;
242 * Retrieve a int typed result from an async syscall
243 * @param[in] req The syscall that has just finished
244 * @param[out] perrno Where to put the syscall's errno
245 * @retval The return value from the asynchronously called syscall
248 int async_syscall_result_int(struct async_req *req, int *perrno)
250 struct async_syscall_state *state = talloc_get_type_abort(
251 req->private_data, struct async_syscall_state);
253 *perrno = state->sys_errno;
254 return state->result.result_int;
258 * fde event handler for the "send" syscall
259 * @param[in] ev The event context that sent us here
260 * @param[in] fde The file descriptor event associated with the send
261 * @param[in] flags Can only be TEVENT_FD_WRITE here
262 * @param[in] priv private data, "struct async_req *" in this case
265 static void async_send_callback(struct tevent_context *ev,
266 struct tevent_fd *fde, uint16_t flags,
267 void *priv)
269 struct async_req *req = talloc_get_type_abort(
270 priv, struct async_req);
271 struct async_syscall_state *state = talloc_get_type_abort(
272 req->private_data, struct async_syscall_state);
273 struct param_send *p = &state->param.param_send;
275 if (state->syscall_type != ASYNC_SYSCALL_SEND) {
276 async_req_error(req, EIO);
277 return;
280 state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
281 p->flags);
282 state->sys_errno = errno;
284 TALLOC_FREE(state->fde);
286 async_req_done(req);
290 * Async version of send(2)
291 * @param[in] mem_ctx The memory context to hang the result off
292 * @param[in] ev The event context to work from
293 * @param[in] fd The socket to send to
294 * @param[in] buffer The buffer to send
295 * @param[in] length How many bytes to send
296 * @param[in] flags flags passed to send(2)
298 * This function is a direct counterpart of send(2)
301 struct async_req *async_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
302 int fd, const void *buffer, size_t length,
303 int flags)
305 struct async_req *result;
306 struct async_syscall_state *state;
308 result = async_fde_syscall_new(
309 mem_ctx, ev, ASYNC_SYSCALL_SEND,
310 fd, TEVENT_FD_WRITE, async_send_callback,
311 &state);
312 if (result == NULL) {
313 return NULL;
316 state->param.param_send.fd = fd;
317 state->param.param_send.buffer = buffer;
318 state->param.param_send.length = length;
319 state->param.param_send.flags = flags;
321 return result;
325 * fde event handler for the "recv" syscall
326 * @param[in] ev The event context that sent us here
327 * @param[in] fde The file descriptor event associated with the recv
328 * @param[in] flags Can only be TEVENT_FD_READ here
329 * @param[in] priv private data, "struct async_req *" in this case
332 static void async_recv_callback(struct tevent_context *ev,
333 struct tevent_fd *fde, uint16_t flags,
334 void *priv)
336 struct async_req *req = talloc_get_type_abort(
337 priv, struct async_req);
338 struct async_syscall_state *state = talloc_get_type_abort(
339 req->private_data, struct async_syscall_state);
340 struct param_recv *p = &state->param.param_recv;
342 if (state->syscall_type != ASYNC_SYSCALL_RECV) {
343 async_req_error(req, EIO);
344 return;
347 state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
348 p->flags);
349 state->sys_errno = errno;
351 TALLOC_FREE(state->fde);
353 async_req_done(req);
357 * Async version of recv(2)
358 * @param[in] mem_ctx The memory context to hang the result off
359 * @param[in] ev The event context to work from
360 * @param[in] fd The socket to recv from
361 * @param[in] buffer The buffer to recv into
362 * @param[in] length How many bytes to recv
363 * @param[in] flags flags passed to recv(2)
365 * This function is a direct counterpart of recv(2)
368 struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
369 int fd, void *buffer, size_t length,
370 int flags)
372 struct async_req *result;
373 struct async_syscall_state *state;
375 result = async_fde_syscall_new(
376 mem_ctx, ev, ASYNC_SYSCALL_RECV,
377 fd, TEVENT_FD_READ, async_recv_callback,
378 &state);
380 if (result == NULL) {
381 return NULL;
384 state->param.param_recv.fd = fd;
385 state->param.param_recv.buffer = buffer;
386 state->param.param_recv.length = length;
387 state->param.param_recv.flags = flags;
389 return result;
392 struct async_connect_state {
393 int fd;
394 int result;
395 int sys_errno;
396 long old_sockflags;
399 static void async_connect_connected(struct tevent_context *ev,
400 struct tevent_fd *fde, uint16_t flags,
401 void *priv);
404 * @brief async version of connect(2)
405 * @param[in] mem_ctx The memory context to hang the result off
406 * @param[in] ev The event context to work from
407 * @param[in] fd The socket to recv from
408 * @param[in] address Where to connect?
409 * @param[in] address_len Length of *address
410 * @retval The async request
412 * This function sets the socket into non-blocking state to be able to call
413 * connect in an async state. This will be reset when the request is finished.
416 struct tevent_req *async_connect_send(TALLOC_CTX *mem_ctx,
417 struct tevent_context *ev,
418 int fd, const struct sockaddr *address,
419 socklen_t address_len)
421 struct tevent_req *result;
422 struct async_connect_state *state;
423 struct tevent_fd *fde;
425 result = tevent_req_create(
426 mem_ctx, &state, struct async_connect_state);
427 if (result == NULL) {
428 return NULL;
432 * We have to set the socket to nonblocking for async connect(2). Keep
433 * the old sockflags around.
436 state->fd = fd;
437 state->sys_errno = 0;
439 state->old_sockflags = fcntl(fd, F_GETFL, 0);
440 if (state->old_sockflags == -1) {
441 goto post_errno;
444 set_blocking(fd, false);
446 state->result = connect(fd, address, address_len);
447 if (state->result == 0) {
448 errno = 0;
449 goto post_errno;
453 * A number of error messages show that something good is progressing
454 * and that we have to wait for readability.
456 * If none of them are present, bail out.
459 if (!(errno == EINPROGRESS || errno == EALREADY ||
460 #ifdef EISCONN
461 errno == EISCONN ||
462 #endif
463 errno == EAGAIN || errno == EINTR)) {
464 goto post_errno;
467 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
468 async_connect_connected, result);
469 if (fde == NULL) {
470 errno = ENOMEM;
471 goto post_errno;
473 return result;
475 post_errno:
476 state->sys_errno = errno;
477 fcntl(fd, F_SETFL, state->old_sockflags);
478 if (state->sys_errno == 0) {
479 tevent_req_done(result);
480 } else {
481 tevent_req_error(result, state->sys_errno);
483 return tevent_req_post(result, ev);
487 * fde event handler for connect(2)
488 * @param[in] ev The event context that sent us here
489 * @param[in] fde The file descriptor event associated with the connect
490 * @param[in] flags Indicate read/writeability of the socket
491 * @param[in] priv private data, "struct async_req *" in this case
494 static void async_connect_connected(struct tevent_context *ev,
495 struct tevent_fd *fde, uint16_t flags,
496 void *priv)
498 struct tevent_req *req = talloc_get_type_abort(
499 priv, struct tevent_req);
500 struct async_connect_state *state = talloc_get_type_abort(
501 req->private_state, struct async_connect_state);
503 TALLOC_FREE(fde);
506 * Stevens, Network Programming says that if there's a
507 * successful connect, the socket is only writable. Upon an
508 * error, it's both readable and writable.
510 if ((flags & (TEVENT_FD_READ|TEVENT_FD_WRITE))
511 == (TEVENT_FD_READ|TEVENT_FD_WRITE)) {
512 int sockerr;
513 socklen_t err_len = sizeof(sockerr);
515 if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
516 (void *)&sockerr, &err_len) == 0) {
517 errno = sockerr;
520 state->sys_errno = errno;
522 DEBUG(10, ("connect returned %s\n", strerror(errno)));
524 fcntl(state->fd, F_SETFL, state->old_sockflags);
525 tevent_req_error(req, state->sys_errno);
526 return;
529 state->sys_errno = 0;
530 tevent_req_done(req);
533 int async_connect_recv(struct tevent_req *req, int *perrno)
535 struct async_connect_state *state = talloc_get_type_abort(
536 req->private_state, struct async_connect_state);
537 int err;
539 fcntl(state->fd, F_SETFL, state->old_sockflags);
541 if (tevent_req_is_unix_error(req, &err)) {
542 *perrno = err;
543 return -1;
546 if (state->sys_errno == 0) {
547 return 0;
550 *perrno = state->sys_errno;
551 return -1;
554 struct writev_state {
555 struct tevent_context *ev;
556 int fd;
557 struct iovec *iov;
558 int count;
559 size_t total_size;
562 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
563 uint16_t flags, void *private_data);
565 struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
566 int fd, struct iovec *iov, int count)
568 struct tevent_req *result;
569 struct writev_state *state;
570 struct tevent_fd *fde;
572 result = tevent_req_create(mem_ctx, &state, struct writev_state);
573 if (result == NULL) {
574 return NULL;
576 state->ev = ev;
577 state->fd = fd;
578 state->total_size = 0;
579 state->count = count;
580 state->iov = (struct iovec *)talloc_memdup(
581 state, iov, sizeof(struct iovec) * count);
582 if (state->iov == NULL) {
583 goto fail;
586 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, writev_handler,
587 result);
588 if (fde == NULL) {
589 goto fail;
591 return result;
593 fail:
594 TALLOC_FREE(result);
595 return NULL;
598 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
599 uint16_t flags, void *private_data)
601 struct tevent_req *req = talloc_get_type_abort(
602 private_data, struct tevent_req);
603 struct writev_state *state = talloc_get_type_abort(
604 req->private_state, struct writev_state);
605 size_t to_write, written;
606 int i;
608 to_write = 0;
610 for (i=0; i<state->count; i++) {
611 to_write += state->iov[i].iov_len;
614 written = sys_writev(state->fd, state->iov, state->count);
615 if (written == -1) {
616 tevent_req_error(req, errno);
617 return;
619 if (written == 0) {
620 tevent_req_error(req, EPIPE);
621 return;
623 state->total_size += written;
625 if (written == to_write) {
626 tevent_req_done(req);
627 return;
631 * We've written less than we were asked to, drop stuff from
632 * state->iov.
635 while (written > 0) {
636 if (written < state->iov[0].iov_len) {
637 state->iov[0].iov_base =
638 (char *)state->iov[0].iov_base + written;
639 state->iov[0].iov_len -= written;
640 break;
642 written = state->iov[0].iov_len;
643 state->iov += 1;
644 state->count -= 1;
648 ssize_t writev_recv(struct tevent_req *req, int *perrno)
650 struct writev_state *state = talloc_get_type_abort(
651 req->private_state, struct writev_state);
653 if (tevent_req_is_unix_error(req, perrno)) {
654 return -1;
656 return state->total_size;
659 struct read_packet_state {
660 int fd;
661 uint8_t *buf;
662 size_t nread;
663 ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
664 void *private_data;
667 static void read_packet_handler(struct tevent_context *ev,
668 struct tevent_fd *fde,
669 uint16_t flags, void *private_data);
671 struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
672 struct tevent_context *ev,
673 int fd, size_t initial,
674 ssize_t (*more)(uint8_t *buf,
675 size_t buflen,
676 void *private_data),
677 void *private_data)
679 struct tevent_req *result;
680 struct read_packet_state *state;
681 struct tevent_fd *fde;
683 result = tevent_req_create(mem_ctx, &state, struct read_packet_state);
684 if (result == NULL) {
685 return NULL;
687 state->fd = fd;
688 state->nread = 0;
689 state->more = more;
690 state->private_data = private_data;
692 state->buf = talloc_array(state, uint8_t, initial);
693 if (state->buf == NULL) {
694 goto fail;
697 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler,
698 result);
699 if (fde == NULL) {
700 goto fail;
702 return result;
703 fail:
704 TALLOC_FREE(result);
705 return NULL;
708 static void read_packet_handler(struct tevent_context *ev,
709 struct tevent_fd *fde,
710 uint16_t flags, void *private_data)
712 struct tevent_req *req = talloc_get_type_abort(
713 private_data, struct tevent_req);
714 struct read_packet_state *state = talloc_get_type_abort(
715 req->private_state, struct read_packet_state);
716 size_t total = talloc_get_size(state->buf);
717 ssize_t nread, more;
718 uint8_t *tmp;
720 nread = read(state->fd, state->buf+state->nread, total-state->nread);
721 if (nread == -1) {
722 tevent_req_error(req, errno);
723 return;
725 if (nread == 0) {
726 tevent_req_error(req, EPIPE);
727 return;
730 state->nread += nread;
731 if (state->nread < total) {
732 /* Come back later */
733 return;
737 * We got what was initially requested. See if "more" asks for -- more.
739 if (state->more == NULL) {
740 /* Nobody to ask, this is a async read_data */
741 tevent_req_done(req);
742 return;
745 more = state->more(state->buf, total, state->private_data);
746 if (more == -1) {
747 /* We got an invalid packet, tell the caller */
748 tevent_req_error(req, EIO);
749 return;
751 if (more == 0) {
752 /* We're done, full packet received */
753 tevent_req_done(req);
754 return;
757 tmp = TALLOC_REALLOC_ARRAY(state, state->buf, uint8_t, total+more);
758 if (tevent_req_nomem(tmp, req)) {
759 return;
761 state->buf = tmp;
764 ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
765 uint8_t **pbuf, int *perrno)
767 struct read_packet_state *state = talloc_get_type_abort(
768 req->private_state, struct read_packet_state);
770 if (tevent_req_is_unix_error(req, perrno)) {
771 return -1;
773 *pbuf = talloc_move(mem_ctx, &state->buf);
774 return talloc_get_size(*pbuf);