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 {
37 ASYNC_SYSCALL_SENDALL,
39 ASYNC_SYSCALL_RECVALL,
44 * Holder for syscall arguments and the result
47 struct async_syscall_state {
48 enum async_syscall_type syscall_type;
49 struct tevent_fd *fde;
58 struct param_sendall {
71 struct param_recvall {
78 struct param_connect {
80 * connect needs to be done on a nonblocking
81 * socket. Keep the old flags around
85 const struct sockaddr *address;
86 socklen_t address_len;
91 ssize_t result_ssize_t;
99 * @brief Map async_req states to unix-style errnos
100 * @param[in] req The async req to get the state from
101 * @param[out] err Pointer to take the unix-style errno
103 * @return true if the async_req is in an error state, false otherwise
106 bool async_req_is_errno(struct async_req *req, int *err)
108 enum async_req_state state;
111 if (!async_req_is_error(req, &state, &error)) {
116 case ASYNC_REQ_USER_ERROR:
119 case ASYNC_REQ_TIMED_OUT:
126 case ASYNC_REQ_NO_MEMORY:
136 int async_req_simple_recv_errno(struct async_req *req)
140 if (async_req_is_errno(req, &err)) {
148 * @brief Create a new async syscall req
149 * @param[in] mem_ctx The memory context to hang the result off
150 * @param[in] ev The event context to work from
151 * @param[in] type Which syscall will this be
152 * @param[in] pstate Where to put the newly created private_data state
153 * @retval The new request
155 * This is a helper function to prepare a new struct async_req with an
156 * associated struct async_syscall_state. The async_syscall_state will be put
157 * into the async_req as private_data.
160 static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx,
161 struct tevent_context *ev,
162 enum async_syscall_type type,
163 struct async_syscall_state **pstate)
165 struct async_req *result;
166 struct async_syscall_state *state;
168 if (!async_req_setup(mem_ctx, &result, &state,
169 struct async_syscall_state)) {
172 state->syscall_type = type;
174 result->private_data = state;
182 * @brief Create a new async syscall req based on a fd
183 * @param[in] mem_ctx The memory context to hang the result off
184 * @param[in] ev The event context to work from
185 * @param[in] type Which syscall will this be
186 * @param[in] fd The file descriptor we work on
187 * @param[in] fde_flags TEVENT_FD_READ/WRITE -- what are we interested in?
188 * @param[in] fde_cb The callback function for the file descriptor event
189 * @param[in] pstate Where to put the newly created private_data state
190 * @retval The new request
192 * This is a helper function to prepare a new struct async_req with an
193 * associated struct async_syscall_state and an associated file descriptor
197 static struct async_req *async_fde_syscall_new(
199 struct tevent_context *ev,
200 enum async_syscall_type type,
203 void (*fde_cb)(struct tevent_context *ev,
204 struct tevent_fd *fde, uint16_t flags,
206 struct async_syscall_state **pstate)
208 struct async_req *result;
209 struct async_syscall_state *state;
211 result = async_syscall_new(mem_ctx, ev, type, &state);
212 if (result == NULL) {
216 state->fde = tevent_add_fd(ev, state, fd, fde_flags, fde_cb, result);
217 if (state->fde == NULL) {
226 * Retrieve a ssize_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 ssize_t async_syscall_result_ssize_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_ssize_t;
242 * Retrieve a size_t 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 size_t async_syscall_result_size_t(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_size_t;
258 * Retrieve a int typed result from an async syscall
259 * @param[in] req The syscall that has just finished
260 * @param[out] perrno Where to put the syscall's errno
261 * @retval The return value from the asynchronously called syscall
264 int async_syscall_result_int(struct async_req *req, int *perrno)
266 struct async_syscall_state *state = talloc_get_type_abort(
267 req->private_data, struct async_syscall_state);
269 *perrno = state->sys_errno;
270 return state->result.result_int;
274 * fde event handler for the "send" syscall
275 * @param[in] ev The event context that sent us here
276 * @param[in] fde The file descriptor event associated with the send
277 * @param[in] flags Can only be TEVENT_FD_WRITE here
278 * @param[in] priv private data, "struct async_req *" in this case
281 static void async_send_callback(struct tevent_context *ev,
282 struct tevent_fd *fde, uint16_t flags,
285 struct async_req *req = talloc_get_type_abort(
286 priv, struct async_req);
287 struct async_syscall_state *state = talloc_get_type_abort(
288 req->private_data, struct async_syscall_state);
289 struct param_send *p = &state->param.param_send;
291 if (state->syscall_type != ASYNC_SYSCALL_SEND) {
292 async_req_error(req, EIO);
296 state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
298 state->sys_errno = errno;
300 TALLOC_FREE(state->fde);
306 * Async version of send(2)
307 * @param[in] mem_ctx The memory context to hang the result off
308 * @param[in] ev The event context to work from
309 * @param[in] fd The socket to send to
310 * @param[in] buffer The buffer to send
311 * @param[in] length How many bytes to send
312 * @param[in] flags flags passed to send(2)
314 * This function is a direct counterpart of send(2)
317 struct async_req *async_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
318 int fd, const void *buffer, size_t length,
321 struct async_req *result;
322 struct async_syscall_state *state;
324 result = async_fde_syscall_new(
325 mem_ctx, ev, ASYNC_SYSCALL_SEND,
326 fd, TEVENT_FD_WRITE, async_send_callback,
328 if (result == NULL) {
332 state->param.param_send.fd = fd;
333 state->param.param_send.buffer = buffer;
334 state->param.param_send.length = length;
335 state->param.param_send.flags = flags;
341 * fde event handler for the "sendall" syscall group
342 * @param[in] ev The event context that sent us here
343 * @param[in] fde The file descriptor event associated with the send
344 * @param[in] flags Can only be TEVENT_FD_WRITE here
345 * @param[in] priv private data, "struct async_req *" in this case
348 static void async_sendall_callback(struct tevent_context *ev,
349 struct tevent_fd *fde, uint16_t flags,
352 struct async_req *req = talloc_get_type_abort(
353 priv, struct async_req);
354 struct async_syscall_state *state = talloc_get_type_abort(
355 req->private_data, struct async_syscall_state);
356 struct param_sendall *p = &state->param.param_sendall;
358 if (state->syscall_type != ASYNC_SYSCALL_SENDALL) {
359 async_req_error(req, EIO);
363 state->result.result_ssize_t = send(p->fd,
364 (const char *)p->buffer + p->sent,
365 p->length - p->sent, p->flags);
366 state->sys_errno = errno;
368 if (state->result.result_ssize_t == -1) {
369 async_req_error(req, state->sys_errno);
373 if (state->result.result_ssize_t == 0) {
374 async_req_error(req, EOF);
378 p->sent += state->result.result_ssize_t;
379 if (p->sent > p->length) {
380 async_req_error(req, EIO);
384 if (p->sent == p->length) {
385 TALLOC_FREE(state->fde);
391 * @brief Send all bytes to a socket
392 * @param[in] mem_ctx The memory context to hang the result off
393 * @param[in] ev The event context to work from
394 * @param[in] fd The socket to send to
395 * @param[in] buffer The buffer to send
396 * @param[in] length How many bytes to send
397 * @param[in] flags flags passed to send(2)
399 * async_sendall calls send(2) as long as it is necessary to send all of the
403 struct async_req *sendall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
404 int fd, const void *buffer, size_t length,
407 struct async_req *result;
408 struct async_syscall_state *state;
410 result = async_fde_syscall_new(
411 mem_ctx, ev, ASYNC_SYSCALL_SENDALL,
412 fd, TEVENT_FD_WRITE, async_sendall_callback,
414 if (result == NULL) {
418 state->param.param_sendall.fd = fd;
419 state->param.param_sendall.buffer = buffer;
420 state->param.param_sendall.length = length;
421 state->param.param_sendall.flags = flags;
422 state->param.param_sendall.sent = 0;
427 ssize_t sendall_recv(struct async_req *req, int *perr)
429 struct async_syscall_state *state = talloc_get_type_abort(
430 req->private_data, struct async_syscall_state);
433 err = async_req_simple_recv_errno(req);
440 return state->result.result_ssize_t;
444 * fde event handler for the "recv" syscall
445 * @param[in] ev The event context that sent us here
446 * @param[in] fde The file descriptor event associated with the recv
447 * @param[in] flags Can only be TEVENT_FD_READ here
448 * @param[in] priv private data, "struct async_req *" in this case
451 static void async_recv_callback(struct tevent_context *ev,
452 struct tevent_fd *fde, uint16_t flags,
455 struct async_req *req = talloc_get_type_abort(
456 priv, struct async_req);
457 struct async_syscall_state *state = talloc_get_type_abort(
458 req->private_data, struct async_syscall_state);
459 struct param_recv *p = &state->param.param_recv;
461 if (state->syscall_type != ASYNC_SYSCALL_RECV) {
462 async_req_error(req, EIO);
466 state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
468 state->sys_errno = errno;
470 TALLOC_FREE(state->fde);
476 * Async version of recv(2)
477 * @param[in] mem_ctx The memory context to hang the result off
478 * @param[in] ev The event context to work from
479 * @param[in] fd The socket to recv from
480 * @param[in] buffer The buffer to recv into
481 * @param[in] length How many bytes to recv
482 * @param[in] flags flags passed to recv(2)
484 * This function is a direct counterpart of recv(2)
487 struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
488 int fd, void *buffer, size_t length,
491 struct async_req *result;
492 struct async_syscall_state *state;
494 result = async_fde_syscall_new(
495 mem_ctx, ev, ASYNC_SYSCALL_RECV,
496 fd, TEVENT_FD_READ, async_recv_callback,
499 if (result == NULL) {
503 state->param.param_recv.fd = fd;
504 state->param.param_recv.buffer = buffer;
505 state->param.param_recv.length = length;
506 state->param.param_recv.flags = flags;
512 * fde event handler for the "recvall" syscall group
513 * @param[in] ev The event context that sent us here
514 * @param[in] fde The file descriptor event associated with the recv
515 * @param[in] flags Can only be TEVENT_FD_READ here
516 * @param[in] priv private data, "struct async_req *" in this case
519 static void async_recvall_callback(struct tevent_context *ev,
520 struct tevent_fd *fde, uint16_t flags,
523 struct async_req *req = talloc_get_type_abort(
524 priv, struct async_req);
525 struct async_syscall_state *state = talloc_get_type_abort(
526 req->private_data, struct async_syscall_state);
527 struct param_recvall *p = &state->param.param_recvall;
529 if (state->syscall_type != ASYNC_SYSCALL_RECVALL) {
530 async_req_error(req, EIO);
534 state->result.result_ssize_t = recv(p->fd,
535 (char *)p->buffer + p->received,
536 p->length - p->received, p->flags);
537 state->sys_errno = errno;
539 if (state->result.result_ssize_t == -1) {
540 async_req_error(req, state->sys_errno);
544 if (state->result.result_ssize_t == 0) {
545 async_req_error(req, EIO);
549 p->received += state->result.result_ssize_t;
550 if (p->received > p->length) {
551 async_req_error(req, EIO);
555 if (p->received == p->length) {
556 TALLOC_FREE(state->fde);
562 * Receive a specified number of bytes from a socket
563 * @param[in] mem_ctx The memory context to hang the result off
564 * @param[in] ev The event context to work from
565 * @param[in] fd The socket to recv from
566 * @param[in] buffer The buffer to recv into
567 * @param[in] length How many bytes to recv
568 * @param[in] flags flags passed to recv(2)
570 * async_recvall will call recv(2) until "length" bytes are received
573 struct async_req *recvall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
574 int fd, void *buffer, size_t length,
577 struct async_req *result;
578 struct async_syscall_state *state;
580 result = async_fde_syscall_new(
581 mem_ctx, ev, ASYNC_SYSCALL_RECVALL,
582 fd, TEVENT_FD_READ, async_recvall_callback,
584 if (result == NULL) {
588 state->param.param_recvall.fd = fd;
589 state->param.param_recvall.buffer = buffer;
590 state->param.param_recvall.length = length;
591 state->param.param_recvall.flags = flags;
592 state->param.param_recvall.received = 0;
597 ssize_t recvall_recv(struct async_req *req, int *perr)
599 struct async_syscall_state *state = talloc_get_type_abort(
600 req->private_data, struct async_syscall_state);
603 err = async_req_simple_recv_errno(req);
610 return state->result.result_ssize_t;
613 struct async_connect_state {
620 static void async_connect_connected(struct tevent_context *ev,
621 struct tevent_fd *fde, uint16_t flags,
625 * @brief async version of connect(2)
626 * @param[in] mem_ctx The memory context to hang the result off
627 * @param[in] ev The event context to work from
628 * @param[in] fd The socket to recv from
629 * @param[in] address Where to connect?
630 * @param[in] address_len Length of *address
631 * @retval The async request
633 * This function sets the socket into non-blocking state to be able to call
634 * connect in an async state. This will be reset when the request is finished.
637 struct tevent_req *async_connect_send(TALLOC_CTX *mem_ctx,
638 struct tevent_context *ev,
639 int fd, const struct sockaddr *address,
640 socklen_t address_len)
642 struct tevent_req *result;
643 struct async_connect_state *state;
644 struct tevent_fd *fde;
646 result = tevent_req_create(
647 mem_ctx, &state, struct async_connect_state);
648 if (result == NULL) {
653 * We have to set the socket to nonblocking for async connect(2). Keep
654 * the old sockflags around.
658 state->sys_errno = 0;
660 state->old_sockflags = fcntl(fd, F_GETFL, 0);
661 if (state->old_sockflags == -1) {
665 set_blocking(fd, false);
667 state->result = connect(fd, address, address_len);
668 if (state->result == 0) {
674 * A number of error messages show that something good is progressing
675 * and that we have to wait for readability.
677 * If none of them are present, bail out.
680 if (!(errno == EINPROGRESS || errno == EALREADY ||
684 errno == EAGAIN || errno == EINTR)) {
688 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
689 async_connect_connected, result);
697 state->sys_errno = errno;
698 fcntl(fd, F_SETFL, state->old_sockflags);
699 if (state->sys_errno == 0) {
700 tevent_req_done(result);
702 tevent_req_error(result, state->sys_errno);
704 return tevent_req_post(result, ev);
708 * fde event handler for connect(2)
709 * @param[in] ev The event context that sent us here
710 * @param[in] fde The file descriptor event associated with the connect
711 * @param[in] flags Indicate read/writeability of the socket
712 * @param[in] priv private data, "struct async_req *" in this case
715 static void async_connect_connected(struct tevent_context *ev,
716 struct tevent_fd *fde, uint16_t flags,
719 struct tevent_req *req = talloc_get_type_abort(
720 priv, struct tevent_req);
721 struct async_connect_state *state = talloc_get_type_abort(
722 req->private_state, struct async_connect_state);
727 * Stevens, Network Programming says that if there's a
728 * successful connect, the socket is only writable. Upon an
729 * error, it's both readable and writable.
731 if ((flags & (TEVENT_FD_READ|TEVENT_FD_WRITE))
732 == (TEVENT_FD_READ|TEVENT_FD_WRITE)) {
734 socklen_t err_len = sizeof(sockerr);
736 if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
737 (void *)&sockerr, &err_len) == 0) {
741 state->sys_errno = errno;
743 DEBUG(10, ("connect returned %s\n", strerror(errno)));
745 fcntl(state->fd, F_SETFL, state->old_sockflags);
746 tevent_req_error(req, state->sys_errno);
750 state->sys_errno = 0;
751 tevent_req_done(req);
754 int async_connect_recv(struct tevent_req *req, int *perrno)
756 struct async_connect_state *state = talloc_get_type_abort(
757 req->private_state, struct async_connect_state);
760 fcntl(state->fd, F_SETFL, state->old_sockflags);
762 if (tevent_req_is_unix_error(req, &err)) {
767 if (state->sys_errno == 0) {
771 *perrno = state->sys_errno;
775 struct writev_state {
776 struct tevent_context *ev;
783 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
784 uint16_t flags, void *private_data);
786 struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
787 int fd, struct iovec *iov, int count)
789 struct tevent_req *result;
790 struct writev_state *state;
791 struct tevent_fd *fde;
793 result = tevent_req_create(mem_ctx, &state, struct writev_state);
794 if (result == NULL) {
799 state->total_size = 0;
800 state->count = count;
801 state->iov = (struct iovec *)talloc_memdup(
802 state, iov, sizeof(struct iovec) * count);
803 if (state->iov == NULL) {
807 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, writev_handler,
819 static void writev_handler(struct tevent_context *ev, 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 writev_state *state = talloc_get_type_abort(
825 req->private_state, struct writev_state);
826 size_t to_write, written;
831 for (i=0; i<state->count; i++) {
832 to_write += state->iov[i].iov_len;
835 written = sys_writev(state->fd, state->iov, state->count);
837 tevent_req_error(req, errno);
841 tevent_req_error(req, EOF);
844 state->total_size += written;
846 if (written == to_write) {
847 tevent_req_done(req);
852 * We've written less than we were asked to, drop stuff from
856 while (written > 0) {
857 if (written < state->iov[0].iov_len) {
858 state->iov[0].iov_base =
859 (char *)state->iov[0].iov_base + written;
860 state->iov[0].iov_len -= written;
863 written = state->iov[0].iov_len;
869 ssize_t writev_recv(struct tevent_req *req, int *perrno)
871 struct writev_state *state = talloc_get_type_abort(
872 req->private_state, struct writev_state);
874 if (tevent_req_is_unix_error(req, perrno)) {
877 return state->total_size;