Remove async_req based async_recv
[Samba/gbeck.git] / lib / async_req / async_sock.c
blob302265c80531098e4d69c139275dce7842f5aa75
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,
40 /**
41 * Holder for syscall arguments and the result
44 struct async_syscall_state {
45 enum async_syscall_type syscall_type;
46 struct tevent_fd *fde;
48 union {
49 struct param_send {
50 int fd;
51 const void *buffer;
52 size_t length;
53 int flags;
54 } param_send;
55 struct param_recv {
56 int fd;
57 void *buffer;
58 size_t length;
59 int flags;
60 } param_recv;
61 } param;
63 union {
64 ssize_t result_ssize_t;
65 size_t result_size_t;
66 int result_int;
67 } result;
68 int sys_errno;
71 /**
72 * @brief Map async_req states to unix-style errnos
73 * @param[in] req The async req to get the state from
74 * @param[out] err Pointer to take the unix-style errno
76 * @return true if the async_req is in an error state, false otherwise
79 bool async_req_is_errno(struct async_req *req, int *err)
81 enum async_req_state state;
82 uint64_t error;
84 if (!async_req_is_error(req, &state, &error)) {
85 return false;
88 switch (state) {
89 case ASYNC_REQ_USER_ERROR:
90 *err = (int)error;
91 break;
92 case ASYNC_REQ_TIMED_OUT:
93 #ifdef ETIMEDOUT
94 *err = ETIMEDOUT;
95 #else
96 *err = EAGAIN;
97 #endif
98 break;
99 case ASYNC_REQ_NO_MEMORY:
100 *err = ENOMEM;
101 break;
102 default:
103 *err = EIO;
104 break;
106 return true;
109 int async_req_simple_recv_errno(struct async_req *req)
111 int err;
113 if (async_req_is_errno(req, &err)) {
114 return err;
117 return 0;
121 * @brief Create a new async syscall req
122 * @param[in] mem_ctx The memory context to hang the result off
123 * @param[in] ev The event context to work from
124 * @param[in] type Which syscall will this be
125 * @param[in] pstate Where to put the newly created private_data state
126 * @retval The new request
128 * This is a helper function to prepare a new struct async_req with an
129 * associated struct async_syscall_state. The async_syscall_state will be put
130 * into the async_req as private_data.
133 static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx,
134 struct tevent_context *ev,
135 enum async_syscall_type type,
136 struct async_syscall_state **pstate)
138 struct async_req *result;
139 struct async_syscall_state *state;
141 if (!async_req_setup(mem_ctx, &result, &state,
142 struct async_syscall_state)) {
143 return NULL;
145 state->syscall_type = type;
147 result->private_data = state;
149 *pstate = state;
151 return result;
155 * @brief Create a new async syscall req based on a fd
156 * @param[in] mem_ctx The memory context to hang the result off
157 * @param[in] ev The event context to work from
158 * @param[in] type Which syscall will this be
159 * @param[in] fd The file descriptor we work on
160 * @param[in] fde_flags TEVENT_FD_READ/WRITE -- what are we interested in?
161 * @param[in] fde_cb The callback function for the file descriptor event
162 * @param[in] pstate Where to put the newly created private_data state
163 * @retval The new request
165 * This is a helper function to prepare a new struct async_req with an
166 * associated struct async_syscall_state and an associated file descriptor
167 * event.
170 static struct async_req *async_fde_syscall_new(
171 TALLOC_CTX *mem_ctx,
172 struct tevent_context *ev,
173 enum async_syscall_type type,
174 int fd,
175 uint16_t fde_flags,
176 void (*fde_cb)(struct tevent_context *ev,
177 struct tevent_fd *fde, uint16_t flags,
178 void *priv),
179 struct async_syscall_state **pstate)
181 struct async_req *result;
182 struct async_syscall_state *state;
184 result = async_syscall_new(mem_ctx, ev, type, &state);
185 if (result == NULL) {
186 return NULL;
189 state->fde = tevent_add_fd(ev, state, fd, fde_flags, fde_cb, result);
190 if (state->fde == NULL) {
191 TALLOC_FREE(result);
192 return NULL;
194 *pstate = state;
195 return result;
199 * Retrieve a ssize_t typed result from an async syscall
200 * @param[in] req The syscall that has just finished
201 * @param[out] perrno Where to put the syscall's errno
202 * @retval The return value from the asynchronously called syscall
205 ssize_t async_syscall_result_ssize_t(struct async_req *req, int *perrno)
207 struct async_syscall_state *state = talloc_get_type_abort(
208 req->private_data, struct async_syscall_state);
210 *perrno = state->sys_errno;
211 return state->result.result_ssize_t;
215 * Retrieve a size_t typed result from an async syscall
216 * @param[in] req The syscall that has just finished
217 * @param[out] perrno Where to put the syscall's errno
218 * @retval The return value from the asynchronously called syscall
221 size_t async_syscall_result_size_t(struct async_req *req, int *perrno)
223 struct async_syscall_state *state = talloc_get_type_abort(
224 req->private_data, struct async_syscall_state);
226 *perrno = state->sys_errno;
227 return state->result.result_size_t;
231 * Retrieve a int typed result from an async syscall
232 * @param[in] req The syscall that has just finished
233 * @param[out] perrno Where to put the syscall's errno
234 * @retval The return value from the asynchronously called syscall
237 int async_syscall_result_int(struct async_req *req, int *perrno)
239 struct async_syscall_state *state = talloc_get_type_abort(
240 req->private_data, struct async_syscall_state);
242 *perrno = state->sys_errno;
243 return state->result.result_int;
247 * fde event handler for the "send" syscall
248 * @param[in] ev The event context that sent us here
249 * @param[in] fde The file descriptor event associated with the send
250 * @param[in] flags Can only be TEVENT_FD_WRITE here
251 * @param[in] priv private data, "struct async_req *" in this case
254 static void async_send_callback(struct tevent_context *ev,
255 struct tevent_fd *fde, uint16_t flags,
256 void *priv)
258 struct async_req *req = talloc_get_type_abort(
259 priv, struct async_req);
260 struct async_syscall_state *state = talloc_get_type_abort(
261 req->private_data, struct async_syscall_state);
262 struct param_send *p = &state->param.param_send;
264 if (state->syscall_type != ASYNC_SYSCALL_SEND) {
265 async_req_error(req, EIO);
266 return;
269 state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
270 p->flags);
271 state->sys_errno = errno;
273 TALLOC_FREE(state->fde);
275 async_req_done(req);
279 * Async version of send(2)
280 * @param[in] mem_ctx The memory context to hang the result off
281 * @param[in] ev The event context to work from
282 * @param[in] fd The socket to send to
283 * @param[in] buffer The buffer to send
284 * @param[in] length How many bytes to send
285 * @param[in] flags flags passed to send(2)
287 * This function is a direct counterpart of send(2)
290 struct async_req *async_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
291 int fd, const void *buffer, size_t length,
292 int flags)
294 struct async_req *result;
295 struct async_syscall_state *state;
297 result = async_fde_syscall_new(
298 mem_ctx, ev, ASYNC_SYSCALL_SEND,
299 fd, TEVENT_FD_WRITE, async_send_callback,
300 &state);
301 if (result == NULL) {
302 return NULL;
305 state->param.param_send.fd = fd;
306 state->param.param_send.buffer = buffer;
307 state->param.param_send.length = length;
308 state->param.param_send.flags = flags;
310 return result;
313 struct async_send_state {
314 int fd;
315 const void *buf;
316 size_t len;
317 int flags;
318 ssize_t sent;
321 static void async_send_handler(struct tevent_context *ev,
322 struct tevent_fd *fde,
323 uint16_t flags, void *private_data);
325 struct tevent_req *async_send_send(TALLOC_CTX *mem_ctx,
326 struct tevent_context *ev,
327 int fd, const void *buf, size_t len,
328 int flags)
330 struct tevent_req *result;
331 struct async_send_state *state;
332 struct tevent_fd *fde;
334 result = tevent_req_create(mem_ctx, &state, struct async_send_state);
335 if (result == NULL) {
336 return result;
338 state->fd = fd;
339 state->buf = buf;
340 state->len = len;
341 state->flags = flags;
343 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, async_send_handler,
344 result);
345 if (fde == NULL) {
346 TALLOC_FREE(result);
347 return NULL;
349 return result;
352 static void async_send_handler(struct tevent_context *ev,
353 struct tevent_fd *fde,
354 uint16_t flags, void *private_data)
356 struct tevent_req *req = talloc_get_type_abort(
357 private_data, struct tevent_req);
358 struct async_send_state *state = talloc_get_type_abort(
359 req->private_state, struct async_send_state);
361 state->sent = send(state->fd, state->buf, state->len, state->flags);
362 if (state->sent == -1) {
363 tevent_req_error(req, errno);
364 return;
366 tevent_req_done(req);
369 ssize_t async_send_recv(struct tevent_req *req, int *perrno)
371 struct async_send_state *state = talloc_get_type_abort(
372 req->private_state, struct async_send_state);
374 if (tevent_req_is_unix_error(req, perrno)) {
375 return -1;
377 return state->sent;
380 struct async_recv_state {
381 int fd;
382 void *buf;
383 size_t len;
384 int flags;
385 ssize_t received;
388 static void async_recv_handler(struct tevent_context *ev,
389 struct tevent_fd *fde,
390 uint16_t flags, void *private_data);
392 struct tevent_req *async_recv_send(TALLOC_CTX *mem_ctx,
393 struct tevent_context *ev,
394 int fd, void *buf, size_t len, int flags)
396 struct tevent_req *result;
397 struct async_recv_state *state;
398 struct tevent_fd *fde;
400 result = tevent_req_create(mem_ctx, &state, struct async_recv_state);
401 if (result == NULL) {
402 return result;
404 state->fd = fd;
405 state->buf = buf;
406 state->len = len;
407 state->flags = flags;
409 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, async_recv_handler,
410 result);
411 if (fde == NULL) {
412 TALLOC_FREE(result);
413 return NULL;
415 return result;
418 static void async_recv_handler(struct tevent_context *ev,
419 struct tevent_fd *fde,
420 uint16_t flags, void *private_data)
422 struct tevent_req *req = talloc_get_type_abort(
423 private_data, struct tevent_req);
424 struct async_recv_state *state = talloc_get_type_abort(
425 req->private_state, struct async_recv_state);
427 state->received = recv(state->fd, state->buf, state->len,
428 state->flags);
429 if (state->received == -1) {
430 tevent_req_error(req, errno);
431 return;
433 tevent_req_done(req);
436 ssize_t async_recv_recv(struct tevent_req *req, int *perrno)
438 struct async_recv_state *state = talloc_get_type_abort(
439 req->private_state, struct async_recv_state);
441 if (tevent_req_is_unix_error(req, perrno)) {
442 return -1;
444 return state->received;
447 struct async_connect_state {
448 int fd;
449 int result;
450 int sys_errno;
451 long old_sockflags;
454 static void async_connect_connected(struct tevent_context *ev,
455 struct tevent_fd *fde, uint16_t flags,
456 void *priv);
459 * @brief async version of connect(2)
460 * @param[in] mem_ctx The memory context to hang the result off
461 * @param[in] ev The event context to work from
462 * @param[in] fd The socket to recv from
463 * @param[in] address Where to connect?
464 * @param[in] address_len Length of *address
465 * @retval The async request
467 * This function sets the socket into non-blocking state to be able to call
468 * connect in an async state. This will be reset when the request is finished.
471 struct tevent_req *async_connect_send(TALLOC_CTX *mem_ctx,
472 struct tevent_context *ev,
473 int fd, const struct sockaddr *address,
474 socklen_t address_len)
476 struct tevent_req *result;
477 struct async_connect_state *state;
478 struct tevent_fd *fde;
480 result = tevent_req_create(
481 mem_ctx, &state, struct async_connect_state);
482 if (result == NULL) {
483 return NULL;
487 * We have to set the socket to nonblocking for async connect(2). Keep
488 * the old sockflags around.
491 state->fd = fd;
492 state->sys_errno = 0;
494 state->old_sockflags = fcntl(fd, F_GETFL, 0);
495 if (state->old_sockflags == -1) {
496 goto post_errno;
499 set_blocking(fd, false);
501 state->result = connect(fd, address, address_len);
502 if (state->result == 0) {
503 errno = 0;
504 goto post_errno;
508 * A number of error messages show that something good is progressing
509 * and that we have to wait for readability.
511 * If none of them are present, bail out.
514 if (!(errno == EINPROGRESS || errno == EALREADY ||
515 #ifdef EISCONN
516 errno == EISCONN ||
517 #endif
518 errno == EAGAIN || errno == EINTR)) {
519 goto post_errno;
522 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
523 async_connect_connected, result);
524 if (fde == NULL) {
525 errno = ENOMEM;
526 goto post_errno;
528 return result;
530 post_errno:
531 state->sys_errno = errno;
532 fcntl(fd, F_SETFL, state->old_sockflags);
533 if (state->sys_errno == 0) {
534 tevent_req_done(result);
535 } else {
536 tevent_req_error(result, state->sys_errno);
538 return tevent_req_post(result, ev);
542 * fde event handler for connect(2)
543 * @param[in] ev The event context that sent us here
544 * @param[in] fde The file descriptor event associated with the connect
545 * @param[in] flags Indicate read/writeability of the socket
546 * @param[in] priv private data, "struct async_req *" in this case
549 static void async_connect_connected(struct tevent_context *ev,
550 struct tevent_fd *fde, uint16_t flags,
551 void *priv)
553 struct tevent_req *req = talloc_get_type_abort(
554 priv, struct tevent_req);
555 struct async_connect_state *state = talloc_get_type_abort(
556 req->private_state, struct async_connect_state);
558 TALLOC_FREE(fde);
561 * Stevens, Network Programming says that if there's a
562 * successful connect, the socket is only writable. Upon an
563 * error, it's both readable and writable.
565 if ((flags & (TEVENT_FD_READ|TEVENT_FD_WRITE))
566 == (TEVENT_FD_READ|TEVENT_FD_WRITE)) {
567 int sockerr;
568 socklen_t err_len = sizeof(sockerr);
570 if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
571 (void *)&sockerr, &err_len) == 0) {
572 errno = sockerr;
575 state->sys_errno = errno;
577 DEBUG(10, ("connect returned %s\n", strerror(errno)));
579 fcntl(state->fd, F_SETFL, state->old_sockflags);
580 tevent_req_error(req, state->sys_errno);
581 return;
584 state->sys_errno = 0;
585 tevent_req_done(req);
588 int async_connect_recv(struct tevent_req *req, int *perrno)
590 struct async_connect_state *state = talloc_get_type_abort(
591 req->private_state, struct async_connect_state);
592 int err;
594 fcntl(state->fd, F_SETFL, state->old_sockflags);
596 if (tevent_req_is_unix_error(req, &err)) {
597 *perrno = err;
598 return -1;
601 if (state->sys_errno == 0) {
602 return 0;
605 *perrno = state->sys_errno;
606 return -1;
609 struct writev_state {
610 struct tevent_context *ev;
611 int fd;
612 struct iovec *iov;
613 int count;
614 size_t total_size;
617 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
618 uint16_t flags, void *private_data);
620 struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
621 int fd, struct iovec *iov, int count)
623 struct tevent_req *result;
624 struct writev_state *state;
625 struct tevent_fd *fde;
627 result = tevent_req_create(mem_ctx, &state, struct writev_state);
628 if (result == NULL) {
629 return NULL;
631 state->ev = ev;
632 state->fd = fd;
633 state->total_size = 0;
634 state->count = count;
635 state->iov = (struct iovec *)talloc_memdup(
636 state, iov, sizeof(struct iovec) * count);
637 if (state->iov == NULL) {
638 goto fail;
641 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, writev_handler,
642 result);
643 if (fde == NULL) {
644 goto fail;
646 return result;
648 fail:
649 TALLOC_FREE(result);
650 return NULL;
653 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
654 uint16_t flags, void *private_data)
656 struct tevent_req *req = talloc_get_type_abort(
657 private_data, struct tevent_req);
658 struct writev_state *state = talloc_get_type_abort(
659 req->private_state, struct writev_state);
660 size_t to_write, written;
661 int i;
663 to_write = 0;
665 for (i=0; i<state->count; i++) {
666 to_write += state->iov[i].iov_len;
669 written = sys_writev(state->fd, state->iov, state->count);
670 if (written == -1) {
671 tevent_req_error(req, errno);
672 return;
674 if (written == 0) {
675 tevent_req_error(req, EPIPE);
676 return;
678 state->total_size += written;
680 if (written == to_write) {
681 tevent_req_done(req);
682 return;
686 * We've written less than we were asked to, drop stuff from
687 * state->iov.
690 while (written > 0) {
691 if (written < state->iov[0].iov_len) {
692 state->iov[0].iov_base =
693 (char *)state->iov[0].iov_base + written;
694 state->iov[0].iov_len -= written;
695 break;
697 written = state->iov[0].iov_len;
698 state->iov += 1;
699 state->count -= 1;
703 ssize_t writev_recv(struct tevent_req *req, int *perrno)
705 struct writev_state *state = talloc_get_type_abort(
706 req->private_state, struct writev_state);
708 if (tevent_req_is_unix_error(req, perrno)) {
709 return -1;
711 return state->total_size;
714 struct read_packet_state {
715 int fd;
716 uint8_t *buf;
717 size_t nread;
718 ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
719 void *private_data;
722 static void read_packet_handler(struct tevent_context *ev,
723 struct tevent_fd *fde,
724 uint16_t flags, void *private_data);
726 struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
727 struct tevent_context *ev,
728 int fd, size_t initial,
729 ssize_t (*more)(uint8_t *buf,
730 size_t buflen,
731 void *private_data),
732 void *private_data)
734 struct tevent_req *result;
735 struct read_packet_state *state;
736 struct tevent_fd *fde;
738 result = tevent_req_create(mem_ctx, &state, struct read_packet_state);
739 if (result == NULL) {
740 return NULL;
742 state->fd = fd;
743 state->nread = 0;
744 state->more = more;
745 state->private_data = private_data;
747 state->buf = talloc_array(state, uint8_t, initial);
748 if (state->buf == NULL) {
749 goto fail;
752 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler,
753 result);
754 if (fde == NULL) {
755 goto fail;
757 return result;
758 fail:
759 TALLOC_FREE(result);
760 return NULL;
763 static void read_packet_handler(struct tevent_context *ev,
764 struct tevent_fd *fde,
765 uint16_t flags, void *private_data)
767 struct tevent_req *req = talloc_get_type_abort(
768 private_data, struct tevent_req);
769 struct read_packet_state *state = talloc_get_type_abort(
770 req->private_state, struct read_packet_state);
771 size_t total = talloc_get_size(state->buf);
772 ssize_t nread, more;
773 uint8_t *tmp;
775 nread = read(state->fd, state->buf+state->nread, total-state->nread);
776 if (nread == -1) {
777 tevent_req_error(req, errno);
778 return;
780 if (nread == 0) {
781 tevent_req_error(req, EPIPE);
782 return;
785 state->nread += nread;
786 if (state->nread < total) {
787 /* Come back later */
788 return;
792 * We got what was initially requested. See if "more" asks for -- more.
794 if (state->more == NULL) {
795 /* Nobody to ask, this is a async read_data */
796 tevent_req_done(req);
797 return;
800 more = state->more(state->buf, total, state->private_data);
801 if (more == -1) {
802 /* We got an invalid packet, tell the caller */
803 tevent_req_error(req, EIO);
804 return;
806 if (more == 0) {
807 /* We're done, full packet received */
808 tevent_req_done(req);
809 return;
812 tmp = TALLOC_REALLOC_ARRAY(state, state->buf, uint8_t, total+more);
813 if (tevent_req_nomem(tmp, req)) {
814 return;
816 state->buf = tmp;
819 ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
820 uint8_t **pbuf, int *perrno)
822 struct read_packet_state *state = talloc_get_type_abort(
823 req->private_state, struct read_packet_state);
825 if (tevent_req_is_unix_error(req, perrno)) {
826 return -1;
828 *pbuf = talloc_move(mem_ctx, &state->buf);
829 return talloc_get_size(*pbuf);