2 Unix SMB/CIFS implementation.
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/>.
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"
29 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
33 * Discriminator for async_syscall_state
35 enum async_syscall_type {
38 ASYNC_SYSCALL_RECVALL,
43 * Holder for syscall arguments and the result
46 struct async_syscall_state {
47 enum async_syscall_type syscall_type;
48 struct tevent_fd *fde;
63 struct param_recvall {
70 struct param_connect {
72 * connect needs to be done on a nonblocking
73 * socket. Keep the old flags around
77 const struct sockaddr *address;
78 socklen_t address_len;
83 ssize_t result_ssize_t;
91 * @brief Map async_req states to unix-style errnos
92 * @param[in] req The async req to get the state from
93 * @param[out] err Pointer to take the unix-style errno
95 * @return true if the async_req is in an error state, false otherwise
98 bool async_req_is_errno(struct async_req *req, int *err)
100 enum async_req_state state;
103 if (!async_req_is_error(req, &state, &error)) {
108 case ASYNC_REQ_USER_ERROR:
111 case ASYNC_REQ_TIMED_OUT:
118 case ASYNC_REQ_NO_MEMORY:
128 int async_req_simple_recv_errno(struct async_req *req)
132 if (async_req_is_errno(req, &err)) {
140 * @brief Create a new async syscall req
141 * @param[in] mem_ctx The memory context to hang the result off
142 * @param[in] ev The event context to work from
143 * @param[in] type Which syscall will this be
144 * @param[in] pstate Where to put the newly created private_data state
145 * @retval The new request
147 * This is a helper function to prepare a new struct async_req with an
148 * associated struct async_syscall_state. The async_syscall_state will be put
149 * into the async_req as private_data.
152 static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx,
153 struct tevent_context *ev,
154 enum async_syscall_type type,
155 struct async_syscall_state **pstate)
157 struct async_req *result;
158 struct async_syscall_state *state;
160 if (!async_req_setup(mem_ctx, &result, &state,
161 struct async_syscall_state)) {
164 state->syscall_type = type;
166 result->private_data = state;
174 * @brief Create a new async syscall req based on a fd
175 * @param[in] mem_ctx The memory context to hang the result off
176 * @param[in] ev The event context to work from
177 * @param[in] type Which syscall will this be
178 * @param[in] fd The file descriptor we work on
179 * @param[in] fde_flags TEVENT_FD_READ/WRITE -- what are we interested in?
180 * @param[in] fde_cb The callback function for the file descriptor event
181 * @param[in] pstate Where to put the newly created private_data state
182 * @retval The new request
184 * This is a helper function to prepare a new struct async_req with an
185 * associated struct async_syscall_state and an associated file descriptor
189 static struct async_req *async_fde_syscall_new(
191 struct tevent_context *ev,
192 enum async_syscall_type type,
195 void (*fde_cb)(struct tevent_context *ev,
196 struct tevent_fd *fde, uint16_t flags,
198 struct async_syscall_state **pstate)
200 struct async_req *result;
201 struct async_syscall_state *state;
203 result = async_syscall_new(mem_ctx, ev, type, &state);
204 if (result == NULL) {
208 state->fde = tevent_add_fd(ev, state, fd, fde_flags, fde_cb, result);
209 if (state->fde == NULL) {
218 * Retrieve a ssize_t typed result from an async syscall
219 * @param[in] req The syscall that has just finished
220 * @param[out] perrno Where to put the syscall's errno
221 * @retval The return value from the asynchronously called syscall
224 ssize_t async_syscall_result_ssize_t(struct async_req *req, int *perrno)
226 struct async_syscall_state *state = talloc_get_type_abort(
227 req->private_data, struct async_syscall_state);
229 *perrno = state->sys_errno;
230 return state->result.result_ssize_t;
234 * Retrieve a size_t typed result from an async syscall
235 * @param[in] req The syscall that has just finished
236 * @param[out] perrno Where to put the syscall's errno
237 * @retval The return value from the asynchronously called syscall
240 size_t async_syscall_result_size_t(struct async_req *req, int *perrno)
242 struct async_syscall_state *state = talloc_get_type_abort(
243 req->private_data, struct async_syscall_state);
245 *perrno = state->sys_errno;
246 return state->result.result_size_t;
250 * Retrieve a int typed result from an async syscall
251 * @param[in] req The syscall that has just finished
252 * @param[out] perrno Where to put the syscall's errno
253 * @retval The return value from the asynchronously called syscall
256 int async_syscall_result_int(struct async_req *req, int *perrno)
258 struct async_syscall_state *state = talloc_get_type_abort(
259 req->private_data, struct async_syscall_state);
261 *perrno = state->sys_errno;
262 return state->result.result_int;
266 * fde event handler for the "send" syscall
267 * @param[in] ev The event context that sent us here
268 * @param[in] fde The file descriptor event associated with the send
269 * @param[in] flags Can only be TEVENT_FD_WRITE here
270 * @param[in] priv private data, "struct async_req *" in this case
273 static void async_send_callback(struct tevent_context *ev,
274 struct tevent_fd *fde, uint16_t flags,
277 struct async_req *req = talloc_get_type_abort(
278 priv, struct async_req);
279 struct async_syscall_state *state = talloc_get_type_abort(
280 req->private_data, struct async_syscall_state);
281 struct param_send *p = &state->param.param_send;
283 if (state->syscall_type != ASYNC_SYSCALL_SEND) {
284 async_req_error(req, EIO);
288 state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
290 state->sys_errno = errno;
292 TALLOC_FREE(state->fde);
298 * Async version of send(2)
299 * @param[in] mem_ctx The memory context to hang the result off
300 * @param[in] ev The event context to work from
301 * @param[in] fd The socket to send to
302 * @param[in] buffer The buffer to send
303 * @param[in] length How many bytes to send
304 * @param[in] flags flags passed to send(2)
306 * This function is a direct counterpart of send(2)
309 struct async_req *async_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
310 int fd, const void *buffer, size_t length,
313 struct async_req *result;
314 struct async_syscall_state *state;
316 result = async_fde_syscall_new(
317 mem_ctx, ev, ASYNC_SYSCALL_SEND,
318 fd, TEVENT_FD_WRITE, async_send_callback,
320 if (result == NULL) {
324 state->param.param_send.fd = fd;
325 state->param.param_send.buffer = buffer;
326 state->param.param_send.length = length;
327 state->param.param_send.flags = flags;
333 * fde event handler for the "recv" syscall
334 * @param[in] ev The event context that sent us here
335 * @param[in] fde The file descriptor event associated with the recv
336 * @param[in] flags Can only be TEVENT_FD_READ here
337 * @param[in] priv private data, "struct async_req *" in this case
340 static void async_recv_callback(struct tevent_context *ev,
341 struct tevent_fd *fde, uint16_t flags,
344 struct async_req *req = talloc_get_type_abort(
345 priv, struct async_req);
346 struct async_syscall_state *state = talloc_get_type_abort(
347 req->private_data, struct async_syscall_state);
348 struct param_recv *p = &state->param.param_recv;
350 if (state->syscall_type != ASYNC_SYSCALL_RECV) {
351 async_req_error(req, EIO);
355 state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
357 state->sys_errno = errno;
359 TALLOC_FREE(state->fde);
365 * Async version of recv(2)
366 * @param[in] mem_ctx The memory context to hang the result off
367 * @param[in] ev The event context to work from
368 * @param[in] fd The socket to recv from
369 * @param[in] buffer The buffer to recv into
370 * @param[in] length How many bytes to recv
371 * @param[in] flags flags passed to recv(2)
373 * This function is a direct counterpart of recv(2)
376 struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
377 int fd, void *buffer, size_t length,
380 struct async_req *result;
381 struct async_syscall_state *state;
383 result = async_fde_syscall_new(
384 mem_ctx, ev, ASYNC_SYSCALL_RECV,
385 fd, TEVENT_FD_READ, async_recv_callback,
388 if (result == NULL) {
392 state->param.param_recv.fd = fd;
393 state->param.param_recv.buffer = buffer;
394 state->param.param_recv.length = length;
395 state->param.param_recv.flags = flags;
401 * fde event handler for the "recvall" syscall group
402 * @param[in] ev The event context that sent us here
403 * @param[in] fde The file descriptor event associated with the recv
404 * @param[in] flags Can only be TEVENT_FD_READ here
405 * @param[in] priv private data, "struct async_req *" in this case
408 static void async_recvall_callback(struct tevent_context *ev,
409 struct tevent_fd *fde, uint16_t flags,
412 struct async_req *req = talloc_get_type_abort(
413 priv, struct async_req);
414 struct async_syscall_state *state = talloc_get_type_abort(
415 req->private_data, struct async_syscall_state);
416 struct param_recvall *p = &state->param.param_recvall;
418 if (state->syscall_type != ASYNC_SYSCALL_RECVALL) {
419 async_req_error(req, EIO);
423 state->result.result_ssize_t = recv(p->fd,
424 (char *)p->buffer + p->received,
425 p->length - p->received, p->flags);
426 state->sys_errno = errno;
428 if (state->result.result_ssize_t == -1) {
429 async_req_error(req, state->sys_errno);
433 if (state->result.result_ssize_t == 0) {
434 async_req_error(req, EIO);
438 p->received += state->result.result_ssize_t;
439 if (p->received > p->length) {
440 async_req_error(req, EIO);
444 if (p->received == p->length) {
445 TALLOC_FREE(state->fde);
451 * Receive a specified number of bytes from a socket
452 * @param[in] mem_ctx The memory context to hang the result off
453 * @param[in] ev The event context to work from
454 * @param[in] fd The socket to recv from
455 * @param[in] buffer The buffer to recv into
456 * @param[in] length How many bytes to recv
457 * @param[in] flags flags passed to recv(2)
459 * async_recvall will call recv(2) until "length" bytes are received
462 struct async_req *recvall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
463 int fd, void *buffer, size_t length,
466 struct async_req *result;
467 struct async_syscall_state *state;
469 result = async_fde_syscall_new(
470 mem_ctx, ev, ASYNC_SYSCALL_RECVALL,
471 fd, TEVENT_FD_READ, async_recvall_callback,
473 if (result == NULL) {
477 state->param.param_recvall.fd = fd;
478 state->param.param_recvall.buffer = buffer;
479 state->param.param_recvall.length = length;
480 state->param.param_recvall.flags = flags;
481 state->param.param_recvall.received = 0;
486 ssize_t recvall_recv(struct async_req *req, int *perr)
488 struct async_syscall_state *state = talloc_get_type_abort(
489 req->private_data, struct async_syscall_state);
492 err = async_req_simple_recv_errno(req);
499 return state->result.result_ssize_t;
502 struct async_connect_state {
509 static void async_connect_connected(struct tevent_context *ev,
510 struct tevent_fd *fde, uint16_t flags,
514 * @brief async version of connect(2)
515 * @param[in] mem_ctx The memory context to hang the result off
516 * @param[in] ev The event context to work from
517 * @param[in] fd The socket to recv from
518 * @param[in] address Where to connect?
519 * @param[in] address_len Length of *address
520 * @retval The async request
522 * This function sets the socket into non-blocking state to be able to call
523 * connect in an async state. This will be reset when the request is finished.
526 struct tevent_req *async_connect_send(TALLOC_CTX *mem_ctx,
527 struct tevent_context *ev,
528 int fd, const struct sockaddr *address,
529 socklen_t address_len)
531 struct tevent_req *result;
532 struct async_connect_state *state;
533 struct tevent_fd *fde;
535 result = tevent_req_create(
536 mem_ctx, &state, struct async_connect_state);
537 if (result == NULL) {
542 * We have to set the socket to nonblocking for async connect(2). Keep
543 * the old sockflags around.
547 state->sys_errno = 0;
549 state->old_sockflags = fcntl(fd, F_GETFL, 0);
550 if (state->old_sockflags == -1) {
554 set_blocking(fd, false);
556 state->result = connect(fd, address, address_len);
557 if (state->result == 0) {
563 * A number of error messages show that something good is progressing
564 * and that we have to wait for readability.
566 * If none of them are present, bail out.
569 if (!(errno == EINPROGRESS || errno == EALREADY ||
573 errno == EAGAIN || errno == EINTR)) {
577 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
578 async_connect_connected, result);
586 state->sys_errno = errno;
587 fcntl(fd, F_SETFL, state->old_sockflags);
588 if (state->sys_errno == 0) {
589 tevent_req_done(result);
591 tevent_req_error(result, state->sys_errno);
593 return tevent_req_post(result, ev);
597 * fde event handler for connect(2)
598 * @param[in] ev The event context that sent us here
599 * @param[in] fde The file descriptor event associated with the connect
600 * @param[in] flags Indicate read/writeability of the socket
601 * @param[in] priv private data, "struct async_req *" in this case
604 static void async_connect_connected(struct tevent_context *ev,
605 struct tevent_fd *fde, uint16_t flags,
608 struct tevent_req *req = talloc_get_type_abort(
609 priv, struct tevent_req);
610 struct async_connect_state *state = talloc_get_type_abort(
611 req->private_state, struct async_connect_state);
616 * Stevens, Network Programming says that if there's a
617 * successful connect, the socket is only writable. Upon an
618 * error, it's both readable and writable.
620 if ((flags & (TEVENT_FD_READ|TEVENT_FD_WRITE))
621 == (TEVENT_FD_READ|TEVENT_FD_WRITE)) {
623 socklen_t err_len = sizeof(sockerr);
625 if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
626 (void *)&sockerr, &err_len) == 0) {
630 state->sys_errno = errno;
632 DEBUG(10, ("connect returned %s\n", strerror(errno)));
634 fcntl(state->fd, F_SETFL, state->old_sockflags);
635 tevent_req_error(req, state->sys_errno);
639 state->sys_errno = 0;
640 tevent_req_done(req);
643 int async_connect_recv(struct tevent_req *req, int *perrno)
645 struct async_connect_state *state = talloc_get_type_abort(
646 req->private_state, struct async_connect_state);
649 fcntl(state->fd, F_SETFL, state->old_sockflags);
651 if (tevent_req_is_unix_error(req, &err)) {
656 if (state->sys_errno == 0) {
660 *perrno = state->sys_errno;
664 struct writev_state {
665 struct tevent_context *ev;
672 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
673 uint16_t flags, void *private_data);
675 struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
676 int fd, struct iovec *iov, int count)
678 struct tevent_req *result;
679 struct writev_state *state;
680 struct tevent_fd *fde;
682 result = tevent_req_create(mem_ctx, &state, struct writev_state);
683 if (result == NULL) {
688 state->total_size = 0;
689 state->count = count;
690 state->iov = (struct iovec *)talloc_memdup(
691 state, iov, sizeof(struct iovec) * count);
692 if (state->iov == NULL) {
696 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, writev_handler,
708 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
709 uint16_t flags, void *private_data)
711 struct tevent_req *req = talloc_get_type_abort(
712 private_data, struct tevent_req);
713 struct writev_state *state = talloc_get_type_abort(
714 req->private_state, struct writev_state);
715 size_t to_write, written;
720 for (i=0; i<state->count; i++) {
721 to_write += state->iov[i].iov_len;
724 written = sys_writev(state->fd, state->iov, state->count);
726 tevent_req_error(req, errno);
730 tevent_req_error(req, EPIPE);
733 state->total_size += written;
735 if (written == to_write) {
736 tevent_req_done(req);
741 * We've written less than we were asked to, drop stuff from
745 while (written > 0) {
746 if (written < state->iov[0].iov_len) {
747 state->iov[0].iov_base =
748 (char *)state->iov[0].iov_base + written;
749 state->iov[0].iov_len -= written;
752 written = state->iov[0].iov_len;
758 ssize_t writev_recv(struct tevent_req *req, int *perrno)
760 struct writev_state *state = talloc_get_type_abort(
761 req->private_state, struct writev_state);
763 if (tevent_req_is_unix_error(req, perrno)) {
766 return state->total_size;
769 struct read_packet_state {
773 ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
777 static void read_packet_handler(struct tevent_context *ev,
778 struct tevent_fd *fde,
779 uint16_t flags, void *private_data);
781 struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
782 struct tevent_context *ev,
783 int fd, size_t initial,
784 ssize_t (*more)(uint8_t *buf,
789 struct tevent_req *result;
790 struct read_packet_state *state;
791 struct tevent_fd *fde;
793 result = tevent_req_create(mem_ctx, &state, struct read_packet_state);
794 if (result == NULL) {
800 state->private_data = private_data;
802 state->buf = talloc_array(state, uint8_t, initial);
803 if (state->buf == NULL) {
807 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler,
818 static void read_packet_handler(struct tevent_context *ev,
819 struct tevent_fd *fde,
820 uint16_t flags, void *private_data)
822 struct tevent_req *req = talloc_get_type_abort(
823 private_data, struct tevent_req);
824 struct read_packet_state *state = talloc_get_type_abort(
825 req->private_state, struct read_packet_state);
826 size_t total = talloc_get_size(state->buf);
830 nread = read(state->fd, state->buf+state->nread, total-state->nread);
832 tevent_req_error(req, errno);
836 tevent_req_error(req, EPIPE);
840 state->nread += nread;
841 if (state->nread < total) {
842 /* Come back later */
847 * We got what was initially requested. See if "more" asks for -- more.
849 if (state->more == NULL) {
850 /* Nobody to ask, this is a async read_data */
851 tevent_req_done(req);
855 more = state->more(state->buf, total, state->private_data);
857 /* We got an invalid packet, tell the caller */
858 tevent_req_error(req, EIO);
862 /* We're done, full packet received */
863 tevent_req_done(req);
867 tmp = TALLOC_REALLOC_ARRAY(state, state->buf, uint8_t, total+more);
868 if (tevent_req_nomem(tmp, req)) {
874 ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
875 uint8_t **pbuf, int *perrno)
877 struct read_packet_state *state = talloc_get_type_abort(
878 req->private_state, struct read_packet_state);
880 if (tevent_req_is_unix_error(req, perrno)) {
883 *pbuf = talloc_move(mem_ctx, &state->buf);
884 return talloc_get_size(*pbuf);