Document default of the printing config variable.
[Samba/nascimento.git] / source3 / lib / async_sock.c
blob73ff6f28709b89a8fa50f2f00815b5b07c655495
1 /*
2 Unix SMB/CIFS implementation.
3 async socket syscalls
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/>.
20 #include "includes.h"
22 /**
23 * Discriminator for async_syscall_state
25 enum async_syscall_type {
26 ASYNC_SYSCALL_SEND,
27 ASYNC_SYSCALL_SENDALL,
28 ASYNC_SYSCALL_RECV,
29 ASYNC_SYSCALL_RECVALL,
30 ASYNC_SYSCALL_CONNECT
33 /**
34 * Holder for syscall arguments and the result
37 struct async_syscall_state {
38 enum async_syscall_type syscall_type;
39 struct fd_event *fde;
41 union {
42 struct param_send {
43 int fd;
44 const void *buffer;
45 size_t length;
46 int flags;
47 } param_send;
48 struct param_sendall {
49 int fd;
50 const void *buffer;
51 size_t length;
52 int flags;
53 size_t sent;
54 } param_sendall;
55 struct param_recv {
56 int fd;
57 void *buffer;
58 size_t length;
59 int flags;
60 } param_recv;
61 struct param_recvall {
62 int fd;
63 void *buffer;
64 size_t length;
65 int flags;
66 size_t received;
67 } param_recvall;
68 struct param_connect {
69 /**
70 * connect needs to be done on a nonblocking
71 * socket. Keep the old flags around
73 long old_sockflags;
74 int fd;
75 const struct sockaddr *address;
76 socklen_t address_len;
77 } param_connect;
78 } param;
80 union {
81 ssize_t result_ssize_t;
82 size_t result_size_t;
83 int result_int;
84 } result;
85 int sys_errno;
88 /**
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)) {
111 return NULL;
113 state->syscall_type = type;
115 result->private_data = state;
117 *pstate = state;
119 return result;
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
135 * event.
138 static struct async_req *async_fde_syscall_new(
139 TALLOC_CTX *mem_ctx,
140 struct event_context *ev,
141 enum async_syscall_type type,
142 int fd,
143 uint16_t fde_flags,
144 void (*fde_cb)(struct event_context *ev,
145 struct fd_event *fde, uint16_t flags,
146 void *priv),
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) {
154 return NULL;
157 state->fde = event_add_fd(ev, state, fd, fde_flags, fde_cb, result);
158 if (state->fde == NULL) {
159 TALLOC_FREE(result);
160 return NULL;
162 *pstate = state;
163 return result;
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,
224 void *priv)
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);
234 return;
237 state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
238 p->flags);
239 state->sys_errno = errno;
241 TALLOC_FREE(state->fde);
243 async_req_done(req);
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,
260 int flags)
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,
268 &state);
269 if (result == NULL) {
270 return 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;
278 return result;
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,
291 void *priv)
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);
301 return;
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));
310 return;
313 if (state->result.result_ssize_t == 0) {
314 async_req_error(req, NT_STATUS_END_OF_FILE);
315 return;
318 p->sent += state->result.result_ssize_t;
319 if (p->sent > p->length) {
320 async_req_error(req, NT_STATUS_INTERNAL_ERROR);
321 return;
324 if (p->sent == p->length) {
325 TALLOC_FREE(state->fde);
326 async_req_done(req);
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
340 * "length" bytes
343 struct async_req *sendall_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
344 int fd, const void *buffer, size_t length,
345 int flags)
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,
353 &state);
354 if (result == NULL) {
355 return 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;
364 return result;
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,
382 void *priv)
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);
392 return;
395 state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
396 p->flags);
397 state->sys_errno = errno;
399 TALLOC_FREE(state->fde);
401 async_req_done(req);
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,
418 int flags)
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,
426 &state);
428 if (result == NULL) {
429 return 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;
437 return result;
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,
450 void *priv)
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);
460 return;
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));
470 return;
473 if (state->result.result_ssize_t == 0) {
474 async_req_error(req, NT_STATUS_END_OF_FILE);
475 return;
478 p->received += state->result.result_ssize_t;
479 if (p->received > p->length) {
480 async_req_error(req, NT_STATUS_INTERNAL_ERROR);
481 return;
484 if (p->received == p->length) {
485 TALLOC_FREE(state->fde);
486 async_req_done(req);
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,
504 int flags)
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,
512 &state);
513 if (result == NULL) {
514 return 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;
523 return result;
526 NTSTATUS recvall_recv(struct async_req *req)
528 return async_req_simple_recv(req);
531 struct async_connect_state {
532 int fd;
533 int result;
534 int sys_errno;
535 long old_sockflags;
538 static void async_connect_connected(struct event_context *ev,
539 struct fd_event *fde, uint16_t flags,
540 void *priv);
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;
563 NTSTATUS status;
565 if (!async_req_setup(mem_ctx, &result, &state,
566 struct async_connect_state)) {
567 return NULL;
571 * We have to set the socket to nonblocking for async connect(2). Keep
572 * the old sockflags around.
575 state->fd = fd;
576 state->sys_errno = 0;
578 state->old_sockflags = sys_fcntl_long(fd, F_GETFL, 0);
579 if (state->old_sockflags == -1) {
580 goto post_errno;
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;
589 goto post_status;
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 ||
600 #ifdef EISCONN
601 errno == EISCONN ||
602 #endif
603 errno == EAGAIN || errno == EINTR)) {
604 goto post_errno;
607 fde = event_add_fd(ev, state, fd, EVENT_FD_READ | EVENT_FD_WRITE,
608 async_connect_connected, result);
609 if (fde == NULL) {
610 status = NT_STATUS_NO_MEMORY;
611 goto post_status;
613 return result;
615 post_errno:
616 state->sys_errno = errno;
617 status = map_nt_error_from_unix(state->sys_errno);
618 post_status:
619 sys_fcntl_long(fd, F_SETFL, state->old_sockflags);
620 if (!async_post_status(result, ev, status)) {
621 goto fail;
623 return result;
624 fail:
625 TALLOC_FREE(result);
626 return NULL;
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,
639 void *priv)
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);
646 TALLOC_FREE(fde);
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)) {
655 int sockerr;
656 socklen_t err_len = sizeof(sockerr);
658 if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
659 (void *)&sockerr, &err_len) == 0) {
660 errno = sockerr;
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));
669 return;
672 state->sys_errno = 0;
673 async_req_done(req);
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);
680 NTSTATUS status;
682 sys_fcntl_long(state->fd, F_SETFL, state->old_sockflags);
684 *perrno = state->sys_errno;
686 if (async_req_is_error(req, &status)) {
687 return status;
689 if (state->sys_errno == 0) {
690 return NT_STATUS_OK;
692 return map_nt_error_from_unix(state->sys_errno);