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"
28 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
32 * Discriminator for async_syscall_state
34 enum async_syscall_type {
36 ASYNC_SYSCALL_SENDALL,
38 ASYNC_SYSCALL_RECVALL,
43 * Holder for syscall arguments and the result
46 struct async_syscall_state {
47 enum async_syscall_type syscall_type;
48 struct tevent_fd *fde;
57 struct param_sendall {
70 struct param_recvall {
77 struct param_connect {
79 * connect needs to be done on a nonblocking
80 * socket. Keep the old flags around
84 const struct sockaddr *address;
85 socklen_t address_len;
90 ssize_t result_ssize_t;
98 * @brief Create a new async syscall req
99 * @param[in] mem_ctx The memory context to hang the result off
100 * @param[in] ev The event context to work from
101 * @param[in] type Which syscall will this be
102 * @param[in] pstate Where to put the newly created private_data state
103 * @retval The new request
105 * This is a helper function to prepare a new struct async_req with an
106 * associated struct async_syscall_state. The async_syscall_state will be put
107 * into the async_req as private_data.
110 static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx,
111 struct tevent_context *ev,
112 enum async_syscall_type type,
113 struct async_syscall_state **pstate)
115 struct async_req *result;
116 struct async_syscall_state *state;
118 if (!async_req_setup(mem_ctx, &result, &state,
119 struct async_syscall_state)) {
122 state->syscall_type = type;
124 result->private_data = state;
132 * @brief Create a new async syscall req based on a fd
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] fd The file descriptor we work on
137 * @param[in] fde_flags TEVENT_FD_READ/WRITE -- what are we interested in?
138 * @param[in] fde_cb The callback function for the file descriptor event
139 * @param[in] pstate Where to put the newly created private_data state
140 * @retval The new request
142 * This is a helper function to prepare a new struct async_req with an
143 * associated struct async_syscall_state and an associated file descriptor
147 static struct async_req *async_fde_syscall_new(
149 struct tevent_context *ev,
150 enum async_syscall_type type,
153 void (*fde_cb)(struct tevent_context *ev,
154 struct tevent_fd *fde, uint16_t flags,
156 struct async_syscall_state **pstate)
158 struct async_req *result;
159 struct async_syscall_state *state;
161 result = async_syscall_new(mem_ctx, ev, type, &state);
162 if (result == NULL) {
166 state->fde = tevent_add_fd(ev, state, fd, fde_flags, fde_cb, result);
167 if (state->fde == NULL) {
176 * Retrieve a ssize_t typed result from an async syscall
177 * @param[in] req The syscall that has just finished
178 * @param[out] perrno Where to put the syscall's errno
179 * @retval The return value from the asynchronously called syscall
182 ssize_t async_syscall_result_ssize_t(struct async_req *req, int *perrno)
184 struct async_syscall_state *state = talloc_get_type_abort(
185 req->private_data, struct async_syscall_state);
187 *perrno = state->sys_errno;
188 return state->result.result_ssize_t;
192 * Retrieve a size_t typed result from an async syscall
193 * @param[in] req The syscall that has just finished
194 * @param[out] perrno Where to put the syscall's errno
195 * @retval The return value from the asynchronously called syscall
198 size_t async_syscall_result_size_t(struct async_req *req, int *perrno)
200 struct async_syscall_state *state = talloc_get_type_abort(
201 req->private_data, struct async_syscall_state);
203 *perrno = state->sys_errno;
204 return state->result.result_size_t;
208 * Retrieve a int typed result from an async syscall
209 * @param[in] req The syscall that has just finished
210 * @param[out] perrno Where to put the syscall's errno
211 * @retval The return value from the asynchronously called syscall
214 int async_syscall_result_int(struct async_req *req, int *perrno)
216 struct async_syscall_state *state = talloc_get_type_abort(
217 req->private_data, struct async_syscall_state);
219 *perrno = state->sys_errno;
220 return state->result.result_int;
224 * fde event handler for the "send" syscall
225 * @param[in] ev The event context that sent us here
226 * @param[in] fde The file descriptor event associated with the send
227 * @param[in] flags Can only be TEVENT_FD_WRITE here
228 * @param[in] priv private data, "struct async_req *" in this case
231 static void async_send_callback(struct tevent_context *ev,
232 struct tevent_fd *fde, uint16_t flags,
235 struct async_req *req = talloc_get_type_abort(
236 priv, struct async_req);
237 struct async_syscall_state *state = talloc_get_type_abort(
238 req->private_data, struct async_syscall_state);
239 struct param_send *p = &state->param.param_send;
241 if (state->syscall_type != ASYNC_SYSCALL_SEND) {
242 async_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
246 state->result.result_ssize_t = send(p->fd, p->buffer, p->length,
248 state->sys_errno = errno;
250 TALLOC_FREE(state->fde);
256 * Async version of send(2)
257 * @param[in] mem_ctx The memory context to hang the result off
258 * @param[in] ev The event context to work from
259 * @param[in] fd The socket to send to
260 * @param[in] buffer The buffer to send
261 * @param[in] length How many bytes to send
262 * @param[in] flags flags passed to send(2)
264 * This function is a direct counterpart of send(2)
267 struct async_req *async_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
268 int fd, const void *buffer, size_t length,
271 struct async_req *result;
272 struct async_syscall_state *state;
274 result = async_fde_syscall_new(
275 mem_ctx, ev, ASYNC_SYSCALL_SEND,
276 fd, TEVENT_FD_WRITE, async_send_callback,
278 if (result == NULL) {
282 state->param.param_send.fd = fd;
283 state->param.param_send.buffer = buffer;
284 state->param.param_send.length = length;
285 state->param.param_send.flags = flags;
291 * fde event handler for the "sendall" syscall group
292 * @param[in] ev The event context that sent us here
293 * @param[in] fde The file descriptor event associated with the send
294 * @param[in] flags Can only be TEVENT_FD_WRITE here
295 * @param[in] priv private data, "struct async_req *" in this case
298 static void async_sendall_callback(struct tevent_context *ev,
299 struct tevent_fd *fde, uint16_t flags,
302 struct async_req *req = talloc_get_type_abort(
303 priv, struct async_req);
304 struct async_syscall_state *state = talloc_get_type_abort(
305 req->private_data, struct async_syscall_state);
306 struct param_sendall *p = &state->param.param_sendall;
308 if (state->syscall_type != ASYNC_SYSCALL_SENDALL) {
309 async_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
313 state->result.result_ssize_t = send(p->fd,
314 (const char *)p->buffer + p->sent,
315 p->length - p->sent, p->flags);
316 state->sys_errno = errno;
318 if (state->result.result_ssize_t == -1) {
319 async_req_nterror(req, map_nt_error_from_unix(state->sys_errno));
323 if (state->result.result_ssize_t == 0) {
324 async_req_nterror(req, NT_STATUS_END_OF_FILE);
328 p->sent += state->result.result_ssize_t;
329 if (p->sent > p->length) {
330 async_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
334 if (p->sent == p->length) {
335 TALLOC_FREE(state->fde);
341 * @brief Send all bytes to a socket
342 * @param[in] mem_ctx The memory context to hang the result off
343 * @param[in] ev The event context to work from
344 * @param[in] fd The socket to send to
345 * @param[in] buffer The buffer to send
346 * @param[in] length How many bytes to send
347 * @param[in] flags flags passed to send(2)
349 * async_sendall calls send(2) as long as it is necessary to send all of the
353 struct async_req *sendall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
354 int fd, const void *buffer, size_t length,
357 struct async_req *result;
358 struct async_syscall_state *state;
360 result = async_fde_syscall_new(
361 mem_ctx, ev, ASYNC_SYSCALL_SENDALL,
362 fd, TEVENT_FD_WRITE, async_sendall_callback,
364 if (result == NULL) {
368 state->param.param_sendall.fd = fd;
369 state->param.param_sendall.buffer = buffer;
370 state->param.param_sendall.length = length;
371 state->param.param_sendall.flags = flags;
372 state->param.param_sendall.sent = 0;
377 NTSTATUS sendall_recv(struct async_req *req)
379 return async_req_simple_recv_ntstatus(req);
383 * fde event handler for the "recv" syscall
384 * @param[in] ev The event context that sent us here
385 * @param[in] fde The file descriptor event associated with the recv
386 * @param[in] flags Can only be TEVENT_FD_READ here
387 * @param[in] priv private data, "struct async_req *" in this case
390 static void async_recv_callback(struct tevent_context *ev,
391 struct tevent_fd *fde, uint16_t flags,
394 struct async_req *req = talloc_get_type_abort(
395 priv, struct async_req);
396 struct async_syscall_state *state = talloc_get_type_abort(
397 req->private_data, struct async_syscall_state);
398 struct param_recv *p = &state->param.param_recv;
400 if (state->syscall_type != ASYNC_SYSCALL_RECV) {
401 async_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
405 state->result.result_ssize_t = recv(p->fd, p->buffer, p->length,
407 state->sys_errno = errno;
409 TALLOC_FREE(state->fde);
415 * Async version of recv(2)
416 * @param[in] mem_ctx The memory context to hang the result off
417 * @param[in] ev The event context to work from
418 * @param[in] fd The socket to recv from
419 * @param[in] buffer The buffer to recv into
420 * @param[in] length How many bytes to recv
421 * @param[in] flags flags passed to recv(2)
423 * This function is a direct counterpart of recv(2)
426 struct async_req *async_recv(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
427 int fd, void *buffer, size_t length,
430 struct async_req *result;
431 struct async_syscall_state *state;
433 result = async_fde_syscall_new(
434 mem_ctx, ev, ASYNC_SYSCALL_RECV,
435 fd, TEVENT_FD_READ, async_recv_callback,
438 if (result == NULL) {
442 state->param.param_recv.fd = fd;
443 state->param.param_recv.buffer = buffer;
444 state->param.param_recv.length = length;
445 state->param.param_recv.flags = flags;
451 * fde event handler for the "recvall" syscall group
452 * @param[in] ev The event context that sent us here
453 * @param[in] fde The file descriptor event associated with the recv
454 * @param[in] flags Can only be TEVENT_FD_READ here
455 * @param[in] priv private data, "struct async_req *" in this case
458 static void async_recvall_callback(struct tevent_context *ev,
459 struct tevent_fd *fde, uint16_t flags,
462 struct async_req *req = talloc_get_type_abort(
463 priv, struct async_req);
464 struct async_syscall_state *state = talloc_get_type_abort(
465 req->private_data, struct async_syscall_state);
466 struct param_recvall *p = &state->param.param_recvall;
468 if (state->syscall_type != ASYNC_SYSCALL_RECVALL) {
469 async_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
473 state->result.result_ssize_t = recv(p->fd,
474 (char *)p->buffer + p->received,
475 p->length - p->received, p->flags);
476 state->sys_errno = errno;
478 if (state->result.result_ssize_t == -1) {
479 async_req_nterror(req, map_nt_error_from_unix(state->sys_errno));
483 if (state->result.result_ssize_t == 0) {
484 async_req_nterror(req, NT_STATUS_END_OF_FILE);
488 p->received += state->result.result_ssize_t;
489 if (p->received > p->length) {
490 async_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
494 if (p->received == p->length) {
495 TALLOC_FREE(state->fde);
501 * Receive a specified number of bytes from a socket
502 * @param[in] mem_ctx The memory context to hang the result off
503 * @param[in] ev The event context to work from
504 * @param[in] fd The socket to recv from
505 * @param[in] buffer The buffer to recv into
506 * @param[in] length How many bytes to recv
507 * @param[in] flags flags passed to recv(2)
509 * async_recvall will call recv(2) until "length" bytes are received
512 struct async_req *recvall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
513 int fd, void *buffer, size_t length,
516 struct async_req *result;
517 struct async_syscall_state *state;
519 result = async_fde_syscall_new(
520 mem_ctx, ev, ASYNC_SYSCALL_RECVALL,
521 fd, TEVENT_FD_READ, async_recvall_callback,
523 if (result == NULL) {
527 state->param.param_recvall.fd = fd;
528 state->param.param_recvall.buffer = buffer;
529 state->param.param_recvall.length = length;
530 state->param.param_recvall.flags = flags;
531 state->param.param_recvall.received = 0;
536 NTSTATUS recvall_recv(struct async_req *req)
538 return async_req_simple_recv_ntstatus(req);
541 struct async_connect_state {
548 static void async_connect_connected(struct tevent_context *ev,
549 struct tevent_fd *fde, uint16_t flags,
553 * @brief async version of connect(2)
554 * @param[in] mem_ctx The memory context to hang the result off
555 * @param[in] ev The event context to work from
556 * @param[in] fd The socket to recv from
557 * @param[in] address Where to connect?
558 * @param[in] address_len Length of *address
559 * @retval The async request
561 * This function sets the socket into non-blocking state to be able to call
562 * connect in an async state. This will be reset when the request is finished.
565 struct async_req *async_connect_send(TALLOC_CTX *mem_ctx,
566 struct tevent_context *ev,
567 int fd, const struct sockaddr *address,
568 socklen_t address_len)
570 struct async_req *result;
571 struct async_connect_state *state;
572 struct tevent_fd *fde;
575 if (!async_req_setup(mem_ctx, &result, &state,
576 struct async_connect_state)) {
581 * We have to set the socket to nonblocking for async connect(2). Keep
582 * the old sockflags around.
586 state->sys_errno = 0;
588 state->old_sockflags = fcntl(fd, F_GETFL, 0);
589 if (state->old_sockflags == -1) {
593 set_blocking(fd, false);
595 state->result = connect(fd, address, address_len);
596 if (state->result == 0) {
597 state->sys_errno = 0;
598 status = NT_STATUS_OK;
603 * A number of error messages show that something good is progressing
604 * and that we have to wait for readability.
606 * If none of them are present, bail out.
609 if (!(errno == EINPROGRESS || errno == EALREADY ||
613 errno == EAGAIN || errno == EINTR)) {
617 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
618 async_connect_connected, result);
620 status = NT_STATUS_NO_MEMORY;
626 state->sys_errno = errno;
627 status = map_nt_error_from_unix(state->sys_errno);
629 fcntl(fd, F_SETFL, state->old_sockflags);
630 if (!async_post_ntstatus(result, ev, status)) {
640 * fde event handler for connect(2)
641 * @param[in] ev The event context that sent us here
642 * @param[in] fde The file descriptor event associated with the connect
643 * @param[in] flags Indicate read/writeability of the socket
644 * @param[in] priv private data, "struct async_req *" in this case
647 static void async_connect_connected(struct tevent_context *ev,
648 struct tevent_fd *fde, uint16_t flags,
651 struct async_req *req = talloc_get_type_abort(
652 priv, struct async_req);
653 struct async_connect_state *state = talloc_get_type_abort(
654 req->private_data, struct async_connect_state);
659 * Stevens, Network Programming says that if there's a
660 * successful connect, the socket is only writable. Upon an
661 * error, it's both readable and writable.
663 if ((flags & (TEVENT_FD_READ|TEVENT_FD_WRITE))
664 == (TEVENT_FD_READ|TEVENT_FD_WRITE)) {
666 socklen_t err_len = sizeof(sockerr);
668 if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
669 (void *)&sockerr, &err_len) == 0) {
673 state->sys_errno = errno;
675 DEBUG(10, ("connect returned %s\n", strerror(errno)));
677 fcntl(state->fd, F_SETFL, state->old_sockflags);
678 async_req_nterror(req, map_nt_error_from_unix(state->sys_errno));
682 state->sys_errno = 0;
686 NTSTATUS async_connect_recv(struct async_req *req, int *perrno)
688 struct async_connect_state *state = talloc_get_type_abort(
689 req->private_data, struct async_connect_state);
692 fcntl(state->fd, F_SETFL, state->old_sockflags);
694 *perrno = state->sys_errno;
696 if (async_req_is_nterror(req, &status)) {
699 if (state->sys_errno == 0) {
702 return map_nt_error_from_unix(state->sys_errno);