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
{
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
;
63 struct param_recvall
{
70 struct param_connect
{
72 * connect needs to be done on a nonblocking
73 * socket. Keep the old flags around
77 const struct sockaddr
*address
;
78 socklen_t address_len
;
83 ssize_t result_ssize_t
;
91 * @brief Map async_req states to unix-style errnos
92 * @param[in] req The async req to get the state from
93 * @param[out] err Pointer to take the unix-style errno
95 * @return true if the async_req is in an error state, false otherwise
98 bool async_req_is_errno(struct async_req
*req
, int *err
)
100 enum async_req_state state
;
103 if (!async_req_is_error(req
, &state
, &error
)) {
108 case ASYNC_REQ_USER_ERROR
:
111 case ASYNC_REQ_TIMED_OUT
:
118 case ASYNC_REQ_NO_MEMORY
:
128 int async_req_simple_recv_errno(struct async_req
*req
)
132 if (async_req_is_errno(req
, &err
)) {
140 * @brief Create a new async syscall req
141 * @param[in] mem_ctx The memory context to hang the result off
142 * @param[in] ev The event context to work from
143 * @param[in] type Which syscall will this be
144 * @param[in] pstate Where to put the newly created private_data state
145 * @retval The new request
147 * This is a helper function to prepare a new struct async_req with an
148 * associated struct async_syscall_state. The async_syscall_state will be put
149 * into the async_req as private_data.
152 static struct async_req
*async_syscall_new(TALLOC_CTX
*mem_ctx
,
153 struct tevent_context
*ev
,
154 enum async_syscall_type type
,
155 struct async_syscall_state
**pstate
)
157 struct async_req
*result
;
158 struct async_syscall_state
*state
;
160 if (!async_req_setup(mem_ctx
, &result
, &state
,
161 struct async_syscall_state
)) {
164 state
->syscall_type
= type
;
166 result
->private_data
= state
;
174 * @brief Create a new async syscall req based on a fd
175 * @param[in] mem_ctx The memory context to hang the result off
176 * @param[in] ev The event context to work from
177 * @param[in] type Which syscall will this be
178 * @param[in] fd The file descriptor we work on
179 * @param[in] fde_flags TEVENT_FD_READ/WRITE -- what are we interested in?
180 * @param[in] fde_cb The callback function for the file descriptor event
181 * @param[in] pstate Where to put the newly created private_data state
182 * @retval The new request
184 * This is a helper function to prepare a new struct async_req with an
185 * associated struct async_syscall_state and an associated file descriptor
189 static struct async_req
*async_fde_syscall_new(
191 struct tevent_context
*ev
,
192 enum async_syscall_type type
,
195 void (*fde_cb
)(struct tevent_context
*ev
,
196 struct tevent_fd
*fde
, uint16_t flags
,
198 struct async_syscall_state
**pstate
)
200 struct async_req
*result
;
201 struct async_syscall_state
*state
;
203 result
= async_syscall_new(mem_ctx
, ev
, type
, &state
);
204 if (result
== NULL
) {
208 state
->fde
= tevent_add_fd(ev
, state
, fd
, fde_flags
, fde_cb
, result
);
209 if (state
->fde
== NULL
) {
218 * Retrieve a ssize_t typed result from an async syscall
219 * @param[in] req The syscall that has just finished
220 * @param[out] perrno Where to put the syscall's errno
221 * @retval The return value from the asynchronously called syscall
224 ssize_t
async_syscall_result_ssize_t(struct async_req
*req
, int *perrno
)
226 struct async_syscall_state
*state
= talloc_get_type_abort(
227 req
->private_data
, struct async_syscall_state
);
229 *perrno
= state
->sys_errno
;
230 return state
->result
.result_ssize_t
;
234 * Retrieve a size_t typed result from an async syscall
235 * @param[in] req The syscall that has just finished
236 * @param[out] perrno Where to put the syscall's errno
237 * @retval The return value from the asynchronously called syscall
240 size_t async_syscall_result_size_t(struct async_req
*req
, int *perrno
)
242 struct async_syscall_state
*state
= talloc_get_type_abort(
243 req
->private_data
, struct async_syscall_state
);
245 *perrno
= state
->sys_errno
;
246 return state
->result
.result_size_t
;
250 * Retrieve a int typed result from an async syscall
251 * @param[in] req The syscall that has just finished
252 * @param[out] perrno Where to put the syscall's errno
253 * @retval The return value from the asynchronously called syscall
256 int async_syscall_result_int(struct async_req
*req
, int *perrno
)
258 struct async_syscall_state
*state
= talloc_get_type_abort(
259 req
->private_data
, struct async_syscall_state
);
261 *perrno
= state
->sys_errno
;
262 return state
->result
.result_int
;
266 * fde event handler for the "send" syscall
267 * @param[in] ev The event context that sent us here
268 * @param[in] fde The file descriptor event associated with the send
269 * @param[in] flags Can only be TEVENT_FD_WRITE here
270 * @param[in] priv private data, "struct async_req *" in this case
273 static void async_send_callback(struct tevent_context
*ev
,
274 struct tevent_fd
*fde
, uint16_t flags
,
277 struct async_req
*req
= talloc_get_type_abort(
278 priv
, struct async_req
);
279 struct async_syscall_state
*state
= talloc_get_type_abort(
280 req
->private_data
, struct async_syscall_state
);
281 struct param_send
*p
= &state
->param
.param_send
;
283 if (state
->syscall_type
!= ASYNC_SYSCALL_SEND
) {
284 async_req_error(req
, EIO
);
288 state
->result
.result_ssize_t
= send(p
->fd
, p
->buffer
, p
->length
,
290 state
->sys_errno
= errno
;
292 TALLOC_FREE(state
->fde
);
298 * Async version of send(2)
299 * @param[in] mem_ctx The memory context to hang the result off
300 * @param[in] ev The event context to work from
301 * @param[in] fd The socket to send to
302 * @param[in] buffer The buffer to send
303 * @param[in] length How many bytes to send
304 * @param[in] flags flags passed to send(2)
306 * This function is a direct counterpart of send(2)
309 struct async_req
*async_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
310 int fd
, const void *buffer
, size_t length
,
313 struct async_req
*result
;
314 struct async_syscall_state
*state
;
316 result
= async_fde_syscall_new(
317 mem_ctx
, ev
, ASYNC_SYSCALL_SEND
,
318 fd
, TEVENT_FD_WRITE
, async_send_callback
,
320 if (result
== NULL
) {
324 state
->param
.param_send
.fd
= fd
;
325 state
->param
.param_send
.buffer
= buffer
;
326 state
->param
.param_send
.length
= length
;
327 state
->param
.param_send
.flags
= flags
;
333 * fde event handler for the "recv" syscall
334 * @param[in] ev The event context that sent us here
335 * @param[in] fde The file descriptor event associated with the recv
336 * @param[in] flags Can only be TEVENT_FD_READ here
337 * @param[in] priv private data, "struct async_req *" in this case
340 static void async_recv_callback(struct tevent_context
*ev
,
341 struct tevent_fd
*fde
, uint16_t flags
,
344 struct async_req
*req
= talloc_get_type_abort(
345 priv
, struct async_req
);
346 struct async_syscall_state
*state
= talloc_get_type_abort(
347 req
->private_data
, struct async_syscall_state
);
348 struct param_recv
*p
= &state
->param
.param_recv
;
350 if (state
->syscall_type
!= ASYNC_SYSCALL_RECV
) {
351 async_req_error(req
, EIO
);
355 state
->result
.result_ssize_t
= recv(p
->fd
, p
->buffer
, p
->length
,
357 state
->sys_errno
= errno
;
359 TALLOC_FREE(state
->fde
);
365 * Async version of recv(2)
366 * @param[in] mem_ctx The memory context to hang the result off
367 * @param[in] ev The event context to work from
368 * @param[in] fd The socket to recv from
369 * @param[in] buffer The buffer to recv into
370 * @param[in] length How many bytes to recv
371 * @param[in] flags flags passed to recv(2)
373 * This function is a direct counterpart of recv(2)
376 struct async_req
*async_recv(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
377 int fd
, void *buffer
, size_t length
,
380 struct async_req
*result
;
381 struct async_syscall_state
*state
;
383 result
= async_fde_syscall_new(
384 mem_ctx
, ev
, ASYNC_SYSCALL_RECV
,
385 fd
, TEVENT_FD_READ
, async_recv_callback
,
388 if (result
== NULL
) {
392 state
->param
.param_recv
.fd
= fd
;
393 state
->param
.param_recv
.buffer
= buffer
;
394 state
->param
.param_recv
.length
= length
;
395 state
->param
.param_recv
.flags
= flags
;
401 * fde event handler for the "recvall" syscall group
402 * @param[in] ev The event context that sent us here
403 * @param[in] fde The file descriptor event associated with the recv
404 * @param[in] flags Can only be TEVENT_FD_READ here
405 * @param[in] priv private data, "struct async_req *" in this case
408 static void async_recvall_callback(struct tevent_context
*ev
,
409 struct tevent_fd
*fde
, uint16_t flags
,
412 struct async_req
*req
= talloc_get_type_abort(
413 priv
, struct async_req
);
414 struct async_syscall_state
*state
= talloc_get_type_abort(
415 req
->private_data
, struct async_syscall_state
);
416 struct param_recvall
*p
= &state
->param
.param_recvall
;
418 if (state
->syscall_type
!= ASYNC_SYSCALL_RECVALL
) {
419 async_req_error(req
, EIO
);
423 state
->result
.result_ssize_t
= recv(p
->fd
,
424 (char *)p
->buffer
+ p
->received
,
425 p
->length
- p
->received
, p
->flags
);
426 state
->sys_errno
= errno
;
428 if (state
->result
.result_ssize_t
== -1) {
429 async_req_error(req
, state
->sys_errno
);
433 if (state
->result
.result_ssize_t
== 0) {
434 async_req_error(req
, EIO
);
438 p
->received
+= state
->result
.result_ssize_t
;
439 if (p
->received
> p
->length
) {
440 async_req_error(req
, EIO
);
444 if (p
->received
== p
->length
) {
445 TALLOC_FREE(state
->fde
);
451 * Receive a specified number of bytes from a socket
452 * @param[in] mem_ctx The memory context to hang the result off
453 * @param[in] ev The event context to work from
454 * @param[in] fd The socket to recv from
455 * @param[in] buffer The buffer to recv into
456 * @param[in] length How many bytes to recv
457 * @param[in] flags flags passed to recv(2)
459 * async_recvall will call recv(2) until "length" bytes are received
462 struct async_req
*recvall_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
463 int fd
, void *buffer
, size_t length
,
466 struct async_req
*result
;
467 struct async_syscall_state
*state
;
469 result
= async_fde_syscall_new(
470 mem_ctx
, ev
, ASYNC_SYSCALL_RECVALL
,
471 fd
, TEVENT_FD_READ
, async_recvall_callback
,
473 if (result
== NULL
) {
477 state
->param
.param_recvall
.fd
= fd
;
478 state
->param
.param_recvall
.buffer
= buffer
;
479 state
->param
.param_recvall
.length
= length
;
480 state
->param
.param_recvall
.flags
= flags
;
481 state
->param
.param_recvall
.received
= 0;
486 ssize_t
recvall_recv(struct async_req
*req
, int *perr
)
488 struct async_syscall_state
*state
= talloc_get_type_abort(
489 req
->private_data
, struct async_syscall_state
);
492 err
= async_req_simple_recv_errno(req
);
499 return state
->result
.result_ssize_t
;
502 struct async_connect_state
{
509 static void async_connect_connected(struct tevent_context
*ev
,
510 struct tevent_fd
*fde
, uint16_t flags
,
514 * @brief async version of connect(2)
515 * @param[in] mem_ctx The memory context to hang the result off
516 * @param[in] ev The event context to work from
517 * @param[in] fd The socket to recv from
518 * @param[in] address Where to connect?
519 * @param[in] address_len Length of *address
520 * @retval The async request
522 * This function sets the socket into non-blocking state to be able to call
523 * connect in an async state. This will be reset when the request is finished.
526 struct tevent_req
*async_connect_send(TALLOC_CTX
*mem_ctx
,
527 struct tevent_context
*ev
,
528 int fd
, const struct sockaddr
*address
,
529 socklen_t address_len
)
531 struct tevent_req
*result
;
532 struct async_connect_state
*state
;
533 struct tevent_fd
*fde
;
535 result
= tevent_req_create(
536 mem_ctx
, &state
, struct async_connect_state
);
537 if (result
== NULL
) {
542 * We have to set the socket to nonblocking for async connect(2). Keep
543 * the old sockflags around.
547 state
->sys_errno
= 0;
549 state
->old_sockflags
= fcntl(fd
, F_GETFL
, 0);
550 if (state
->old_sockflags
== -1) {
554 set_blocking(fd
, false);
556 state
->result
= connect(fd
, address
, address_len
);
557 if (state
->result
== 0) {
563 * A number of error messages show that something good is progressing
564 * and that we have to wait for readability.
566 * If none of them are present, bail out.
569 if (!(errno
== EINPROGRESS
|| errno
== EALREADY
||
573 errno
== EAGAIN
|| errno
== EINTR
)) {
577 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
| TEVENT_FD_WRITE
,
578 async_connect_connected
, result
);
586 state
->sys_errno
= errno
;
587 fcntl(fd
, F_SETFL
, state
->old_sockflags
);
588 if (state
->sys_errno
== 0) {
589 tevent_req_done(result
);
591 tevent_req_error(result
, state
->sys_errno
);
593 return tevent_req_post(result
, ev
);
597 * fde event handler for connect(2)
598 * @param[in] ev The event context that sent us here
599 * @param[in] fde The file descriptor event associated with the connect
600 * @param[in] flags Indicate read/writeability of the socket
601 * @param[in] priv private data, "struct async_req *" in this case
604 static void async_connect_connected(struct tevent_context
*ev
,
605 struct tevent_fd
*fde
, uint16_t flags
,
608 struct tevent_req
*req
= talloc_get_type_abort(
609 priv
, struct tevent_req
);
610 struct async_connect_state
*state
= talloc_get_type_abort(
611 req
->private_state
, struct async_connect_state
);
616 * Stevens, Network Programming says that if there's a
617 * successful connect, the socket is only writable. Upon an
618 * error, it's both readable and writable.
620 if ((flags
& (TEVENT_FD_READ
|TEVENT_FD_WRITE
))
621 == (TEVENT_FD_READ
|TEVENT_FD_WRITE
)) {
623 socklen_t err_len
= sizeof(sockerr
);
625 if (getsockopt(state
->fd
, SOL_SOCKET
, SO_ERROR
,
626 (void *)&sockerr
, &err_len
) == 0) {
630 state
->sys_errno
= errno
;
632 DEBUG(10, ("connect returned %s\n", strerror(errno
)));
634 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
635 tevent_req_error(req
, state
->sys_errno
);
639 state
->sys_errno
= 0;
640 tevent_req_done(req
);
643 int async_connect_recv(struct tevent_req
*req
, int *perrno
)
645 struct async_connect_state
*state
= talloc_get_type_abort(
646 req
->private_state
, struct async_connect_state
);
649 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
651 if (tevent_req_is_unix_error(req
, &err
)) {
656 if (state
->sys_errno
== 0) {
660 *perrno
= state
->sys_errno
;
664 struct writev_state
{
665 struct tevent_context
*ev
;
672 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
673 uint16_t flags
, void *private_data
);
675 struct tevent_req
*writev_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
676 int fd
, struct iovec
*iov
, int count
)
678 struct tevent_req
*result
;
679 struct writev_state
*state
;
680 struct tevent_fd
*fde
;
682 result
= tevent_req_create(mem_ctx
, &state
, struct writev_state
);
683 if (result
== NULL
) {
688 state
->total_size
= 0;
689 state
->count
= count
;
690 state
->iov
= (struct iovec
*)talloc_memdup(
691 state
, iov
, sizeof(struct iovec
) * count
);
692 if (state
->iov
== NULL
) {
696 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_WRITE
, writev_handler
,
708 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
709 uint16_t flags
, void *private_data
)
711 struct tevent_req
*req
= talloc_get_type_abort(
712 private_data
, struct tevent_req
);
713 struct writev_state
*state
= talloc_get_type_abort(
714 req
->private_state
, struct writev_state
);
715 size_t to_write
, written
;
720 for (i
=0; i
<state
->count
; i
++) {
721 to_write
+= state
->iov
[i
].iov_len
;
724 written
= sys_writev(state
->fd
, state
->iov
, state
->count
);
726 tevent_req_error(req
, errno
);
730 tevent_req_error(req
, EOF
);
733 state
->total_size
+= written
;
735 if (written
== to_write
) {
736 tevent_req_done(req
);
741 * We've written less than we were asked to, drop stuff from
745 while (written
> 0) {
746 if (written
< state
->iov
[0].iov_len
) {
747 state
->iov
[0].iov_base
=
748 (char *)state
->iov
[0].iov_base
+ written
;
749 state
->iov
[0].iov_len
-= written
;
752 written
= state
->iov
[0].iov_len
;
758 ssize_t
writev_recv(struct tevent_req
*req
, int *perrno
)
760 struct writev_state
*state
= talloc_get_type_abort(
761 req
->private_state
, struct writev_state
);
763 if (tevent_req_is_unix_error(req
, perrno
)) {
766 return state
->total_size
;