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 {
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;
64 ssize_t result_ssize_t;
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;
84 if (!async_req_is_error(req, &state, &error)) {
89 case ASYNC_REQ_USER_ERROR:
92 case ASYNC_REQ_TIMED_OUT:
99 case ASYNC_REQ_NO_MEMORY:
109 int async_req_simple_recv_errno(struct async_req *req)
113 if (async_req_is_errno(req, &err)) {
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)) {
145 state->syscall_type = type;
147 result->private_data = state;
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
170 static struct async_req *async_fde_syscall_new(
172 struct tevent_context *ev,
173 enum async_syscall_type type,
176 void (*fde_cb)(struct tevent_context *ev,
177 struct tevent_fd *fde, uint16_t flags,
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) {
189 state->fde = tevent_add_fd(ev, state, fd, fde_flags, fde_cb, result);
190 if (state->fde == NULL) {
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,
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);
269 state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
271 state->sys_errno = errno;
273 TALLOC_FREE(state->fde);
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,
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,
301 if (result == 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;
314 * fde event handler for the "recv" syscall
315 * @param[in] ev The event context that sent us here
316 * @param[in] fde The file descriptor event associated with the recv
317 * @param[in] flags Can only be TEVENT_FD_READ here
318 * @param[in] priv private data, "struct async_req *" in this case
321 static void async_recv_callback(struct tevent_context *ev,
322 struct tevent_fd *fde, uint16_t flags,
325 struct async_req *req = talloc_get_type_abort(
326 priv, struct async_req);
327 struct async_syscall_state *state = talloc_get_type_abort(
328 req->private_data, struct async_syscall_state);
329 struct param_recv *p = &state->param.param_recv;
331 if (state->syscall_type != ASYNC_SYSCALL_RECV) {
332 async_req_error(req, EIO);
336 state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
338 state->sys_errno = errno;
340 TALLOC_FREE(state->fde);
346 * Async version of recv(2)
347 * @param[in] mem_ctx The memory context to hang the result off
348 * @param[in] ev The event context to work from
349 * @param[in] fd The socket to recv from
350 * @param[in] buffer The buffer to recv into
351 * @param[in] length How many bytes to recv
352 * @param[in] flags flags passed to recv(2)
354 * This function is a direct counterpart of recv(2)
357 struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
358 int fd, void *buffer, size_t length,
361 struct async_req *result;
362 struct async_syscall_state *state;
364 result = async_fde_syscall_new(
365 mem_ctx, ev, ASYNC_SYSCALL_RECV,
366 fd, TEVENT_FD_READ, async_recv_callback,
369 if (result == NULL) {
373 state->param.param_recv.fd = fd;
374 state->param.param_recv.buffer = buffer;
375 state->param.param_recv.length = length;
376 state->param.param_recv.flags = flags;
381 struct async_send_state {
389 static void async_send_handler(struct tevent_context *ev,
390 struct tevent_fd *fde,
391 uint16_t flags, void *private_data);
393 struct tevent_req *async_send_send(TALLOC_CTX *mem_ctx,
394 struct tevent_context *ev,
395 int fd, const void *buf, size_t len,
398 struct tevent_req *result;
399 struct async_send_state *state;
400 struct tevent_fd *fde;
402 result = tevent_req_create(mem_ctx, &state, struct async_send_state);
403 if (result == NULL) {
409 state->flags = flags;
411 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, async_send_handler,
420 static void async_send_handler(struct tevent_context *ev,
421 struct tevent_fd *fde,
422 uint16_t flags, void *private_data)
424 struct tevent_req *req = talloc_get_type_abort(
425 private_data, struct tevent_req);
426 struct async_send_state *state = talloc_get_type_abort(
427 req->private_state, struct async_send_state);
429 state->sent = send(state->fd, state->buf, state->len, state->flags);
430 if (state->sent == -1) {
431 tevent_req_error(req, errno);
434 tevent_req_done(req);
437 ssize_t async_send_recv(struct tevent_req *req, int *perrno)
439 struct async_send_state *state = talloc_get_type_abort(
440 req->private_state, struct async_send_state);
442 if (tevent_req_is_unix_error(req, perrno)) {
448 struct async_connect_state {
455 static void async_connect_connected(struct tevent_context *ev,
456 struct tevent_fd *fde, uint16_t flags,
460 * @brief async version of connect(2)
461 * @param[in] mem_ctx The memory context to hang the result off
462 * @param[in] ev The event context to work from
463 * @param[in] fd The socket to recv from
464 * @param[in] address Where to connect?
465 * @param[in] address_len Length of *address
466 * @retval The async request
468 * This function sets the socket into non-blocking state to be able to call
469 * connect in an async state. This will be reset when the request is finished.
472 struct tevent_req *async_connect_send(TALLOC_CTX *mem_ctx,
473 struct tevent_context *ev,
474 int fd, const struct sockaddr *address,
475 socklen_t address_len)
477 struct tevent_req *result;
478 struct async_connect_state *state;
479 struct tevent_fd *fde;
481 result = tevent_req_create(
482 mem_ctx, &state, struct async_connect_state);
483 if (result == NULL) {
488 * We have to set the socket to nonblocking for async connect(2). Keep
489 * the old sockflags around.
493 state->sys_errno = 0;
495 state->old_sockflags = fcntl(fd, F_GETFL, 0);
496 if (state->old_sockflags == -1) {
500 set_blocking(fd, false);
502 state->result = connect(fd, address, address_len);
503 if (state->result == 0) {
509 * A number of error messages show that something good is progressing
510 * and that we have to wait for readability.
512 * If none of them are present, bail out.
515 if (!(errno == EINPROGRESS || errno == EALREADY ||
519 errno == EAGAIN || errno == EINTR)) {
523 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
524 async_connect_connected, result);
532 state->sys_errno = errno;
533 fcntl(fd, F_SETFL, state->old_sockflags);
534 if (state->sys_errno == 0) {
535 tevent_req_done(result);
537 tevent_req_error(result, state->sys_errno);
539 return tevent_req_post(result, ev);
543 * fde event handler for connect(2)
544 * @param[in] ev The event context that sent us here
545 * @param[in] fde The file descriptor event associated with the connect
546 * @param[in] flags Indicate read/writeability of the socket
547 * @param[in] priv private data, "struct async_req *" in this case
550 static void async_connect_connected(struct tevent_context *ev,
551 struct tevent_fd *fde, uint16_t flags,
554 struct tevent_req *req = talloc_get_type_abort(
555 priv, struct tevent_req);
556 struct async_connect_state *state = talloc_get_type_abort(
557 req->private_state, struct async_connect_state);
562 * Stevens, Network Programming says that if there's a
563 * successful connect, the socket is only writable. Upon an
564 * error, it's both readable and writable.
566 if ((flags & (TEVENT_FD_READ|TEVENT_FD_WRITE))
567 == (TEVENT_FD_READ|TEVENT_FD_WRITE)) {
569 socklen_t err_len = sizeof(sockerr);
571 if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
572 (void *)&sockerr, &err_len) == 0) {
576 state->sys_errno = errno;
578 DEBUG(10, ("connect returned %s\n", strerror(errno)));
580 fcntl(state->fd, F_SETFL, state->old_sockflags);
581 tevent_req_error(req, state->sys_errno);
585 state->sys_errno = 0;
586 tevent_req_done(req);
589 int async_connect_recv(struct tevent_req *req, int *perrno)
591 struct async_connect_state *state = talloc_get_type_abort(
592 req->private_state, struct async_connect_state);
595 fcntl(state->fd, F_SETFL, state->old_sockflags);
597 if (tevent_req_is_unix_error(req, &err)) {
602 if (state->sys_errno == 0) {
606 *perrno = state->sys_errno;
610 struct writev_state {
611 struct tevent_context *ev;
618 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
619 uint16_t flags, void *private_data);
621 struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
622 int fd, struct iovec *iov, int count)
624 struct tevent_req *result;
625 struct writev_state *state;
626 struct tevent_fd *fde;
628 result = tevent_req_create(mem_ctx, &state, struct writev_state);
629 if (result == NULL) {
634 state->total_size = 0;
635 state->count = count;
636 state->iov = (struct iovec *)talloc_memdup(
637 state, iov, sizeof(struct iovec) * count);
638 if (state->iov == NULL) {
642 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, writev_handler,
654 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
655 uint16_t flags, void *private_data)
657 struct tevent_req *req = talloc_get_type_abort(
658 private_data, struct tevent_req);
659 struct writev_state *state = talloc_get_type_abort(
660 req->private_state, struct writev_state);
661 size_t to_write, written;
666 for (i=0; i<state->count; i++) {
667 to_write += state->iov[i].iov_len;
670 written = sys_writev(state->fd, state->iov, state->count);
672 tevent_req_error(req, errno);
676 tevent_req_error(req, EPIPE);
679 state->total_size += written;
681 if (written == to_write) {
682 tevent_req_done(req);
687 * We've written less than we were asked to, drop stuff from
691 while (written > 0) {
692 if (written < state->iov[0].iov_len) {
693 state->iov[0].iov_base =
694 (char *)state->iov[0].iov_base + written;
695 state->iov[0].iov_len -= written;
698 written = state->iov[0].iov_len;
704 ssize_t writev_recv(struct tevent_req *req, int *perrno)
706 struct writev_state *state = talloc_get_type_abort(
707 req->private_state, struct writev_state);
709 if (tevent_req_is_unix_error(req, perrno)) {
712 return state->total_size;
715 struct read_packet_state {
719 ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
723 static void read_packet_handler(struct tevent_context *ev,
724 struct tevent_fd *fde,
725 uint16_t flags, void *private_data);
727 struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
728 struct tevent_context *ev,
729 int fd, size_t initial,
730 ssize_t (*more)(uint8_t *buf,
735 struct tevent_req *result;
736 struct read_packet_state *state;
737 struct tevent_fd *fde;
739 result = tevent_req_create(mem_ctx, &state, struct read_packet_state);
740 if (result == NULL) {
746 state->private_data = private_data;
748 state->buf = talloc_array(state, uint8_t, initial);
749 if (state->buf == NULL) {
753 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler,
764 static void read_packet_handler(struct tevent_context *ev,
765 struct tevent_fd *fde,
766 uint16_t flags, void *private_data)
768 struct tevent_req *req = talloc_get_type_abort(
769 private_data, struct tevent_req);
770 struct read_packet_state *state = talloc_get_type_abort(
771 req->private_state, struct read_packet_state);
772 size_t total = talloc_get_size(state->buf);
776 nread = read(state->fd, state->buf+state->nread, total-state->nread);
778 tevent_req_error(req, errno);
782 tevent_req_error(req, EPIPE);
786 state->nread += nread;
787 if (state->nread < total) {
788 /* Come back later */
793 * We got what was initially requested. See if "more" asks for -- more.
795 if (state->more == NULL) {
796 /* Nobody to ask, this is a async read_data */
797 tevent_req_done(req);
801 more = state->more(state->buf, total, state->private_data);
803 /* We got an invalid packet, tell the caller */
804 tevent_req_error(req, EIO);
808 /* We're done, full packet received */
809 tevent_req_done(req);
813 tmp = TALLOC_REALLOC_ARRAY(state, state->buf, uint8_t, total+more);
814 if (tevent_req_nomem(tmp, req)) {
820 ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
821 uint8_t **pbuf, int *perrno)
823 struct read_packet_state *state = talloc_get_type_abort(
824 req->private_state, struct read_packet_state);
826 if (tevent_req_is_unix_error(req, perrno)) {
829 *pbuf = talloc_move(mem_ctx, &state->buf);
830 return talloc_get_size(*pbuf);