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
{
42 * Holder for syscall arguments and the result
45 struct async_syscall_state
{
46 enum async_syscall_type syscall_type
;
47 struct tevent_fd
*fde
;
62 struct param_connect
{
64 * connect needs to be done on a nonblocking
65 * socket. Keep the old flags around
69 const struct sockaddr
*address
;
70 socklen_t address_len
;
75 ssize_t result_ssize_t
;
83 * @brief Map async_req states to unix-style errnos
84 * @param[in] req The async req to get the state from
85 * @param[out] err Pointer to take the unix-style errno
87 * @return true if the async_req is in an error state, false otherwise
90 bool async_req_is_errno(struct async_req
*req
, int *err
)
92 enum async_req_state state
;
95 if (!async_req_is_error(req
, &state
, &error
)) {
100 case ASYNC_REQ_USER_ERROR
:
103 case ASYNC_REQ_TIMED_OUT
:
110 case ASYNC_REQ_NO_MEMORY
:
120 int async_req_simple_recv_errno(struct async_req
*req
)
124 if (async_req_is_errno(req
, &err
)) {
132 * @brief Create a new async syscall req
133 * @param[in] mem_ctx The memory context to hang the result off
134 * @param[in] ev The event context to work from
135 * @param[in] type Which syscall will this be
136 * @param[in] pstate Where to put the newly created private_data state
137 * @retval The new request
139 * This is a helper function to prepare a new struct async_req with an
140 * associated struct async_syscall_state. The async_syscall_state will be put
141 * into the async_req as private_data.
144 static struct async_req
*async_syscall_new(TALLOC_CTX
*mem_ctx
,
145 struct tevent_context
*ev
,
146 enum async_syscall_type type
,
147 struct async_syscall_state
**pstate
)
149 struct async_req
*result
;
150 struct async_syscall_state
*state
;
152 if (!async_req_setup(mem_ctx
, &result
, &state
,
153 struct async_syscall_state
)) {
156 state
->syscall_type
= type
;
158 result
->private_data
= state
;
166 * @brief Create a new async syscall req based on a fd
167 * @param[in] mem_ctx The memory context to hang the result off
168 * @param[in] ev The event context to work from
169 * @param[in] type Which syscall will this be
170 * @param[in] fd The file descriptor we work on
171 * @param[in] fde_flags TEVENT_FD_READ/WRITE -- what are we interested in?
172 * @param[in] fde_cb The callback function for the file descriptor event
173 * @param[in] pstate Where to put the newly created private_data state
174 * @retval The new request
176 * This is a helper function to prepare a new struct async_req with an
177 * associated struct async_syscall_state and an associated file descriptor
181 static struct async_req
*async_fde_syscall_new(
183 struct tevent_context
*ev
,
184 enum async_syscall_type type
,
187 void (*fde_cb
)(struct tevent_context
*ev
,
188 struct tevent_fd
*fde
, uint16_t flags
,
190 struct async_syscall_state
**pstate
)
192 struct async_req
*result
;
193 struct async_syscall_state
*state
;
195 result
= async_syscall_new(mem_ctx
, ev
, type
, &state
);
196 if (result
== NULL
) {
200 state
->fde
= tevent_add_fd(ev
, state
, fd
, fde_flags
, fde_cb
, result
);
201 if (state
->fde
== NULL
) {
210 * Retrieve a ssize_t typed result from an async syscall
211 * @param[in] req The syscall that has just finished
212 * @param[out] perrno Where to put the syscall's errno
213 * @retval The return value from the asynchronously called syscall
216 ssize_t
async_syscall_result_ssize_t(struct async_req
*req
, int *perrno
)
218 struct async_syscall_state
*state
= talloc_get_type_abort(
219 req
->private_data
, struct async_syscall_state
);
221 *perrno
= state
->sys_errno
;
222 return state
->result
.result_ssize_t
;
226 * Retrieve a size_t typed result from an async syscall
227 * @param[in] req The syscall that has just finished
228 * @param[out] perrno Where to put the syscall's errno
229 * @retval The return value from the asynchronously called syscall
232 size_t async_syscall_result_size_t(struct async_req
*req
, int *perrno
)
234 struct async_syscall_state
*state
= talloc_get_type_abort(
235 req
->private_data
, struct async_syscall_state
);
237 *perrno
= state
->sys_errno
;
238 return state
->result
.result_size_t
;
242 * Retrieve a int typed result from an async syscall
243 * @param[in] req The syscall that has just finished
244 * @param[out] perrno Where to put the syscall's errno
245 * @retval The return value from the asynchronously called syscall
248 int async_syscall_result_int(struct async_req
*req
, int *perrno
)
250 struct async_syscall_state
*state
= talloc_get_type_abort(
251 req
->private_data
, struct async_syscall_state
);
253 *perrno
= state
->sys_errno
;
254 return state
->result
.result_int
;
258 * fde event handler for the "send" syscall
259 * @param[in] ev The event context that sent us here
260 * @param[in] fde The file descriptor event associated with the send
261 * @param[in] flags Can only be TEVENT_FD_WRITE here
262 * @param[in] priv private data, "struct async_req *" in this case
265 static void async_send_callback(struct tevent_context
*ev
,
266 struct tevent_fd
*fde
, uint16_t flags
,
269 struct async_req
*req
= talloc_get_type_abort(
270 priv
, struct async_req
);
271 struct async_syscall_state
*state
= talloc_get_type_abort(
272 req
->private_data
, struct async_syscall_state
);
273 struct param_send
*p
= &state
->param
.param_send
;
275 if (state
->syscall_type
!= ASYNC_SYSCALL_SEND
) {
276 async_req_error(req
, EIO
);
280 state
->result
.result_ssize_t
= send(p
->fd
, p
->buffer
, p
->length
,
282 state
->sys_errno
= errno
;
284 TALLOC_FREE(state
->fde
);
290 * Async version of send(2)
291 * @param[in] mem_ctx The memory context to hang the result off
292 * @param[in] ev The event context to work from
293 * @param[in] fd The socket to send to
294 * @param[in] buffer The buffer to send
295 * @param[in] length How many bytes to send
296 * @param[in] flags flags passed to send(2)
298 * This function is a direct counterpart of send(2)
301 struct async_req
*async_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
302 int fd
, const void *buffer
, size_t length
,
305 struct async_req
*result
;
306 struct async_syscall_state
*state
;
308 result
= async_fde_syscall_new(
309 mem_ctx
, ev
, ASYNC_SYSCALL_SEND
,
310 fd
, TEVENT_FD_WRITE
, async_send_callback
,
312 if (result
== NULL
) {
316 state
->param
.param_send
.fd
= fd
;
317 state
->param
.param_send
.buffer
= buffer
;
318 state
->param
.param_send
.length
= length
;
319 state
->param
.param_send
.flags
= flags
;
325 * fde event handler for the "recv" syscall
326 * @param[in] ev The event context that sent us here
327 * @param[in] fde The file descriptor event associated with the recv
328 * @param[in] flags Can only be TEVENT_FD_READ here
329 * @param[in] priv private data, "struct async_req *" in this case
332 static void async_recv_callback(struct tevent_context
*ev
,
333 struct tevent_fd
*fde
, uint16_t flags
,
336 struct async_req
*req
= talloc_get_type_abort(
337 priv
, struct async_req
);
338 struct async_syscall_state
*state
= talloc_get_type_abort(
339 req
->private_data
, struct async_syscall_state
);
340 struct param_recv
*p
= &state
->param
.param_recv
;
342 if (state
->syscall_type
!= ASYNC_SYSCALL_RECV
) {
343 async_req_error(req
, EIO
);
347 state
->result
.result_ssize_t
= recv(p
->fd
, p
->buffer
, p
->length
,
349 state
->sys_errno
= errno
;
351 TALLOC_FREE(state
->fde
);
357 * Async version of recv(2)
358 * @param[in] mem_ctx The memory context to hang the result off
359 * @param[in] ev The event context to work from
360 * @param[in] fd The socket to recv from
361 * @param[in] buffer The buffer to recv into
362 * @param[in] length How many bytes to recv
363 * @param[in] flags flags passed to recv(2)
365 * This function is a direct counterpart of recv(2)
368 struct async_req
*async_recv(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
369 int fd
, void *buffer
, size_t length
,
372 struct async_req
*result
;
373 struct async_syscall_state
*state
;
375 result
= async_fde_syscall_new(
376 mem_ctx
, ev
, ASYNC_SYSCALL_RECV
,
377 fd
, TEVENT_FD_READ
, async_recv_callback
,
380 if (result
== NULL
) {
384 state
->param
.param_recv
.fd
= fd
;
385 state
->param
.param_recv
.buffer
= buffer
;
386 state
->param
.param_recv
.length
= length
;
387 state
->param
.param_recv
.flags
= flags
;
392 struct async_connect_state
{
399 static void async_connect_connected(struct tevent_context
*ev
,
400 struct tevent_fd
*fde
, uint16_t flags
,
404 * @brief async version of connect(2)
405 * @param[in] mem_ctx The memory context to hang the result off
406 * @param[in] ev The event context to work from
407 * @param[in] fd The socket to recv from
408 * @param[in] address Where to connect?
409 * @param[in] address_len Length of *address
410 * @retval The async request
412 * This function sets the socket into non-blocking state to be able to call
413 * connect in an async state. This will be reset when the request is finished.
416 struct tevent_req
*async_connect_send(TALLOC_CTX
*mem_ctx
,
417 struct tevent_context
*ev
,
418 int fd
, const struct sockaddr
*address
,
419 socklen_t address_len
)
421 struct tevent_req
*result
;
422 struct async_connect_state
*state
;
423 struct tevent_fd
*fde
;
425 result
= tevent_req_create(
426 mem_ctx
, &state
, struct async_connect_state
);
427 if (result
== NULL
) {
432 * We have to set the socket to nonblocking for async connect(2). Keep
433 * the old sockflags around.
437 state
->sys_errno
= 0;
439 state
->old_sockflags
= fcntl(fd
, F_GETFL
, 0);
440 if (state
->old_sockflags
== -1) {
444 set_blocking(fd
, false);
446 state
->result
= connect(fd
, address
, address_len
);
447 if (state
->result
== 0) {
453 * A number of error messages show that something good is progressing
454 * and that we have to wait for readability.
456 * If none of them are present, bail out.
459 if (!(errno
== EINPROGRESS
|| errno
== EALREADY
||
463 errno
== EAGAIN
|| errno
== EINTR
)) {
467 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
| TEVENT_FD_WRITE
,
468 async_connect_connected
, result
);
476 state
->sys_errno
= errno
;
477 fcntl(fd
, F_SETFL
, state
->old_sockflags
);
478 if (state
->sys_errno
== 0) {
479 tevent_req_done(result
);
481 tevent_req_error(result
, state
->sys_errno
);
483 return tevent_req_post(result
, ev
);
487 * fde event handler for connect(2)
488 * @param[in] ev The event context that sent us here
489 * @param[in] fde The file descriptor event associated with the connect
490 * @param[in] flags Indicate read/writeability of the socket
491 * @param[in] priv private data, "struct async_req *" in this case
494 static void async_connect_connected(struct tevent_context
*ev
,
495 struct tevent_fd
*fde
, uint16_t flags
,
498 struct tevent_req
*req
= talloc_get_type_abort(
499 priv
, struct tevent_req
);
500 struct async_connect_state
*state
= talloc_get_type_abort(
501 req
->private_state
, struct async_connect_state
);
506 * Stevens, Network Programming says that if there's a
507 * successful connect, the socket is only writable. Upon an
508 * error, it's both readable and writable.
510 if ((flags
& (TEVENT_FD_READ
|TEVENT_FD_WRITE
))
511 == (TEVENT_FD_READ
|TEVENT_FD_WRITE
)) {
513 socklen_t err_len
= sizeof(sockerr
);
515 if (getsockopt(state
->fd
, SOL_SOCKET
, SO_ERROR
,
516 (void *)&sockerr
, &err_len
) == 0) {
520 state
->sys_errno
= errno
;
522 DEBUG(10, ("connect returned %s\n", strerror(errno
)));
524 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
525 tevent_req_error(req
, state
->sys_errno
);
529 state
->sys_errno
= 0;
530 tevent_req_done(req
);
533 int async_connect_recv(struct tevent_req
*req
, int *perrno
)
535 struct async_connect_state
*state
= talloc_get_type_abort(
536 req
->private_state
, struct async_connect_state
);
539 fcntl(state
->fd
, F_SETFL
, state
->old_sockflags
);
541 if (tevent_req_is_unix_error(req
, &err
)) {
546 if (state
->sys_errno
== 0) {
550 *perrno
= state
->sys_errno
;
554 struct writev_state
{
555 struct tevent_context
*ev
;
562 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
563 uint16_t flags
, void *private_data
);
565 struct tevent_req
*writev_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
566 int fd
, struct iovec
*iov
, int count
)
568 struct tevent_req
*result
;
569 struct writev_state
*state
;
570 struct tevent_fd
*fde
;
572 result
= tevent_req_create(mem_ctx
, &state
, struct writev_state
);
573 if (result
== NULL
) {
578 state
->total_size
= 0;
579 state
->count
= count
;
580 state
->iov
= (struct iovec
*)talloc_memdup(
581 state
, iov
, sizeof(struct iovec
) * count
);
582 if (state
->iov
== NULL
) {
586 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_WRITE
, writev_handler
,
598 static void writev_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
599 uint16_t flags
, void *private_data
)
601 struct tevent_req
*req
= talloc_get_type_abort(
602 private_data
, struct tevent_req
);
603 struct writev_state
*state
= talloc_get_type_abort(
604 req
->private_state
, struct writev_state
);
605 size_t to_write
, written
;
610 for (i
=0; i
<state
->count
; i
++) {
611 to_write
+= state
->iov
[i
].iov_len
;
614 written
= sys_writev(state
->fd
, state
->iov
, state
->count
);
616 tevent_req_error(req
, errno
);
620 tevent_req_error(req
, EPIPE
);
623 state
->total_size
+= written
;
625 if (written
== to_write
) {
626 tevent_req_done(req
);
631 * We've written less than we were asked to, drop stuff from
635 while (written
> 0) {
636 if (written
< state
->iov
[0].iov_len
) {
637 state
->iov
[0].iov_base
=
638 (char *)state
->iov
[0].iov_base
+ written
;
639 state
->iov
[0].iov_len
-= written
;
642 written
= state
->iov
[0].iov_len
;
648 ssize_t
writev_recv(struct tevent_req
*req
, int *perrno
)
650 struct writev_state
*state
= talloc_get_type_abort(
651 req
->private_state
, struct writev_state
);
653 if (tevent_req_is_unix_error(req
, perrno
)) {
656 return state
->total_size
;
659 struct read_packet_state
{
663 ssize_t (*more
)(uint8_t *buf
, size_t buflen
, void *private_data
);
667 static void read_packet_handler(struct tevent_context
*ev
,
668 struct tevent_fd
*fde
,
669 uint16_t flags
, void *private_data
);
671 struct tevent_req
*read_packet_send(TALLOC_CTX
*mem_ctx
,
672 struct tevent_context
*ev
,
673 int fd
, size_t initial
,
674 ssize_t (*more
)(uint8_t *buf
,
679 struct tevent_req
*result
;
680 struct read_packet_state
*state
;
681 struct tevent_fd
*fde
;
683 result
= tevent_req_create(mem_ctx
, &state
, struct read_packet_state
);
684 if (result
== NULL
) {
690 state
->private_data
= private_data
;
692 state
->buf
= talloc_array(state
, uint8_t, initial
);
693 if (state
->buf
== NULL
) {
697 fde
= tevent_add_fd(ev
, state
, fd
, TEVENT_FD_READ
, read_packet_handler
,
708 static void read_packet_handler(struct tevent_context
*ev
,
709 struct tevent_fd
*fde
,
710 uint16_t flags
, void *private_data
)
712 struct tevent_req
*req
= talloc_get_type_abort(
713 private_data
, struct tevent_req
);
714 struct read_packet_state
*state
= talloc_get_type_abort(
715 req
->private_state
, struct read_packet_state
);
716 size_t total
= talloc_get_size(state
->buf
);
720 nread
= read(state
->fd
, state
->buf
+state
->nread
, total
-state
->nread
);
722 tevent_req_error(req
, errno
);
726 tevent_req_error(req
, EPIPE
);
730 state
->nread
+= nread
;
731 if (state
->nread
< total
) {
732 /* Come back later */
737 * We got what was initially requested. See if "more" asks for -- more.
739 if (state
->more
== NULL
) {
740 /* Nobody to ask, this is a async read_data */
741 tevent_req_done(req
);
745 more
= state
->more(state
->buf
, total
, state
->private_data
);
747 /* We got an invalid packet, tell the caller */
748 tevent_req_error(req
, EIO
);
752 /* We're done, full packet received */
753 tevent_req_done(req
);
757 tmp
= TALLOC_REALLOC_ARRAY(state
, state
->buf
, uint8_t, total
+more
);
758 if (tevent_req_nomem(tmp
, req
)) {
764 ssize_t
read_packet_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
765 uint8_t **pbuf
, int *perrno
)
767 struct read_packet_state
*state
= talloc_get_type_abort(
768 req
->private_state
, struct read_packet_state
);
770 if (tevent_req_is_unix_error(req
, perrno
)) {
773 *pbuf
= talloc_move(mem_ctx
, &state
->buf
);
774 return talloc_get_size(*pbuf
);