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
;
313 struct async_send_state
{
321 static void async_send_handler(struct tevent_context
*ev
,
322 struct tevent_fd
*fde
,
323 uint16_t flags
, void *private_data
);
325 struct tevent_req
*async_send_send(TALLOC_CTX
*mem_ctx
,
326 struct tevent_context
*ev
,
327 int fd
, const void *buf
, size_t len
,
330 struct tevent_req
*result
;
331 struct async_send_state
*state
;
332 struct tevent_fd
*fde
;
334 result
= tevent_req_create(mem_ctx
, &state
, struct async_send_state
);
335 if (result
== NULL
) {
341 state
->flags
= flags
;
343 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_WRITE
, async_send_handler
,
352 static void async_send_handler(struct tevent_context
*ev
,
353 struct tevent_fd
*fde
,
354 uint16_t flags
, void *private_data
)
356 struct tevent_req
*req
= talloc_get_type_abort(
357 private_data
, struct tevent_req
);
358 struct async_send_state
*state
= talloc_get_type_abort(
359 req
->private_state
, struct async_send_state
);
361 state
->sent
= send(state
->fd
, state
->buf
, state
->len
, state
->flags
);
362 if (state
->sent
== -1) {
363 tevent_req_error(req
, errno
);
366 tevent_req_done(req
);
369 ssize_t
async_send_recv(struct tevent_req
*req
, int *perrno
)
371 struct async_send_state
*state
= talloc_get_type_abort(
372 req
->private_state
, struct async_send_state
);
374 if (tevent_req_is_unix_error(req
, perrno
)) {
380 struct async_recv_state
{
388 static void async_recv_handler(struct tevent_context
*ev
,
389 struct tevent_fd
*fde
,
390 uint16_t flags
, void *private_data
);
392 struct tevent_req
*async_recv_send(TALLOC_CTX
*mem_ctx
,
393 struct tevent_context
*ev
,
394 int fd
, void *buf
, size_t len
, int flags
)
396 struct tevent_req
*result
;
397 struct async_recv_state
*state
;
398 struct tevent_fd
*fde
;
400 result
= tevent_req_create(mem_ctx
, &state
, struct async_recv_state
);
401 if (result
== NULL
) {
407 state
->flags
= flags
;
409 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
, async_recv_handler
,
418 static void async_recv_handler(struct tevent_context
*ev
,
419 struct tevent_fd
*fde
,
420 uint16_t flags
, void *private_data
)
422 struct tevent_req
*req
= talloc_get_type_abort(
423 private_data
, struct tevent_req
);
424 struct async_recv_state
*state
= talloc_get_type_abort(
425 req
->private_state
, struct async_recv_state
);
427 state
->received
= recv(state
->fd
, state
->buf
, state
->len
,
429 if (state
->received
== -1) {
430 tevent_req_error(req
, errno
);
433 tevent_req_done(req
);
436 ssize_t
async_recv_recv(struct tevent_req
*req
, int *perrno
)
438 struct async_recv_state
*state
= talloc_get_type_abort(
439 req
->private_state
, struct async_recv_state
);
441 if (tevent_req_is_unix_error(req
, perrno
)) {
444 return state
->received
;
447 struct async_connect_state
{
454 static void async_connect_connected(struct tevent_context
*ev
,
455 struct tevent_fd
*fde
, uint16_t flags
,
459 * @brief async version of connect(2)
460 * @param[in] mem_ctx The memory context to hang the result off
461 * @param[in] ev The event context to work from
462 * @param[in] fd The socket to recv from
463 * @param[in] address Where to connect?
464 * @param[in] address_len Length of *address
465 * @retval The async request
467 * This function sets the socket into non-blocking state to be able to call
468 * connect in an async state. This will be reset when the request is finished.
471 struct tevent_req
*async_connect_send(TALLOC_CTX
*mem_ctx
,
472 struct tevent_context
*ev
,
473 int fd
, const struct sockaddr
*address
,
474 socklen_t address_len
)
476 struct tevent_req
*result
;
477 struct async_connect_state
*state
;
478 struct tevent_fd
*fde
;
480 result
= tevent_req_create(
481 mem_ctx
, &state
, struct async_connect_state
);
482 if (result
== NULL
) {
487 * We have to set the socket to nonblocking for async connect(2). Keep
488 * the old sockflags around.
492 state
->sys_errno
= 0;
494 state
->old_sockflags
= fcntl(fd
, F_GETFL
, 0);
495 if (state
->old_sockflags
== -1) {
499 set_blocking(fd
, false);
501 state
->result
= connect(fd
, address
, address_len
);
502 if (state
->result
== 0) {
508 * A number of error messages show that something good is progressing
509 * and that we have to wait for readability.
511 * If none of them are present, bail out.
514 if (!(errno
== EINPROGRESS
|| errno
== EALREADY
||
518 errno
== EAGAIN
|| errno
== EINTR
)) {
522 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
| TEVENT_FD_WRITE
,
523 async_connect_connected
, result
);
531 state
->sys_errno
= errno
;
532 fcntl(fd
, F_SETFL
, state
->old_sockflags
);
533 if (state
->sys_errno
== 0) {
534 tevent_req_done(result
);
536 tevent_req_error(result
, state
->sys_errno
);
538 return tevent_req_post(result
, ev
);
542 * fde event handler for connect(2)
543 * @param[in] ev The event context that sent us here
544 * @param[in] fde The file descriptor event associated with the connect
545 * @param[in] flags Indicate read/writeability of the socket
546 * @param[in] priv private data, "struct async_req *" in this case
549 static void async_connect_connected(struct tevent_context
*ev
,
550 struct tevent_fd
*fde
, uint16_t flags
,
553 struct tevent_req
*req
= talloc_get_type_abort(
554 priv
, struct tevent_req
);
555 struct async_connect_state
*state
= talloc_get_type_abort(
556 req
->private_state
, struct async_connect_state
);
561 * Stevens, Network Programming says that if there's a
562 * successful connect, the socket is only writable. Upon an
563 * error, it's both readable and writable.
565 if ((flags
& (TEVENT_FD_READ
|TEVENT_FD_WRITE
))
566 == (TEVENT_FD_READ
|TEVENT_FD_WRITE
)) {
568 socklen_t err_len
= sizeof(sockerr
);
570 if (getsockopt(state
->fd
, SOL_SOCKET
, SO_ERROR
,
571 (void *)&sockerr
, &err_len
) == 0) {
575 state
->sys_errno
= errno
;
577 DEBUG(10, ("connect returned %s\n", strerror(errno
)));
579 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
580 tevent_req_error(req
, state
->sys_errno
);
584 state
->sys_errno
= 0;
585 tevent_req_done(req
);
588 int async_connect_recv(struct tevent_req
*req
, int *perrno
)
590 struct async_connect_state
*state
= talloc_get_type_abort(
591 req
->private_state
, struct async_connect_state
);
594 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
596 if (tevent_req_is_unix_error(req
, &err
)) {
601 if (state
->sys_errno
== 0) {
605 *perrno
= state
->sys_errno
;
609 struct writev_state
{
610 struct tevent_context
*ev
;
617 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
618 uint16_t flags
, void *private_data
);
620 struct tevent_req
*writev_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
621 int fd
, struct iovec
*iov
, int count
)
623 struct tevent_req
*result
;
624 struct writev_state
*state
;
625 struct tevent_fd
*fde
;
627 result
= tevent_req_create(mem_ctx
, &state
, struct writev_state
);
628 if (result
== NULL
) {
633 state
->total_size
= 0;
634 state
->count
= count
;
635 state
->iov
= (struct iovec
*)talloc_memdup(
636 state
, iov
, sizeof(struct iovec
) * count
);
637 if (state
->iov
== NULL
) {
641 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_WRITE
, writev_handler
,
653 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
654 uint16_t flags
, void *private_data
)
656 struct tevent_req
*req
= talloc_get_type_abort(
657 private_data
, struct tevent_req
);
658 struct writev_state
*state
= talloc_get_type_abort(
659 req
->private_state
, struct writev_state
);
660 size_t to_write
, written
;
665 for (i
=0; i
<state
->count
; i
++) {
666 to_write
+= state
->iov
[i
].iov_len
;
669 written
= sys_writev(state
->fd
, state
->iov
, state
->count
);
671 tevent_req_error(req
, errno
);
675 tevent_req_error(req
, EPIPE
);
678 state
->total_size
+= written
;
680 if (written
== to_write
) {
681 tevent_req_done(req
);
686 * We've written less than we were asked to, drop stuff from
690 while (written
> 0) {
691 if (written
< state
->iov
[0].iov_len
) {
692 state
->iov
[0].iov_base
=
693 (char *)state
->iov
[0].iov_base
+ written
;
694 state
->iov
[0].iov_len
-= written
;
697 written
= state
->iov
[0].iov_len
;
703 ssize_t
writev_recv(struct tevent_req
*req
, int *perrno
)
705 struct writev_state
*state
= talloc_get_type_abort(
706 req
->private_state
, struct writev_state
);
708 if (tevent_req_is_unix_error(req
, perrno
)) {
711 return state
->total_size
;
714 struct read_packet_state
{
718 ssize_t (*more
)(uint8_t *buf
, size_t buflen
, void *private_data
);
722 static void read_packet_handler(struct tevent_context
*ev
,
723 struct tevent_fd
*fde
,
724 uint16_t flags
, void *private_data
);
726 struct tevent_req
*read_packet_send(TALLOC_CTX
*mem_ctx
,
727 struct tevent_context
*ev
,
728 int fd
, size_t initial
,
729 ssize_t (*more
)(uint8_t *buf
,
734 struct tevent_req
*result
;
735 struct read_packet_state
*state
;
736 struct tevent_fd
*fde
;
738 result
= tevent_req_create(mem_ctx
, &state
, struct read_packet_state
);
739 if (result
== NULL
) {
745 state
->private_data
= private_data
;
747 state
->buf
= talloc_array(state
, uint8_t, initial
);
748 if (state
->buf
== NULL
) {
752 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
, read_packet_handler
,
763 static void read_packet_handler(struct tevent_context
*ev
,
764 struct tevent_fd
*fde
,
765 uint16_t flags
, void *private_data
)
767 struct tevent_req
*req
= talloc_get_type_abort(
768 private_data
, struct tevent_req
);
769 struct read_packet_state
*state
= talloc_get_type_abort(
770 req
->private_state
, struct read_packet_state
);
771 size_t total
= talloc_get_size(state
->buf
);
775 nread
= read(state
->fd
, state
->buf
+state
->nread
, total
-state
->nread
);
777 tevent_req_error(req
, errno
);
781 tevent_req_error(req
, EPIPE
);
785 state
->nread
+= nread
;
786 if (state
->nread
< total
) {
787 /* Come back later */
792 * We got what was initially requested. See if "more" asks for -- more.
794 if (state
->more
== NULL
) {
795 /* Nobody to ask, this is a async read_data */
796 tevent_req_done(req
);
800 more
= state
->more(state
->buf
, total
, state
->private_data
);
802 /* We got an invalid packet, tell the caller */
803 tevent_req_error(req
, EIO
);
807 /* We're done, full packet received */
808 tevent_req_done(req
);
812 tmp
= TALLOC_REALLOC_ARRAY(state
, state
->buf
, uint8_t, total
+more
);
813 if (tevent_req_nomem(tmp
, req
)) {
819 ssize_t
read_packet_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
820 uint8_t **pbuf
, int *perrno
)
822 struct read_packet_state
*state
= talloc_get_type_abort(
823 req
->private_state
, struct read_packet_state
);
825 if (tevent_req_is_unix_error(req
, perrno
)) {
828 *pbuf
= talloc_move(mem_ctx
, &state
->buf
);
829 return talloc_get_size(*pbuf
);