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
, ev
);
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 int sys_errno
= state
->sys_errno
;
186 ssize_t result
= state
->result
.result_ssize_t
;
195 * Retrieve a size_t typed result from an async syscall
196 * @param[in] req The syscall that has just finished
197 * @param[out] perrno Where to put the syscall's errno
198 * @retval The return value from the asynchronously called syscall
201 size_t async_syscall_result_size_t(struct async_req
**req
, int *perrno
)
203 struct async_syscall_state
*state
= talloc_get_type_abort(
204 (*req
)->private_data
, struct async_syscall_state
);
206 int sys_errno
= state
->sys_errno
;
207 size_t result
= state
->result
.result_ssize_t
;
216 * Retrieve a int typed result from an async syscall
217 * @param[in] req The syscall that has just finished
218 * @param[out] perrno Where to put the syscall's errno
219 * @retval The return value from the asynchronously called syscall
222 ssize_t
async_syscall_result_int(struct async_req
**req
, int *perrno
)
224 struct async_syscall_state
*state
= talloc_get_type_abort(
225 (*req
)->private_data
, struct async_syscall_state
);
227 int sys_errno
= state
->sys_errno
;
228 int result
= state
->result
.result_ssize_t
;
237 * fde event handler for the "send" syscall
238 * @param[in] ev The event context that sent us here
239 * @param[in] fde The file descriptor event associated with the send
240 * @param[in] flags Can only be EVENT_FD_WRITE here
241 * @param[in] priv private data, "struct async_req *" in this case
244 static void async_send_callback(struct event_context
*ev
,
245 struct fd_event
*fde
, uint16_t flags
,
248 struct async_req
*req
= talloc_get_type_abort(
249 priv
, struct async_req
);
250 struct async_syscall_state
*state
= talloc_get_type_abort(
251 req
->private_data
, struct async_syscall_state
);
252 struct param_send
*p
= &state
->param
.param_send
;
254 SMB_ASSERT(state
->syscall_type
== ASYNC_SYSCALL_SEND
);
256 state
->result
.result_ssize_t
= send(p
->fd
, p
->buffer
, p
->length
,
258 state
->sys_errno
= errno
;
260 TALLOC_FREE(state
->fde
);
266 * Async version of send(2)
267 * @param[in] mem_ctx The memory context to hang the result off
268 * @param[in] ev The event context to work from
269 * @param[in] fd The socket to send to
270 * @param[in] buffer The buffer to send
271 * @param[in] length How many bytes to send
272 * @param[in] flags flags passed to send(2)
274 * This function is a direct counterpart of send(2)
277 struct async_req
*async_send(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
278 int fd
, const void *buffer
, size_t length
,
281 struct async_req
*result
;
282 struct async_syscall_state
*state
;
284 result
= async_fde_syscall_new(
285 mem_ctx
, ev
, ASYNC_SYSCALL_SEND
,
286 fd
, EVENT_FD_WRITE
, async_send_callback
,
288 if (result
== NULL
) {
292 state
->param
.param_send
.fd
= fd
;
293 state
->param
.param_send
.buffer
= buffer
;
294 state
->param
.param_send
.length
= length
;
295 state
->param
.param_send
.flags
= flags
;
301 * fde event handler for the "sendall" syscall group
302 * @param[in] ev The event context that sent us here
303 * @param[in] fde The file descriptor event associated with the send
304 * @param[in] flags Can only be EVENT_FD_WRITE here
305 * @param[in] priv private data, "struct async_req *" in this case
308 static void async_sendall_callback(struct event_context
*ev
,
309 struct fd_event
*fde
, uint16_t flags
,
312 struct async_req
*req
= talloc_get_type_abort(
313 priv
, struct async_req
);
314 struct async_syscall_state
*state
= talloc_get_type_abort(
315 req
->private_data
, struct async_syscall_state
);
316 struct param_sendall
*p
= &state
->param
.param_sendall
;
318 SMB_ASSERT(state
->syscall_type
== ASYNC_SYSCALL_SENDALL
);
320 state
->result
.result_ssize_t
= send(p
->fd
, (char *)p
->buffer
+ p
->sent
,
321 p
->length
- p
->sent
, p
->flags
);
322 state
->sys_errno
= errno
;
324 if (state
->result
.result_ssize_t
== -1) {
325 async_req_error(req
, map_nt_error_from_unix(state
->sys_errno
));
329 if (state
->result
.result_ssize_t
== 0) {
330 async_req_error(req
, NT_STATUS_END_OF_FILE
);
334 p
->sent
+= state
->result
.result_ssize_t
;
335 SMB_ASSERT(p
->sent
<= p
->length
);
337 if (p
->sent
== p
->length
) {
338 TALLOC_FREE(state
->fde
);
344 * @brief Send all bytes to a socket
345 * @param[in] mem_ctx The memory context to hang the result off
346 * @param[in] ev The event context to work from
347 * @param[in] fd The socket to send to
348 * @param[in] buffer The buffer to send
349 * @param[in] length How many bytes to send
350 * @param[in] flags flags passed to send(2)
352 * async_sendall calls send(2) as long as it is necessary to send all of the
356 struct async_req
*async_sendall(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
357 int fd
, const void *buffer
, size_t length
,
360 struct async_req
*result
;
361 struct async_syscall_state
*state
;
363 result
= async_fde_syscall_new(
364 mem_ctx
, ev
, ASYNC_SYSCALL_SENDALL
,
365 fd
, EVENT_FD_WRITE
, async_sendall_callback
,
367 if (result
== NULL
) {
371 state
->param
.param_sendall
.fd
= fd
;
372 state
->param
.param_sendall
.buffer
= buffer
;
373 state
->param
.param_sendall
.length
= length
;
374 state
->param
.param_sendall
.flags
= flags
;
375 state
->param
.param_sendall
.sent
= 0;
381 * fde event handler for the "recv" syscall
382 * @param[in] ev The event context that sent us here
383 * @param[in] fde The file descriptor event associated with the recv
384 * @param[in] flags Can only be EVENT_FD_READ here
385 * @param[in] priv private data, "struct async_req *" in this case
388 static void async_recv_callback(struct event_context
*ev
,
389 struct fd_event
*fde
, uint16_t flags
,
392 struct async_req
*req
= talloc_get_type_abort(
393 priv
, struct async_req
);
394 struct async_syscall_state
*state
= talloc_get_type_abort(
395 req
->private_data
, struct async_syscall_state
);
396 struct param_recv
*p
= &state
->param
.param_recv
;
398 SMB_ASSERT(state
->syscall_type
== ASYNC_SYSCALL_RECV
);
400 state
->result
.result_ssize_t
= recv(p
->fd
, p
->buffer
, p
->length
,
402 state
->sys_errno
= errno
;
404 TALLOC_FREE(state
->fde
);
410 * Async version of recv(2)
411 * @param[in] mem_ctx The memory context to hang the result off
412 * @param[in] ev The event context to work from
413 * @param[in] fd The socket to recv from
414 * @param[in] buffer The buffer to recv into
415 * @param[in] length How many bytes to recv
416 * @param[in] flags flags passed to recv(2)
418 * This function is a direct counterpart of recv(2)
421 struct async_req
*async_recv(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
422 int fd
, void *buffer
, size_t length
,
425 struct async_req
*result
;
426 struct async_syscall_state
*state
;
428 result
= async_fde_syscall_new(
429 mem_ctx
, ev
, ASYNC_SYSCALL_RECV
,
430 fd
, EVENT_FD_READ
, async_recv_callback
,
433 if (result
== NULL
) {
437 state
->param
.param_recv
.fd
= fd
;
438 state
->param
.param_recv
.buffer
= buffer
;
439 state
->param
.param_recv
.length
= length
;
440 state
->param
.param_recv
.flags
= flags
;
446 * fde event handler for the "recvall" syscall group
447 * @param[in] ev The event context that sent us here
448 * @param[in] fde The file descriptor event associated with the recv
449 * @param[in] flags Can only be EVENT_FD_READ here
450 * @param[in] priv private data, "struct async_req *" in this case
453 static void async_recvall_callback(struct event_context
*ev
,
454 struct fd_event
*fde
, uint16_t flags
,
457 struct async_req
*req
= talloc_get_type_abort(
458 priv
, struct async_req
);
459 struct async_syscall_state
*state
= talloc_get_type_abort(
460 req
->private_data
, struct async_syscall_state
);
461 struct param_recvall
*p
= &state
->param
.param_recvall
;
463 SMB_ASSERT(state
->syscall_type
== ASYNC_SYSCALL_RECVALL
);
465 state
->result
.result_ssize_t
= recv(p
->fd
,
466 (char *)p
->buffer
+ p
->received
,
467 p
->length
- p
->received
, p
->flags
);
468 state
->sys_errno
= errno
;
470 if (state
->result
.result_ssize_t
== -1) {
471 async_req_error(req
, map_nt_error_from_unix(state
->sys_errno
));
475 if (state
->result
.result_ssize_t
== 0) {
476 async_req_error(req
, NT_STATUS_END_OF_FILE
);
480 p
->received
+= state
->result
.result_ssize_t
;
481 SMB_ASSERT(p
->received
<= p
->length
);
483 if (p
->received
== p
->length
) {
484 TALLOC_FREE(state
->fde
);
490 * Receive a specified number of bytes from a socket
491 * @param[in] mem_ctx The memory context to hang the result off
492 * @param[in] ev The event context to work from
493 * @param[in] fd The socket to recv from
494 * @param[in] buffer The buffer to recv into
495 * @param[in] length How many bytes to recv
496 * @param[in] flags flags passed to recv(2)
498 * async_recvall will call recv(2) until "length" bytes are received
501 struct async_req
*async_recvall(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
502 int fd
, void *buffer
, size_t length
,
505 struct async_req
*result
;
506 struct async_syscall_state
*state
;
508 result
= async_fde_syscall_new(
509 mem_ctx
, ev
, ASYNC_SYSCALL_RECVALL
,
510 fd
, EVENT_FD_READ
, async_recvall_callback
,
512 if (result
== NULL
) {
516 state
->param
.param_recvall
.fd
= fd
;
517 state
->param
.param_recvall
.buffer
= buffer
;
518 state
->param
.param_recvall
.length
= length
;
519 state
->param
.param_recvall
.flags
= flags
;
520 state
->param
.param_recvall
.received
= 0;
526 * fde event handler for connect(2)
527 * @param[in] ev The event context that sent us here
528 * @param[in] fde The file descriptor event associated with the connect
529 * @param[in] flags Indicate read/writeability of the socket
530 * @param[in] priv private data, "struct async_req *" in this case
533 static void async_connect_callback(struct event_context
*ev
,
534 struct fd_event
*fde
, uint16_t flags
,
537 struct async_req
*req
= talloc_get_type_abort(
538 priv
, struct async_req
);
539 struct async_syscall_state
*state
= talloc_get_type_abort(
540 req
->private_data
, struct async_syscall_state
);
541 struct param_connect
*p
= &state
->param
.param_connect
;
543 SMB_ASSERT(state
->syscall_type
== ASYNC_SYSCALL_CONNECT
);
545 TALLOC_FREE(state
->fde
);
548 * Stevens, Network Programming says that if there's a
549 * successful connect, the socket is only writable. Upon an
550 * error, it's both readable and writable.
552 if ((flags
& (EVENT_FD_READ
|EVENT_FD_WRITE
))
553 == (EVENT_FD_READ
|EVENT_FD_WRITE
)) {
555 socklen_t err_len
= sizeof(sockerr
);
557 if (getsockopt(p
->fd
, SOL_SOCKET
, SO_ERROR
,
558 (void *)&sockerr
, &err_len
) == 0) {
562 state
->sys_errno
= errno
;
564 DEBUG(10, ("connect returned %s\n", strerror(errno
)));
566 sys_fcntl_long(p
->fd
, F_SETFL
, p
->old_sockflags
);
568 async_req_error(req
, map_nt_error_from_unix(state
->sys_errno
));
572 sys_fcntl_long(p
->fd
, F_SETFL
, p
->old_sockflags
);
574 state
->result
.result_int
= 0;
575 state
->sys_errno
= 0;
581 * @brief async version of connect(2)
582 * @param[in] mem_ctx The memory context to hang the result off
583 * @param[in] ev The event context to work from
584 * @param[in] fd The socket to recv from
585 * @param[in] address Where to connect?
586 * @param[in] address_len Length of *address
587 * @retval The async request
589 * This function sets the socket into non-blocking state to be able to call
590 * connect in an async state. This will be reset when the request is finished.
593 struct async_req
*async_connect(TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
594 int fd
, const struct sockaddr
*address
,
595 socklen_t address_len
)
597 struct async_req
*result
;
598 struct async_syscall_state
*state
;
599 struct param_connect
*p
;
601 result
= async_syscall_new(mem_ctx
, ev
, ASYNC_SYSCALL_CONNECT
, &state
);
602 if (result
== NULL
) {
605 p
= &state
->param
.param_connect
;
608 * We have to set the socket to nonblocking for async connect(2). Keep
609 * the old sockflags around.
612 p
->old_sockflags
= sys_fcntl_long(fd
, F_GETFL
, 0);
614 if (p
->old_sockflags
== -1) {
615 if (async_post_status(result
, map_nt_error_from_unix(errno
))) {
622 set_blocking(fd
, true);
624 state
->result
.result_int
= connect(fd
, address
, address_len
);
626 if (state
->result
.result_int
== 0) {
627 state
->sys_errno
= 0;
628 if (async_post_status(result
, NT_STATUS_OK
)) {
631 sys_fcntl_long(fd
, F_SETFL
, p
->old_sockflags
);
637 * A number of error messages show that something good is progressing
638 * and that we have to wait for readability.
640 * If none of them are present, bail out.
643 if (!(errno
== EINPROGRESS
|| errno
== EALREADY
||
647 errno
== EAGAIN
|| errno
== EINTR
)) {
649 state
->sys_errno
= errno
;
651 if (async_post_status(result
, map_nt_error_from_unix(errno
))) {
654 sys_fcntl_long(fd
, F_SETFL
, p
->old_sockflags
);
659 state
->fde
= event_add_fd(ev
, state
, fd
,
660 EVENT_FD_READ
| EVENT_FD_WRITE
,
661 async_connect_callback
, state
);
662 if (state
->fde
== NULL
) {
663 sys_fcntl_long(fd
, F_SETFL
, p
->old_sockflags
);
668 state
->param
.param_connect
.fd
= fd
;
669 state
->param
.param_connect
.address
= address
;
670 state
->param
.param_connect
.address_len
= address_len
;