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:
121 case ASYNC_REQ_NO_MEMORY:
131 int async_req_simple_recv_errno(struct async_req *req)
135 if (async_req_is_errno(req, &err)) {
143 * @brief Create a new async syscall req
144 * @param[in] mem_ctx The memory context to hang the result off
145 * @param[in] ev The event context to work from
146 * @param[in] type Which syscall will this be
147 * @param[in] pstate Where to put the newly created private_data state
148 * @retval The new request
150 * This is a helper function to prepare a new struct async_req with an
151 * associated struct async_syscall_state. The async_syscall_state will be put
152 * into the async_req as private_data.
155 static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx,
156 struct tevent_context *ev,
157 enum async_syscall_type type,
158 struct async_syscall_state **pstate)
160 struct async_req *result;
161 struct async_syscall_state *state;
163 if (!async_req_setup(mem_ctx, &result, &state,
164 struct async_syscall_state)) {
167 state->syscall_type = type;
169 result->private_data = state;
177 * @brief Create a new async syscall req based on a fd
178 * @param[in] mem_ctx The memory context to hang the result off
179 * @param[in] ev The event context to work from
180 * @param[in] type Which syscall will this be
181 * @param[in] fd The file descriptor we work on
182 * @param[in] fde_flags TEVENT_FD_READ/WRITE -- what are we interested in?
183 * @param[in] fde_cb The callback function for the file descriptor event
184 * @param[in] pstate Where to put the newly created private_data state
185 * @retval The new request
187 * This is a helper function to prepare a new struct async_req with an
188 * associated struct async_syscall_state and an associated file descriptor
192 static struct async_req *async_fde_syscall_new(
194 struct tevent_context *ev,
195 enum async_syscall_type type,
198 void (*fde_cb)(struct tevent_context *ev,
199 struct tevent_fd *fde, uint16_t flags,
201 struct async_syscall_state **pstate)
203 struct async_req *result;
204 struct async_syscall_state *state;
206 result = async_syscall_new(mem_ctx, ev, type, &state);
207 if (result == NULL) {
211 state->fde = tevent_add_fd(ev, state, fd, fde_flags, fde_cb, result);
212 if (state->fde == NULL) {
221 * Retrieve a ssize_t typed result from an async syscall
222 * @param[in] req The syscall that has just finished
223 * @param[out] perrno Where to put the syscall's errno
224 * @retval The return value from the asynchronously called syscall
227 ssize_t async_syscall_result_ssize_t(struct async_req *req, int *perrno)
229 struct async_syscall_state *state = talloc_get_type_abort(
230 req->private_data, struct async_syscall_state);
232 *perrno = state->sys_errno;
233 return state->result.result_ssize_t;
237 * Retrieve a size_t typed result from an async syscall
238 * @param[in] req The syscall that has just finished
239 * @param[out] perrno Where to put the syscall's errno
240 * @retval The return value from the asynchronously called syscall
243 size_t async_syscall_result_size_t(struct async_req *req, int *perrno)
245 struct async_syscall_state *state = talloc_get_type_abort(
246 req->private_data, struct async_syscall_state);
248 *perrno = state->sys_errno;
249 return state->result.result_size_t;
253 * Retrieve a int typed result from an async syscall
254 * @param[in] req The syscall that has just finished
255 * @param[out] perrno Where to put the syscall's errno
256 * @retval The return value from the asynchronously called syscall
259 int async_syscall_result_int(struct async_req *req, int *perrno)
261 struct async_syscall_state *state = talloc_get_type_abort(
262 req->private_data, struct async_syscall_state);
264 *perrno = state->sys_errno;
265 return state->result.result_int;
269 * fde event handler for the "send" syscall
270 * @param[in] ev The event context that sent us here
271 * @param[in] fde The file descriptor event associated with the send
272 * @param[in] flags Can only be TEVENT_FD_WRITE here
273 * @param[in] priv private data, "struct async_req *" in this case
276 static void async_send_callback(struct tevent_context *ev,
277 struct tevent_fd *fde, uint16_t flags,
280 struct async_req *req = talloc_get_type_abort(
281 priv, struct async_req);
282 struct async_syscall_state *state = talloc_get_type_abort(
283 req->private_data, struct async_syscall_state);
284 struct param_send *p = &state->param.param_send;
286 if (state->syscall_type != ASYNC_SYSCALL_SEND) {
287 async_req_error(req, EIO);
291 state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
293 state->sys_errno = errno;
295 TALLOC_FREE(state->fde);
301 * Async version of send(2)
302 * @param[in] mem_ctx The memory context to hang the result off
303 * @param[in] ev The event context to work from
304 * @param[in] fd The socket to send to
305 * @param[in] buffer The buffer to send
306 * @param[in] length How many bytes to send
307 * @param[in] flags flags passed to send(2)
309 * This function is a direct counterpart of send(2)
312 struct async_req *async_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
313 int fd, const void *buffer, size_t length,
316 struct async_req *result;
317 struct async_syscall_state *state;
319 result = async_fde_syscall_new(
320 mem_ctx, ev, ASYNC_SYSCALL_SEND,
321 fd, TEVENT_FD_WRITE, async_send_callback,
323 if (result == NULL) {
327 state->param.param_send.fd = fd;
328 state->param.param_send.buffer = buffer;
329 state->param.param_send.length = length;
330 state->param.param_send.flags = flags;
336 * fde event handler for the "sendall" syscall group
337 * @param[in] ev The event context that sent us here
338 * @param[in] fde The file descriptor event associated with the send
339 * @param[in] flags Can only be TEVENT_FD_WRITE here
340 * @param[in] priv private data, "struct async_req *" in this case
343 static void async_sendall_callback(struct tevent_context *ev,
344 struct tevent_fd *fde, uint16_t flags,
347 struct async_req *req = talloc_get_type_abort(
348 priv, struct async_req);
349 struct async_syscall_state *state = talloc_get_type_abort(
350 req->private_data, struct async_syscall_state);
351 struct param_sendall *p = &state->param.param_sendall;
353 if (state->syscall_type != ASYNC_SYSCALL_SENDALL) {
354 async_req_error(req, EIO);
358 state->result.result_ssize_t = send(p->fd,
359 (const char *)p->buffer + p->sent,
360 p->length - p->sent, p->flags);
361 state->sys_errno = errno;
363 if (state->result.result_ssize_t == -1) {
364 async_req_error(req, state->sys_errno);
368 if (state->result.result_ssize_t == 0) {
369 async_req_error(req, EOF);
373 p->sent += state->result.result_ssize_t;
374 if (p->sent > p->length) {
375 async_req_error(req, EIO);
379 if (p->sent == p->length) {
380 TALLOC_FREE(state->fde);
386 * @brief Send all bytes to a socket
387 * @param[in] mem_ctx The memory context to hang the result off
388 * @param[in] ev The event context to work from
389 * @param[in] fd The socket to send to
390 * @param[in] buffer The buffer to send
391 * @param[in] length How many bytes to send
392 * @param[in] flags flags passed to send(2)
394 * async_sendall calls send(2) as long as it is necessary to send all of the
398 struct async_req *sendall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
399 int fd, const void *buffer, size_t length,
402 struct async_req *result;
403 struct async_syscall_state *state;
405 result = async_fde_syscall_new(
406 mem_ctx, ev, ASYNC_SYSCALL_SENDALL,
407 fd, TEVENT_FD_WRITE, async_sendall_callback,
409 if (result == NULL) {
413 state->param.param_sendall.fd = fd;
414 state->param.param_sendall.buffer = buffer;
415 state->param.param_sendall.length = length;
416 state->param.param_sendall.flags = flags;
417 state->param.param_sendall.sent = 0;
422 ssize_t sendall_recv(struct async_req *req, int *perr)
424 struct async_syscall_state *state = talloc_get_type_abort(
425 req->private_data, struct async_syscall_state);
428 err = async_req_simple_recv_errno(req);
435 return state->result.result_ssize_t;
439 * fde event handler for the "recv" syscall
440 * @param[in] ev The event context that sent us here
441 * @param[in] fde The file descriptor event associated with the recv
442 * @param[in] flags Can only be TEVENT_FD_READ here
443 * @param[in] priv private data, "struct async_req *" in this case
446 static void async_recv_callback(struct tevent_context *ev,
447 struct tevent_fd *fde, uint16_t flags,
450 struct async_req *req = talloc_get_type_abort(
451 priv, struct async_req);
452 struct async_syscall_state *state = talloc_get_type_abort(
453 req->private_data, struct async_syscall_state);
454 struct param_recv *p = &state->param.param_recv;
456 if (state->syscall_type != ASYNC_SYSCALL_RECV) {
457 async_req_error(req, EIO);
461 state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
463 state->sys_errno = errno;
465 TALLOC_FREE(state->fde);
471 * Async version of recv(2)
472 * @param[in] mem_ctx The memory context to hang the result off
473 * @param[in] ev The event context to work from
474 * @param[in] fd The socket to recv from
475 * @param[in] buffer The buffer to recv into
476 * @param[in] length How many bytes to recv
477 * @param[in] flags flags passed to recv(2)
479 * This function is a direct counterpart of recv(2)
482 struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
483 int fd, void *buffer, size_t length,
486 struct async_req *result;
487 struct async_syscall_state *state;
489 result = async_fde_syscall_new(
490 mem_ctx, ev, ASYNC_SYSCALL_RECV,
491 fd, TEVENT_FD_READ, async_recv_callback,
494 if (result == NULL) {
498 state->param.param_recv.fd = fd;
499 state->param.param_recv.buffer = buffer;
500 state->param.param_recv.length = length;
501 state->param.param_recv.flags = flags;
507 * fde event handler for the "recvall" syscall group
508 * @param[in] ev The event context that sent us here
509 * @param[in] fde The file descriptor event associated with the recv
510 * @param[in] flags Can only be TEVENT_FD_READ here
511 * @param[in] priv private data, "struct async_req *" in this case
514 static void async_recvall_callback(struct tevent_context *ev,
515 struct tevent_fd *fde, uint16_t flags,
518 struct async_req *req = talloc_get_type_abort(
519 priv, struct async_req);
520 struct async_syscall_state *state = talloc_get_type_abort(
521 req->private_data, struct async_syscall_state);
522 struct param_recvall *p = &state->param.param_recvall;
524 if (state->syscall_type != ASYNC_SYSCALL_RECVALL) {
525 async_req_error(req, EIO);
529 state->result.result_ssize_t = recv(p->fd,
530 (char *)p->buffer + p->received,
531 p->length - p->received, p->flags);
532 state->sys_errno = errno;
534 if (state->result.result_ssize_t == -1) {
535 async_req_error(req, state->sys_errno);
539 if (state->result.result_ssize_t == 0) {
540 async_req_error(req, EIO);
544 p->received += state->result.result_ssize_t;
545 if (p->received > p->length) {
546 async_req_error(req, EIO);
550 if (p->received == p->length) {
551 TALLOC_FREE(state->fde);
557 * Receive a specified number of bytes from a socket
558 * @param[in] mem_ctx The memory context to hang the result off
559 * @param[in] ev The event context to work from
560 * @param[in] fd The socket to recv from
561 * @param[in] buffer The buffer to recv into
562 * @param[in] length How many bytes to recv
563 * @param[in] flags flags passed to recv(2)
565 * async_recvall will call recv(2) until "length" bytes are received
568 struct async_req *recvall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
569 int fd, void *buffer, size_t length,
572 struct async_req *result;
573 struct async_syscall_state *state;
575 result = async_fde_syscall_new(
576 mem_ctx, ev, ASYNC_SYSCALL_RECVALL,
577 fd, TEVENT_FD_READ, async_recvall_callback,
579 if (result == NULL) {
583 state->param.param_recvall.fd = fd;
584 state->param.param_recvall.buffer = buffer;
585 state->param.param_recvall.length = length;
586 state->param.param_recvall.flags = flags;
587 state->param.param_recvall.received = 0;
592 ssize_t recvall_recv(struct async_req *req, int *perr)
594 struct async_syscall_state *state = talloc_get_type_abort(
595 req->private_data, struct async_syscall_state);
598 err = async_req_simple_recv_errno(req);
605 return state->result.result_ssize_t;
608 struct async_connect_state {
615 static void async_connect_connected(struct tevent_context *ev,
616 struct tevent_fd *fde, uint16_t flags,
620 * @brief async version of connect(2)
621 * @param[in] mem_ctx The memory context to hang the result off
622 * @param[in] ev The event context to work from
623 * @param[in] fd The socket to recv from
624 * @param[in] address Where to connect?
625 * @param[in] address_len Length of *address
626 * @retval The async request
628 * This function sets the socket into non-blocking state to be able to call
629 * connect in an async state. This will be reset when the request is finished.
632 struct async_req *async_connect_send(TALLOC_CTX *mem_ctx,
633 struct tevent_context *ev,
634 int fd, const struct sockaddr *address,
635 socklen_t address_len)
637 struct async_req *result;
638 struct async_connect_state *state;
639 struct tevent_fd *fde;
641 if (!async_req_setup(mem_ctx, &result, &state,
642 struct async_connect_state)) {
647 * We have to set the socket to nonblocking for async connect(2). Keep
648 * the old sockflags around.
652 state->sys_errno = 0;
654 state->old_sockflags = fcntl(fd, F_GETFL, 0);
655 if (state->old_sockflags == -1) {
659 set_blocking(fd, false);
661 state->result = connect(fd, address, address_len);
662 if (state->result == 0) {
663 state->sys_errno = 0;
668 * A number of error messages show that something good is progressing
669 * and that we have to wait for readability.
671 * If none of them are present, bail out.
674 if (!(errno == EINPROGRESS || errno == EALREADY ||
678 errno == EAGAIN || errno == EINTR)) {
682 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
683 async_connect_connected, result);
685 state->sys_errno = ENOMEM;
691 state->sys_errno = errno;
693 fcntl(fd, F_SETFL, state->old_sockflags);
694 if (!async_post_error(result, ev, state->sys_errno)) {
704 * fde event handler for connect(2)
705 * @param[in] ev The event context that sent us here
706 * @param[in] fde The file descriptor event associated with the connect
707 * @param[in] flags Indicate read/writeability of the socket
708 * @param[in] priv private data, "struct async_req *" in this case
711 static void async_connect_connected(struct tevent_context *ev,
712 struct tevent_fd *fde, uint16_t flags,
715 struct async_req *req = talloc_get_type_abort(
716 priv, struct async_req);
717 struct async_connect_state *state = talloc_get_type_abort(
718 req->private_data, struct async_connect_state);
723 * Stevens, Network Programming says that if there's a
724 * successful connect, the socket is only writable. Upon an
725 * error, it's both readable and writable.
727 if ((flags & (TEVENT_FD_READ|TEVENT_FD_WRITE))
728 == (TEVENT_FD_READ|TEVENT_FD_WRITE)) {
730 socklen_t err_len = sizeof(sockerr);
732 if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
733 (void *)&sockerr, &err_len) == 0) {
737 state->sys_errno = errno;
739 DEBUG(10, ("connect returned %s\n", strerror(errno)));
741 fcntl(state->fd, F_SETFL, state->old_sockflags);
742 async_req_error(req, state->sys_errno);
746 state->sys_errno = 0;
750 int async_connect_recv(struct async_req *req, int *perrno)
752 struct async_connect_state *state = talloc_get_type_abort(
753 req->private_data, struct async_connect_state);
756 fcntl(state->fd, F_SETFL, state->old_sockflags);
759 if (async_req_is_errno(req, &err)) {
763 if (state->sys_errno == 0) {
767 *perrno = state->sys_errno;