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"
28 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
32 * Discriminator for async_syscall_state
34 enum async_syscall_type {
36 ASYNC_SYSCALL_SENDALL,
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;
57 struct param_sendall {
70 struct param_recvall {
77 struct param_connect {
79 * connect needs to be done on a nonblocking
80 * socket. Keep the old flags around
84 const struct sockaddr *address;
85 socklen_t address_len;
90 ssize_t result_ssize_t;
98 * @brief Map async_req states to unix-style errnos
99 * @param[in] req The async req to get the state from
100 * @param[out] err Pointer to take the unix-style errno
102 * @return true if the async_req is in an error state, false otherwise
105 bool async_req_is_errno(struct async_req *req, int *err)
107 enum async_req_state state;
110 if (!async_req_is_error(req, &state, &error)) {
115 case ASYNC_REQ_USER_ERROR:
118 case ASYNC_REQ_TIMED_OUT:
119 #ifdef HAVE_ETIMEDOUT
125 case ASYNC_REQ_NO_MEMORY:
135 int async_req_simple_recv_errno(struct async_req *req)
139 if (async_req_is_errno(req, &err)) {
147 * @brief Create a new async syscall req
148 * @param[in] mem_ctx The memory context to hang the result off
149 * @param[in] ev The event context to work from
150 * @param[in] type Which syscall will this be
151 * @param[in] pstate Where to put the newly created private_data state
152 * @retval The new request
154 * This is a helper function to prepare a new struct async_req with an
155 * associated struct async_syscall_state. The async_syscall_state will be put
156 * into the async_req as private_data.
159 static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx,
160 struct tevent_context *ev,
161 enum async_syscall_type type,
162 struct async_syscall_state **pstate)
164 struct async_req *result;
165 struct async_syscall_state *state;
167 if (!async_req_setup(mem_ctx, &result, &state,
168 struct async_syscall_state)) {
171 state->syscall_type = type;
173 result->private_data = state;
181 * @brief Create a new async syscall req based on a fd
182 * @param[in] mem_ctx The memory context to hang the result off
183 * @param[in] ev The event context to work from
184 * @param[in] type Which syscall will this be
185 * @param[in] fd The file descriptor we work on
186 * @param[in] fde_flags TEVENT_FD_READ/WRITE -- what are we interested in?
187 * @param[in] fde_cb The callback function for the file descriptor event
188 * @param[in] pstate Where to put the newly created private_data state
189 * @retval The new request
191 * This is a helper function to prepare a new struct async_req with an
192 * associated struct async_syscall_state and an associated file descriptor
196 static struct async_req *async_fde_syscall_new(
198 struct tevent_context *ev,
199 enum async_syscall_type type,
202 void (*fde_cb)(struct tevent_context *ev,
203 struct tevent_fd *fde, uint16_t flags,
205 struct async_syscall_state **pstate)
207 struct async_req *result;
208 struct async_syscall_state *state;
210 result = async_syscall_new(mem_ctx, ev, type, &state);
211 if (result == NULL) {
215 state->fde = tevent_add_fd(ev, state, fd, fde_flags, fde_cb, result);
216 if (state->fde == NULL) {
225 * Retrieve a ssize_t typed result from an async syscall
226 * @param[in] req The syscall that has just finished
227 * @param[out] perrno Where to put the syscall's errno
228 * @retval The return value from the asynchronously called syscall
231 ssize_t async_syscall_result_ssize_t(struct async_req *req, int *perrno)
233 struct async_syscall_state *state = talloc_get_type_abort(
234 req->private_data, struct async_syscall_state);
236 *perrno = state->sys_errno;
237 return state->result.result_ssize_t;
241 * Retrieve a size_t typed result from an async syscall
242 * @param[in] req The syscall that has just finished
243 * @param[out] perrno Where to put the syscall's errno
244 * @retval The return value from the asynchronously called syscall
247 size_t async_syscall_result_size_t(struct async_req *req, int *perrno)
249 struct async_syscall_state *state = talloc_get_type_abort(
250 req->private_data, struct async_syscall_state);
252 *perrno = state->sys_errno;
253 return state->result.result_size_t;
257 * Retrieve a int typed result from an async syscall
258 * @param[in] req The syscall that has just finished
259 * @param[out] perrno Where to put the syscall's errno
260 * @retval The return value from the asynchronously called syscall
263 int async_syscall_result_int(struct async_req *req, int *perrno)
265 struct async_syscall_state *state = talloc_get_type_abort(
266 req->private_data, struct async_syscall_state);
268 *perrno = state->sys_errno;
269 return state->result.result_int;
273 * fde event handler for the "send" syscall
274 * @param[in] ev The event context that sent us here
275 * @param[in] fde The file descriptor event associated with the send
276 * @param[in] flags Can only be TEVENT_FD_WRITE here
277 * @param[in] priv private data, "struct async_req *" in this case
280 static void async_send_callback(struct tevent_context *ev,
281 struct tevent_fd *fde, uint16_t flags,
284 struct async_req *req = talloc_get_type_abort(
285 priv, struct async_req);
286 struct async_syscall_state *state = talloc_get_type_abort(
287 req->private_data, struct async_syscall_state);
288 struct param_send *p = &state->param.param_send;
290 if (state->syscall_type != ASYNC_SYSCALL_SEND) {
291 async_req_error(req, EIO);
295 state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
297 state->sys_errno = errno;
299 TALLOC_FREE(state->fde);
305 * Async version of send(2)
306 * @param[in] mem_ctx The memory context to hang the result off
307 * @param[in] ev The event context to work from
308 * @param[in] fd The socket to send to
309 * @param[in] buffer The buffer to send
310 * @param[in] length How many bytes to send
311 * @param[in] flags flags passed to send(2)
313 * This function is a direct counterpart of send(2)
316 struct async_req *async_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
317 int fd, const void *buffer, size_t length,
320 struct async_req *result;
321 struct async_syscall_state *state;
323 result = async_fde_syscall_new(
324 mem_ctx, ev, ASYNC_SYSCALL_SEND,
325 fd, TEVENT_FD_WRITE, async_send_callback,
327 if (result == NULL) {
331 state->param.param_send.fd = fd;
332 state->param.param_send.buffer = buffer;
333 state->param.param_send.length = length;
334 state->param.param_send.flags = flags;
340 * fde event handler for the "sendall" syscall group
341 * @param[in] ev The event context that sent us here
342 * @param[in] fde The file descriptor event associated with the send
343 * @param[in] flags Can only be TEVENT_FD_WRITE here
344 * @param[in] priv private data, "struct async_req *" in this case
347 static void async_sendall_callback(struct tevent_context *ev,
348 struct tevent_fd *fde, uint16_t flags,
351 struct async_req *req = talloc_get_type_abort(
352 priv, struct async_req);
353 struct async_syscall_state *state = talloc_get_type_abort(
354 req->private_data, struct async_syscall_state);
355 struct param_sendall *p = &state->param.param_sendall;
357 if (state->syscall_type != ASYNC_SYSCALL_SENDALL) {
358 async_req_error(req, EIO);
362 state->result.result_ssize_t = send(p->fd,
363 (const char *)p->buffer + p->sent,
364 p->length - p->sent, p->flags);
365 state->sys_errno = errno;
367 if (state->result.result_ssize_t == -1) {
368 async_req_error(req, state->sys_errno);
372 if (state->result.result_ssize_t == 0) {
373 async_req_error(req, EOF);
377 p->sent += state->result.result_ssize_t;
378 if (p->sent > p->length) {
379 async_req_error(req, EIO);
383 if (p->sent == p->length) {
384 TALLOC_FREE(state->fde);
390 * @brief Send all bytes to a socket
391 * @param[in] mem_ctx The memory context to hang the result off
392 * @param[in] ev The event context to work from
393 * @param[in] fd The socket to send to
394 * @param[in] buffer The buffer to send
395 * @param[in] length How many bytes to send
396 * @param[in] flags flags passed to send(2)
398 * async_sendall calls send(2) as long as it is necessary to send all of the
402 struct async_req *sendall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
403 int fd, const void *buffer, size_t length,
406 struct async_req *result;
407 struct async_syscall_state *state;
409 result = async_fde_syscall_new(
410 mem_ctx, ev, ASYNC_SYSCALL_SENDALL,
411 fd, TEVENT_FD_WRITE, async_sendall_callback,
413 if (result == NULL) {
417 state->param.param_sendall.fd = fd;
418 state->param.param_sendall.buffer = buffer;
419 state->param.param_sendall.length = length;
420 state->param.param_sendall.flags = flags;
421 state->param.param_sendall.sent = 0;
426 ssize_t sendall_recv(struct async_req *req, int *perr)
428 struct async_syscall_state *state = talloc_get_type_abort(
429 req->private_data, struct async_syscall_state);
432 err = async_req_simple_recv_errno(req);
439 return state->result.result_ssize_t;
443 * fde event handler for the "recv" syscall
444 * @param[in] ev The event context that sent us here
445 * @param[in] fde The file descriptor event associated with the recv
446 * @param[in] flags Can only be TEVENT_FD_READ here
447 * @param[in] priv private data, "struct async_req *" in this case
450 static void async_recv_callback(struct tevent_context *ev,
451 struct tevent_fd *fde, uint16_t flags,
454 struct async_req *req = talloc_get_type_abort(
455 priv, struct async_req);
456 struct async_syscall_state *state = talloc_get_type_abort(
457 req->private_data, struct async_syscall_state);
458 struct param_recv *p = &state->param.param_recv;
460 if (state->syscall_type != ASYNC_SYSCALL_RECV) {
461 async_req_error(req, EIO);
465 state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
467 state->sys_errno = errno;
469 TALLOC_FREE(state->fde);
475 * Async version of recv(2)
476 * @param[in] mem_ctx The memory context to hang the result off
477 * @param[in] ev The event context to work from
478 * @param[in] fd The socket to recv from
479 * @param[in] buffer The buffer to recv into
480 * @param[in] length How many bytes to recv
481 * @param[in] flags flags passed to recv(2)
483 * This function is a direct counterpart of recv(2)
486 struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
487 int fd, void *buffer, size_t length,
490 struct async_req *result;
491 struct async_syscall_state *state;
493 result = async_fde_syscall_new(
494 mem_ctx, ev, ASYNC_SYSCALL_RECV,
495 fd, TEVENT_FD_READ, async_recv_callback,
498 if (result == NULL) {
502 state->param.param_recv.fd = fd;
503 state->param.param_recv.buffer = buffer;
504 state->param.param_recv.length = length;
505 state->param.param_recv.flags = flags;
511 * fde event handler for the "recvall" syscall group
512 * @param[in] ev The event context that sent us here
513 * @param[in] fde The file descriptor event associated with the recv
514 * @param[in] flags Can only be TEVENT_FD_READ here
515 * @param[in] priv private data, "struct async_req *" in this case
518 static void async_recvall_callback(struct tevent_context *ev,
519 struct tevent_fd *fde, uint16_t flags,
522 struct async_req *req = talloc_get_type_abort(
523 priv, struct async_req);
524 struct async_syscall_state *state = talloc_get_type_abort(
525 req->private_data, struct async_syscall_state);
526 struct param_recvall *p = &state->param.param_recvall;
528 if (state->syscall_type != ASYNC_SYSCALL_RECVALL) {
529 async_req_error(req, EIO);
533 state->result.result_ssize_t = recv(p->fd,
534 (char *)p->buffer + p->received,
535 p->length - p->received, p->flags);
536 state->sys_errno = errno;
538 if (state->result.result_ssize_t == -1) {
539 async_req_error(req, state->sys_errno);
543 if (state->result.result_ssize_t == 0) {
544 async_req_error(req, EIO);
548 p->received += state->result.result_ssize_t;
549 if (p->received > p->length) {
550 async_req_error(req, EIO);
554 if (p->received == p->length) {
555 TALLOC_FREE(state->fde);
561 * Receive a specified number of bytes from a socket
562 * @param[in] mem_ctx The memory context to hang the result off
563 * @param[in] ev The event context to work from
564 * @param[in] fd The socket to recv from
565 * @param[in] buffer The buffer to recv into
566 * @param[in] length How many bytes to recv
567 * @param[in] flags flags passed to recv(2)
569 * async_recvall will call recv(2) until "length" bytes are received
572 struct async_req *recvall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
573 int fd, void *buffer, size_t length,
576 struct async_req *result;
577 struct async_syscall_state *state;
579 result = async_fde_syscall_new(
580 mem_ctx, ev, ASYNC_SYSCALL_RECVALL,
581 fd, TEVENT_FD_READ, async_recvall_callback,
583 if (result == NULL) {
587 state->param.param_recvall.fd = fd;
588 state->param.param_recvall.buffer = buffer;
589 state->param.param_recvall.length = length;
590 state->param.param_recvall.flags = flags;
591 state->param.param_recvall.received = 0;
596 ssize_t recvall_recv(struct async_req *req, int *perr)
598 struct async_syscall_state *state = talloc_get_type_abort(
599 req->private_data, struct async_syscall_state);
602 err = async_req_simple_recv_errno(req);
609 return state->result.result_ssize_t;
612 struct async_connect_state {
619 static void async_connect_connected(struct tevent_context *ev,
620 struct tevent_fd *fde, uint16_t flags,
624 * @brief async version of connect(2)
625 * @param[in] mem_ctx The memory context to hang the result off
626 * @param[in] ev The event context to work from
627 * @param[in] fd The socket to recv from
628 * @param[in] address Where to connect?
629 * @param[in] address_len Length of *address
630 * @retval The async request
632 * This function sets the socket into non-blocking state to be able to call
633 * connect in an async state. This will be reset when the request is finished.
636 struct async_req *async_connect_send(TALLOC_CTX *mem_ctx,
637 struct tevent_context *ev,
638 int fd, const struct sockaddr *address,
639 socklen_t address_len)
641 struct async_req *result;
642 struct async_connect_state *state;
643 struct tevent_fd *fde;
645 if (!async_req_setup(mem_ctx, &result, &state,
646 struct async_connect_state)) {
651 * We have to set the socket to nonblocking for async connect(2). Keep
652 * the old sockflags around.
656 state->sys_errno = 0;
658 state->old_sockflags = fcntl(fd, F_GETFL, 0);
659 if (state->old_sockflags == -1) {
663 set_blocking(fd, false);
665 state->result = connect(fd, address, address_len);
666 if (state->result == 0) {
667 state->sys_errno = 0;
672 * A number of error messages show that something good is progressing
673 * and that we have to wait for readability.
675 * If none of them are present, bail out.
678 if (!(errno == EINPROGRESS || errno == EALREADY ||
682 errno == EAGAIN || errno == EINTR)) {
686 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
687 async_connect_connected, result);
689 state->sys_errno = ENOMEM;
695 state->sys_errno = errno;
697 fcntl(fd, F_SETFL, state->old_sockflags);
698 if (!async_post_error(result, ev, state->sys_errno)) {
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 async_req *req = talloc_get_type_abort(
720 priv, struct async_req);
721 struct async_connect_state *state = talloc_get_type_abort(
722 req->private_data, 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 async_req_error(req, state->sys_errno);
750 state->sys_errno = 0;
754 int async_connect_recv(struct async_req *req, int *perrno)
756 struct async_connect_state *state = talloc_get_type_abort(
757 req->private_data, struct async_connect_state);
760 fcntl(state->fd, F_SETFL, state->old_sockflags);
763 if (async_req_is_errno(req, &err)) {
767 if (state->sys_errno == 0) {
771 *perrno = state->sys_errno;