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/>.
23 * Discriminator for async_syscall_state
25 enum async_syscall_type
{
27 ASYNC_SYSCALL_SENDALL
,
29 ASYNC_SYSCALL_RECVALL
,
34 * Holder for syscall arguments and the result
37 struct async_syscall_state
{
38 enum async_syscall_type syscall_type
;
48 struct param_sendall
{
61 struct param_recvall
{
68 struct param_connect
{
70 * connect needs to be done on a nonblocking
71 * socket. Keep the old flags around
75 const struct sockaddr
*address
;
76 socklen_t address_len
;
81 ssize_t result_ssize_t
;
89 * @brief Create a new async syscall req
90 * @param[in] mem_ctx The memory context to hang the result off
91 * @param[in] ev The event context to work from
92 * @param[in] type Which syscall will this be
93 * @param[in] pstate Where to put the newly created private_data state
94 * @retval The new request
96 * This is a helper function to prepare a new struct async_req with an
97 * associated struct async_syscall_state. The async_syscall_state will be put
98 * into the async_req as private_data.
101 static struct async_req
*async_syscall_new(TALLOC_CTX
*mem_ctx
,
102 struct event_context
*ev
,
103 enum async_syscall_type type
,
104 struct async_syscall_state
**pstate
)
106 struct async_req
*result
;
107 struct async_syscall_state
*state
;
109 result
= async_req_new(mem_ctx
);
110 if (result
== NULL
) {
114 state
= talloc(result
, struct async_syscall_state
);
120 state
->syscall_type
= type
;
122 result
->private_data
= state
;
130 * @brief Create a new async syscall req based on a fd
131 * @param[in] mem_ctx The memory context to hang the result off
132 * @param[in] ev The event context to work from
133 * @param[in] type Which syscall will this be
134 * @param[in] fd The file descriptor we work on
135 * @param[in] fde_flags EVENT_FD_READ/WRITE -- what are we interested in?
136 * @param[in] fde_cb The callback function for the file descriptor event
137 * @param[in] pstate Where to put the newly created private_data state
138 * @retval The new request
140 * This is a helper function to prepare a new struct async_req with an
141 * associated struct async_syscall_state and an associated file descriptor
145 static struct async_req
*async_fde_syscall_new(
147 struct event_context
*ev
,
148 enum async_syscall_type type
,
151 void (*fde_cb
)(struct event_context
*ev
,
152 struct fd_event
*fde
, uint16_t flags
,
154 struct async_syscall_state
**pstate
)
156 struct async_req
*result
;
157 struct async_syscall_state
*state
;
159 result
= async_syscall_new(mem_ctx
, ev
, type
, &state
);
160 if (result
== NULL
) {
164 state
->fde
= event_add_fd(ev
, state
, fd
, fde_flags
, fde_cb
, result
);
165 if (state
->fde
== NULL
) {
174 * Retrieve a ssize_t typed result from an async syscall
175 * @param[in] req The syscall that has just finished
176 * @param[out] perrno Where to put the syscall's errno
177 * @retval The return value from the asynchronously called syscall
180 ssize_t
async_syscall_result_ssize_t(struct async_req
*req
, int *perrno
)
182 struct async_syscall_state
*state
= talloc_get_type_abort(
183 req
->private_data
, struct async_syscall_state
);
185 *perrno
= state
->sys_errno
;
186 return state
->result
.result_ssize_t
;
190 * Retrieve a size_t typed result from an async syscall
191 * @param[in] req The syscall that has just finished
192 * @param[out] perrno Where to put the syscall's errno
193 * @retval The return value from the asynchronously called syscall
196 size_t async_syscall_result_size_t(struct async_req
*req
, int *perrno
)
198 struct async_syscall_state
*state
= talloc_get_type_abort(
199 req
->private_data
, struct async_syscall_state
);
201 *perrno
= state
->sys_errno
;
202 return state
->result
.result_size_t
;
206 * Retrieve a int typed result from an async syscall
207 * @param[in] req The syscall that has just finished
208 * @param[out] perrno Where to put the syscall's errno
209 * @retval The return value from the asynchronously called syscall
212 int async_syscall_result_int(struct async_req
*req
, int *perrno
)
214 struct async_syscall_state
*state
= talloc_get_type_abort(
215 req
->private_data
, struct async_syscall_state
);
217 *perrno
= state
->sys_errno
;
218 return state
->result
.result_int
;
222 * fde event handler for the "send" syscall
223 * @param[in] ev The event context that sent us here
224 * @param[in] fde The file descriptor event associated with the send
225 * @param[in] flags Can only be EVENT_FD_WRITE here
226 * @param[in] priv private data, "struct async_req *" in this case
229 static void async_send_callback(struct event_context
*ev
,
230 struct fd_event
*fde
, uint16_t flags
,
233 struct async_req
*req
= talloc_get_type_abort(
234 priv
, struct async_req
);
235 struct async_syscall_state
*state
= talloc_get_type_abort(
236 req
->private_data
, struct async_syscall_state
);
237 struct param_send
*p
= &state
->param
.param_send
;
239 if (state
->syscall_type
!= ASYNC_SYSCALL_SEND
) {
240 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
244 state
->result
.result_ssize_t
= send(p
->fd
, p
->buffer
, p
->length
,
246 state
->sys_errno
= errno
;
248 TALLOC_FREE(state
->fde
);
254 * Async version of send(2)
255 * @param[in] mem_ctx The memory context to hang the result off
256 * @param[in] ev The event context to work from
257 * @param[in] fd The socket to send to
258 * @param[in] buffer The buffer to send
259 * @param[in] length How many bytes to send
260 * @param[in] flags flags passed to send(2)
262 * This function is a direct counterpart of send(2)
265 struct async_req
*async_send(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
266 int fd
, const void *buffer
, size_t length
,
269 struct async_req
*result
;
270 struct async_syscall_state
*state
;
272 result
= async_fde_syscall_new(
273 mem_ctx
, ev
, ASYNC_SYSCALL_SEND
,
274 fd
, EVENT_FD_WRITE
, async_send_callback
,
276 if (result
== NULL
) {
280 state
->param
.param_send
.fd
= fd
;
281 state
->param
.param_send
.buffer
= buffer
;
282 state
->param
.param_send
.length
= length
;
283 state
->param
.param_send
.flags
= flags
;
289 * fde event handler for the "sendall" syscall group
290 * @param[in] ev The event context that sent us here
291 * @param[in] fde The file descriptor event associated with the send
292 * @param[in] flags Can only be EVENT_FD_WRITE here
293 * @param[in] priv private data, "struct async_req *" in this case
296 static void async_sendall_callback(struct event_context
*ev
,
297 struct fd_event
*fde
, uint16_t flags
,
300 struct async_req
*req
= talloc_get_type_abort(
301 priv
, struct async_req
);
302 struct async_syscall_state
*state
= talloc_get_type_abort(
303 req
->private_data
, struct async_syscall_state
);
304 struct param_sendall
*p
= &state
->param
.param_sendall
;
306 if (state
->syscall_type
!= ASYNC_SYSCALL_SENDALL
) {
307 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
311 state
->result
.result_ssize_t
= send(p
->fd
, (char *)p
->buffer
+ p
->sent
,
312 p
->length
- p
->sent
, p
->flags
);
313 state
->sys_errno
= errno
;
315 if (state
->result
.result_ssize_t
== -1) {
316 async_req_error(req
, map_nt_error_from_unix(state
->sys_errno
));
320 if (state
->result
.result_ssize_t
== 0) {
321 async_req_error(req
, NT_STATUS_END_OF_FILE
);
325 p
->sent
+= state
->result
.result_ssize_t
;
326 if (p
->sent
> p
->length
) {
327 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
331 if (p
->sent
== p
->length
) {
332 TALLOC_FREE(state
->fde
);
338 * @brief Send all bytes to a socket
339 * @param[in] mem_ctx The memory context to hang the result off
340 * @param[in] ev The event context to work from
341 * @param[in] fd The socket to send to
342 * @param[in] buffer The buffer to send
343 * @param[in] length How many bytes to send
344 * @param[in] flags flags passed to send(2)
346 * async_sendall calls send(2) as long as it is necessary to send all of the
350 struct async_req
*sendall_send(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
351 int fd
, const void *buffer
, size_t length
,
354 struct async_req
*result
;
355 struct async_syscall_state
*state
;
357 result
= async_fde_syscall_new(
358 mem_ctx
, ev
, ASYNC_SYSCALL_SENDALL
,
359 fd
, EVENT_FD_WRITE
, async_sendall_callback
,
361 if (result
== NULL
) {
365 state
->param
.param_sendall
.fd
= fd
;
366 state
->param
.param_sendall
.buffer
= buffer
;
367 state
->param
.param_sendall
.length
= length
;
368 state
->param
.param_sendall
.flags
= flags
;
369 state
->param
.param_sendall
.sent
= 0;
374 NTSTATUS
sendall_recv(struct async_req
*req
)
376 return async_req_simple_recv(req
);
380 * fde event handler for the "recv" syscall
381 * @param[in] ev The event context that sent us here
382 * @param[in] fde The file descriptor event associated with the recv
383 * @param[in] flags Can only be EVENT_FD_READ here
384 * @param[in] priv private data, "struct async_req *" in this case
387 static void async_recv_callback(struct event_context
*ev
,
388 struct fd_event
*fde
, uint16_t flags
,
391 struct async_req
*req
= talloc_get_type_abort(
392 priv
, struct async_req
);
393 struct async_syscall_state
*state
= talloc_get_type_abort(
394 req
->private_data
, struct async_syscall_state
);
395 struct param_recv
*p
= &state
->param
.param_recv
;
397 if (state
->syscall_type
!= ASYNC_SYSCALL_RECV
) {
398 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
402 state
->result
.result_ssize_t
= recv(p
->fd
, p
->buffer
, p
->length
,
404 state
->sys_errno
= errno
;
406 TALLOC_FREE(state
->fde
);
412 * Async version of recv(2)
413 * @param[in] mem_ctx The memory context to hang the result off
414 * @param[in] ev The event context to work from
415 * @param[in] fd The socket to recv from
416 * @param[in] buffer The buffer to recv into
417 * @param[in] length How many bytes to recv
418 * @param[in] flags flags passed to recv(2)
420 * This function is a direct counterpart of recv(2)
423 struct async_req
*async_recv(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
424 int fd
, void *buffer
, size_t length
,
427 struct async_req
*result
;
428 struct async_syscall_state
*state
;
430 result
= async_fde_syscall_new(
431 mem_ctx
, ev
, ASYNC_SYSCALL_RECV
,
432 fd
, EVENT_FD_READ
, async_recv_callback
,
435 if (result
== NULL
) {
439 state
->param
.param_recv
.fd
= fd
;
440 state
->param
.param_recv
.buffer
= buffer
;
441 state
->param
.param_recv
.length
= length
;
442 state
->param
.param_recv
.flags
= flags
;
448 * fde event handler for the "recvall" syscall group
449 * @param[in] ev The event context that sent us here
450 * @param[in] fde The file descriptor event associated with the recv
451 * @param[in] flags Can only be EVENT_FD_READ here
452 * @param[in] priv private data, "struct async_req *" in this case
455 static void async_recvall_callback(struct event_context
*ev
,
456 struct fd_event
*fde
, uint16_t flags
,
459 struct async_req
*req
= talloc_get_type_abort(
460 priv
, struct async_req
);
461 struct async_syscall_state
*state
= talloc_get_type_abort(
462 req
->private_data
, struct async_syscall_state
);
463 struct param_recvall
*p
= &state
->param
.param_recvall
;
465 if (state
->syscall_type
!= ASYNC_SYSCALL_RECVALL
) {
466 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
470 state
->result
.result_ssize_t
= recv(p
->fd
,
471 (char *)p
->buffer
+ p
->received
,
472 p
->length
- p
->received
, p
->flags
);
473 state
->sys_errno
= errno
;
475 if (state
->result
.result_ssize_t
== -1) {
476 async_req_error(req
, map_nt_error_from_unix(state
->sys_errno
));
480 if (state
->result
.result_ssize_t
== 0) {
481 async_req_error(req
, NT_STATUS_END_OF_FILE
);
485 p
->received
+= state
->result
.result_ssize_t
;
486 if (p
->received
> p
->length
) {
487 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
491 if (p
->received
== p
->length
) {
492 TALLOC_FREE(state
->fde
);
498 * Receive a specified number of bytes from a socket
499 * @param[in] mem_ctx The memory context to hang the result off
500 * @param[in] ev The event context to work from
501 * @param[in] fd The socket to recv from
502 * @param[in] buffer The buffer to recv into
503 * @param[in] length How many bytes to recv
504 * @param[in] flags flags passed to recv(2)
506 * async_recvall will call recv(2) until "length" bytes are received
509 struct async_req
*recvall_send(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
510 int fd
, void *buffer
, size_t length
,
513 struct async_req
*result
;
514 struct async_syscall_state
*state
;
516 result
= async_fde_syscall_new(
517 mem_ctx
, ev
, ASYNC_SYSCALL_RECVALL
,
518 fd
, EVENT_FD_READ
, async_recvall_callback
,
520 if (result
== NULL
) {
524 state
->param
.param_recvall
.fd
= fd
;
525 state
->param
.param_recvall
.buffer
= buffer
;
526 state
->param
.param_recvall
.length
= length
;
527 state
->param
.param_recvall
.flags
= flags
;
528 state
->param
.param_recvall
.received
= 0;
533 NTSTATUS
recvall_recv(struct async_req
*req
)
535 return async_req_simple_recv(req
);
538 struct async_connect_state
{
545 static void async_connect_connected(struct event_context
*ev
,
546 struct fd_event
*fde
, uint16_t flags
,
550 * @brief async version of connect(2)
551 * @param[in] mem_ctx The memory context to hang the result off
552 * @param[in] ev The event context to work from
553 * @param[in] fd The socket to recv from
554 * @param[in] address Where to connect?
555 * @param[in] address_len Length of *address
556 * @retval The async request
558 * This function sets the socket into non-blocking state to be able to call
559 * connect in an async state. This will be reset when the request is finished.
562 struct async_req
*async_connect_send(TALLOC_CTX
*mem_ctx
,
563 struct event_context
*ev
,
564 int fd
, const struct sockaddr
*address
,
565 socklen_t address_len
)
567 struct async_req
*result
;
568 struct async_connect_state
*state
;
569 struct fd_event
*fde
;
572 result
= async_req_new(mem_ctx
);
573 if (result
== NULL
) {
576 state
= talloc(result
, struct async_connect_state
);
580 result
->private_data
= state
;
583 * We have to set the socket to nonblocking for async connect(2). Keep
584 * the old sockflags around.
588 state
->sys_errno
= 0;
590 state
->old_sockflags
= sys_fcntl_long(fd
, F_GETFL
, 0);
591 if (state
->old_sockflags
== -1) {
595 set_blocking(fd
, false);
597 state
->result
= connect(fd
, address
, address_len
);
598 if (state
->result
== 0) {
599 state
->sys_errno
= 0;
600 status
= NT_STATUS_OK
;
605 * A number of error messages show that something good is progressing
606 * and that we have to wait for readability.
608 * If none of them are present, bail out.
611 if (!(errno
== EINPROGRESS
|| errno
== EALREADY
||
615 errno
== EAGAIN
|| errno
== EINTR
)) {
619 fde
= event_add_fd(ev
, state
, fd
, EVENT_FD_READ
| EVENT_FD_WRITE
,
620 async_connect_connected
, result
);
622 status
= NT_STATUS_NO_MEMORY
;
628 state
->sys_errno
= errno
;
629 status
= map_nt_error_from_unix(state
->sys_errno
);
631 sys_fcntl_long(fd
, F_SETFL
, state
->old_sockflags
);
632 if (!async_post_status(result
, ev
, status
)) {
642 * fde event handler for connect(2)
643 * @param[in] ev The event context that sent us here
644 * @param[in] fde The file descriptor event associated with the connect
645 * @param[in] flags Indicate read/writeability of the socket
646 * @param[in] priv private data, "struct async_req *" in this case
649 static void async_connect_connected(struct event_context
*ev
,
650 struct fd_event
*fde
, uint16_t flags
,
653 struct async_req
*req
= talloc_get_type_abort(
654 priv
, struct async_req
);
655 struct async_connect_state
*state
= talloc_get_type_abort(
656 req
->private_data
, struct async_connect_state
);
661 * Stevens, Network Programming says that if there's a
662 * successful connect, the socket is only writable. Upon an
663 * error, it's both readable and writable.
665 if ((flags
& (EVENT_FD_READ
|EVENT_FD_WRITE
))
666 == (EVENT_FD_READ
|EVENT_FD_WRITE
)) {
668 socklen_t err_len
= sizeof(sockerr
);
670 if (getsockopt(state
->fd
, SOL_SOCKET
, SO_ERROR
,
671 (void *)&sockerr
, &err_len
) == 0) {
675 state
->sys_errno
= errno
;
677 DEBUG(10, ("connect returned %s\n", strerror(errno
)));
679 sys_fcntl_long(state
->fd
, F_SETFL
, state
->old_sockflags
);
680 async_req_error(req
, map_nt_error_from_unix(state
->sys_errno
));
684 state
->sys_errno
= 0;
688 NTSTATUS
async_connect_recv(struct async_req
*req
, int *perrno
)
690 struct async_connect_state
*state
= talloc_get_type_abort(
691 req
->private_data
, struct async_connect_state
);
694 sys_fcntl_long(state
->fd
, F_SETFL
, state
->old_sockflags
);
696 *perrno
= state
->sys_errno
;
698 if (async_req_is_error(req
, &status
)) {
701 if (state
->sys_errno
== 0) {
704 return map_nt_error_from_unix(state
->sys_errno
);