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 if (!async_req_setup(mem_ctx
, &result
, &state
,
110 struct async_syscall_state
)) {
113 state
->syscall_type
= type
;
115 result
->private_data
= state
;
123 * @brief Create a new async syscall req based on a fd
124 * @param[in] mem_ctx The memory context to hang the result off
125 * @param[in] ev The event context to work from
126 * @param[in] type Which syscall will this be
127 * @param[in] fd The file descriptor we work on
128 * @param[in] fde_flags EVENT_FD_READ/WRITE -- what are we interested in?
129 * @param[in] fde_cb The callback function for the file descriptor event
130 * @param[in] pstate Where to put the newly created private_data state
131 * @retval The new request
133 * This is a helper function to prepare a new struct async_req with an
134 * associated struct async_syscall_state and an associated file descriptor
138 static struct async_req
*async_fde_syscall_new(
140 struct event_context
*ev
,
141 enum async_syscall_type type
,
144 void (*fde_cb
)(struct event_context
*ev
,
145 struct fd_event
*fde
, uint16_t flags
,
147 struct async_syscall_state
**pstate
)
149 struct async_req
*result
;
150 struct async_syscall_state
*state
;
152 result
= async_syscall_new(mem_ctx
, ev
, type
, &state
);
153 if (result
== NULL
) {
157 state
->fde
= event_add_fd(ev
, state
, fd
, fde_flags
, fde_cb
, result
);
158 if (state
->fde
== NULL
) {
167 * Retrieve a ssize_t typed result from an async syscall
168 * @param[in] req The syscall that has just finished
169 * @param[out] perrno Where to put the syscall's errno
170 * @retval The return value from the asynchronously called syscall
173 ssize_t
async_syscall_result_ssize_t(struct async_req
*req
, int *perrno
)
175 struct async_syscall_state
*state
= talloc_get_type_abort(
176 req
->private_data
, struct async_syscall_state
);
178 *perrno
= state
->sys_errno
;
179 return state
->result
.result_ssize_t
;
183 * Retrieve a size_t typed result from an async syscall
184 * @param[in] req The syscall that has just finished
185 * @param[out] perrno Where to put the syscall's errno
186 * @retval The return value from the asynchronously called syscall
189 size_t async_syscall_result_size_t(struct async_req
*req
, int *perrno
)
191 struct async_syscall_state
*state
= talloc_get_type_abort(
192 req
->private_data
, struct async_syscall_state
);
194 *perrno
= state
->sys_errno
;
195 return state
->result
.result_size_t
;
199 * Retrieve a int 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 int async_syscall_result_int(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_int
;
215 * fde event handler for the "send" syscall
216 * @param[in] ev The event context that sent us here
217 * @param[in] fde The file descriptor event associated with the send
218 * @param[in] flags Can only be EVENT_FD_WRITE here
219 * @param[in] priv private data, "struct async_req *" in this case
222 static void async_send_callback(struct event_context
*ev
,
223 struct fd_event
*fde
, uint16_t flags
,
226 struct async_req
*req
= talloc_get_type_abort(
227 priv
, struct async_req
);
228 struct async_syscall_state
*state
= talloc_get_type_abort(
229 req
->private_data
, struct async_syscall_state
);
230 struct param_send
*p
= &state
->param
.param_send
;
232 if (state
->syscall_type
!= ASYNC_SYSCALL_SEND
) {
233 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
237 state
->result
.result_ssize_t
= send(p
->fd
, p
->buffer
, p
->length
,
239 state
->sys_errno
= errno
;
241 TALLOC_FREE(state
->fde
);
247 * Async version of send(2)
248 * @param[in] mem_ctx The memory context to hang the result off
249 * @param[in] ev The event context to work from
250 * @param[in] fd The socket to send to
251 * @param[in] buffer The buffer to send
252 * @param[in] length How many bytes to send
253 * @param[in] flags flags passed to send(2)
255 * This function is a direct counterpart of send(2)
258 struct async_req
*async_send(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
259 int fd
, const void *buffer
, size_t length
,
262 struct async_req
*result
;
263 struct async_syscall_state
*state
;
265 result
= async_fde_syscall_new(
266 mem_ctx
, ev
, ASYNC_SYSCALL_SEND
,
267 fd
, EVENT_FD_WRITE
, async_send_callback
,
269 if (result
== NULL
) {
273 state
->param
.param_send
.fd
= fd
;
274 state
->param
.param_send
.buffer
= buffer
;
275 state
->param
.param_send
.length
= length
;
276 state
->param
.param_send
.flags
= flags
;
282 * fde event handler for the "sendall" syscall group
283 * @param[in] ev The event context that sent us here
284 * @param[in] fde The file descriptor event associated with the send
285 * @param[in] flags Can only be EVENT_FD_WRITE here
286 * @param[in] priv private data, "struct async_req *" in this case
289 static void async_sendall_callback(struct event_context
*ev
,
290 struct fd_event
*fde
, uint16_t flags
,
293 struct async_req
*req
= talloc_get_type_abort(
294 priv
, struct async_req
);
295 struct async_syscall_state
*state
= talloc_get_type_abort(
296 req
->private_data
, struct async_syscall_state
);
297 struct param_sendall
*p
= &state
->param
.param_sendall
;
299 if (state
->syscall_type
!= ASYNC_SYSCALL_SENDALL
) {
300 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
304 state
->result
.result_ssize_t
= send(p
->fd
, (char *)p
->buffer
+ p
->sent
,
305 p
->length
- p
->sent
, p
->flags
);
306 state
->sys_errno
= errno
;
308 if (state
->result
.result_ssize_t
== -1) {
309 async_req_error(req
, map_nt_error_from_unix(state
->sys_errno
));
313 if (state
->result
.result_ssize_t
== 0) {
314 async_req_error(req
, NT_STATUS_END_OF_FILE
);
318 p
->sent
+= state
->result
.result_ssize_t
;
319 if (p
->sent
> p
->length
) {
320 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
324 if (p
->sent
== p
->length
) {
325 TALLOC_FREE(state
->fde
);
331 * @brief Send all bytes to a socket
332 * @param[in] mem_ctx The memory context to hang the result off
333 * @param[in] ev The event context to work from
334 * @param[in] fd The socket to send to
335 * @param[in] buffer The buffer to send
336 * @param[in] length How many bytes to send
337 * @param[in] flags flags passed to send(2)
339 * async_sendall calls send(2) as long as it is necessary to send all of the
343 struct async_req
*sendall_send(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
344 int fd
, const void *buffer
, size_t length
,
347 struct async_req
*result
;
348 struct async_syscall_state
*state
;
350 result
= async_fde_syscall_new(
351 mem_ctx
, ev
, ASYNC_SYSCALL_SENDALL
,
352 fd
, EVENT_FD_WRITE
, async_sendall_callback
,
354 if (result
== NULL
) {
358 state
->param
.param_sendall
.fd
= fd
;
359 state
->param
.param_sendall
.buffer
= buffer
;
360 state
->param
.param_sendall
.length
= length
;
361 state
->param
.param_sendall
.flags
= flags
;
362 state
->param
.param_sendall
.sent
= 0;
367 NTSTATUS
sendall_recv(struct async_req
*req
)
369 return async_req_simple_recv(req
);
373 * fde event handler for the "recv" syscall
374 * @param[in] ev The event context that sent us here
375 * @param[in] fde The file descriptor event associated with the recv
376 * @param[in] flags Can only be EVENT_FD_READ here
377 * @param[in] priv private data, "struct async_req *" in this case
380 static void async_recv_callback(struct event_context
*ev
,
381 struct fd_event
*fde
, uint16_t flags
,
384 struct async_req
*req
= talloc_get_type_abort(
385 priv
, struct async_req
);
386 struct async_syscall_state
*state
= talloc_get_type_abort(
387 req
->private_data
, struct async_syscall_state
);
388 struct param_recv
*p
= &state
->param
.param_recv
;
390 if (state
->syscall_type
!= ASYNC_SYSCALL_RECV
) {
391 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
395 state
->result
.result_ssize_t
= recv(p
->fd
, p
->buffer
, p
->length
,
397 state
->sys_errno
= errno
;
399 TALLOC_FREE(state
->fde
);
405 * Async version of recv(2)
406 * @param[in] mem_ctx The memory context to hang the result off
407 * @param[in] ev The event context to work from
408 * @param[in] fd The socket to recv from
409 * @param[in] buffer The buffer to recv into
410 * @param[in] length How many bytes to recv
411 * @param[in] flags flags passed to recv(2)
413 * This function is a direct counterpart of recv(2)
416 struct async_req
*async_recv(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
417 int fd
, void *buffer
, size_t length
,
420 struct async_req
*result
;
421 struct async_syscall_state
*state
;
423 result
= async_fde_syscall_new(
424 mem_ctx
, ev
, ASYNC_SYSCALL_RECV
,
425 fd
, EVENT_FD_READ
, async_recv_callback
,
428 if (result
== NULL
) {
432 state
->param
.param_recv
.fd
= fd
;
433 state
->param
.param_recv
.buffer
= buffer
;
434 state
->param
.param_recv
.length
= length
;
435 state
->param
.param_recv
.flags
= flags
;
441 * fde event handler for the "recvall" syscall group
442 * @param[in] ev The event context that sent us here
443 * @param[in] fde The file descriptor event associated with the recv
444 * @param[in] flags Can only be EVENT_FD_READ here
445 * @param[in] priv private data, "struct async_req *" in this case
448 static void async_recvall_callback(struct event_context
*ev
,
449 struct fd_event
*fde
, uint16_t flags
,
452 struct async_req
*req
= talloc_get_type_abort(
453 priv
, struct async_req
);
454 struct async_syscall_state
*state
= talloc_get_type_abort(
455 req
->private_data
, struct async_syscall_state
);
456 struct param_recvall
*p
= &state
->param
.param_recvall
;
458 if (state
->syscall_type
!= ASYNC_SYSCALL_RECVALL
) {
459 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
463 state
->result
.result_ssize_t
= recv(p
->fd
,
464 (char *)p
->buffer
+ p
->received
,
465 p
->length
- p
->received
, p
->flags
);
466 state
->sys_errno
= errno
;
468 if (state
->result
.result_ssize_t
== -1) {
469 async_req_error(req
, map_nt_error_from_unix(state
->sys_errno
));
473 if (state
->result
.result_ssize_t
== 0) {
474 async_req_error(req
, NT_STATUS_END_OF_FILE
);
478 p
->received
+= state
->result
.result_ssize_t
;
479 if (p
->received
> p
->length
) {
480 async_req_error(req
, NT_STATUS_INTERNAL_ERROR
);
484 if (p
->received
== p
->length
) {
485 TALLOC_FREE(state
->fde
);
491 * Receive a specified number of bytes from a socket
492 * @param[in] mem_ctx The memory context to hang the result off
493 * @param[in] ev The event context to work from
494 * @param[in] fd The socket to recv from
495 * @param[in] buffer The buffer to recv into
496 * @param[in] length How many bytes to recv
497 * @param[in] flags flags passed to recv(2)
499 * async_recvall will call recv(2) until "length" bytes are received
502 struct async_req
*recvall_send(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
503 int fd
, void *buffer
, size_t length
,
506 struct async_req
*result
;
507 struct async_syscall_state
*state
;
509 result
= async_fde_syscall_new(
510 mem_ctx
, ev
, ASYNC_SYSCALL_RECVALL
,
511 fd
, EVENT_FD_READ
, async_recvall_callback
,
513 if (result
== NULL
) {
517 state
->param
.param_recvall
.fd
= fd
;
518 state
->param
.param_recvall
.buffer
= buffer
;
519 state
->param
.param_recvall
.length
= length
;
520 state
->param
.param_recvall
.flags
= flags
;
521 state
->param
.param_recvall
.received
= 0;
526 NTSTATUS
recvall_recv(struct async_req
*req
)
528 return async_req_simple_recv(req
);
531 struct async_connect_state
{
538 static void async_connect_connected(struct event_context
*ev
,
539 struct fd_event
*fde
, uint16_t flags
,
543 * @brief async version of connect(2)
544 * @param[in] mem_ctx The memory context to hang the result off
545 * @param[in] ev The event context to work from
546 * @param[in] fd The socket to recv from
547 * @param[in] address Where to connect?
548 * @param[in] address_len Length of *address
549 * @retval The async request
551 * This function sets the socket into non-blocking state to be able to call
552 * connect in an async state. This will be reset when the request is finished.
555 struct async_req
*async_connect_send(TALLOC_CTX
*mem_ctx
,
556 struct event_context
*ev
,
557 int fd
, const struct sockaddr
*address
,
558 socklen_t address_len
)
560 struct async_req
*result
;
561 struct async_connect_state
*state
;
562 struct fd_event
*fde
;
565 if (!async_req_setup(mem_ctx
, &result
, &state
,
566 struct async_connect_state
)) {
571 * We have to set the socket to nonblocking for async connect(2). Keep
572 * the old sockflags around.
576 state
->sys_errno
= 0;
578 state
->old_sockflags
= sys_fcntl_long(fd
, F_GETFL
, 0);
579 if (state
->old_sockflags
== -1) {
583 set_blocking(fd
, false);
585 state
->result
= connect(fd
, address
, address_len
);
586 if (state
->result
== 0) {
587 state
->sys_errno
= 0;
588 status
= NT_STATUS_OK
;
593 * A number of error messages show that something good is progressing
594 * and that we have to wait for readability.
596 * If none of them are present, bail out.
599 if (!(errno
== EINPROGRESS
|| errno
== EALREADY
||
603 errno
== EAGAIN
|| errno
== EINTR
)) {
607 fde
= event_add_fd(ev
, state
, fd
, EVENT_FD_READ
| EVENT_FD_WRITE
,
608 async_connect_connected
, result
);
610 status
= NT_STATUS_NO_MEMORY
;
616 state
->sys_errno
= errno
;
617 status
= map_nt_error_from_unix(state
->sys_errno
);
619 sys_fcntl_long(fd
, F_SETFL
, state
->old_sockflags
);
620 if (!async_post_status(result
, ev
, status
)) {
630 * fde event handler for connect(2)
631 * @param[in] ev The event context that sent us here
632 * @param[in] fde The file descriptor event associated with the connect
633 * @param[in] flags Indicate read/writeability of the socket
634 * @param[in] priv private data, "struct async_req *" in this case
637 static void async_connect_connected(struct event_context
*ev
,
638 struct fd_event
*fde
, uint16_t flags
,
641 struct async_req
*req
= talloc_get_type_abort(
642 priv
, struct async_req
);
643 struct async_connect_state
*state
= talloc_get_type_abort(
644 req
->private_data
, struct async_connect_state
);
649 * Stevens, Network Programming says that if there's a
650 * successful connect, the socket is only writable. Upon an
651 * error, it's both readable and writable.
653 if ((flags
& (EVENT_FD_READ
|EVENT_FD_WRITE
))
654 == (EVENT_FD_READ
|EVENT_FD_WRITE
)) {
656 socklen_t err_len
= sizeof(sockerr
);
658 if (getsockopt(state
->fd
, SOL_SOCKET
, SO_ERROR
,
659 (void *)&sockerr
, &err_len
) == 0) {
663 state
->sys_errno
= errno
;
665 DEBUG(10, ("connect returned %s\n", strerror(errno
)));
667 sys_fcntl_long(state
->fd
, F_SETFL
, state
->old_sockflags
);
668 async_req_error(req
, map_nt_error_from_unix(state
->sys_errno
));
672 state
->sys_errno
= 0;
676 NTSTATUS
async_connect_recv(struct async_req
*req
, int *perrno
)
678 struct async_connect_state
*state
= talloc_get_type_abort(
679 req
->private_data
, struct async_connect_state
);
682 sys_fcntl_long(state
->fd
, F_SETFL
, state
->old_sockflags
);
684 *perrno
= state
->sys_errno
;
686 if (async_req_is_error(req
, &status
)) {
689 if (state
->sys_errno
== 0) {
692 return map_nt_error_from_unix(state
->sys_errno
);