2 Unix SMB/CIFS implementation.
4 Copyright (C) Volker Lendecke 2008
6 ** NOTE! The following LGPL license applies to the async_sock
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Library General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "system/network.h"
26 #include "system/filesys.h"
29 #include "lib/async_req/async_sock.h"
30 #include "lib/util/iov_buf.h"
32 /* Note: lib/util/ is currently GPL */
33 #include "lib/util/tevent_unix.h"
34 #include "lib/util/samba_util.h"
36 struct async_connect_state {
38 struct tevent_fd *fde;
41 socklen_t address_len;
42 struct sockaddr_storage address;
44 void (*before_connect)(void *private_data);
45 void (*after_connect)(void *private_data);
49 static void async_connect_cleanup(struct tevent_req *req,
50 enum tevent_req_state req_state);
51 static void async_connect_connected(struct tevent_context *ev,
52 struct tevent_fd *fde, uint16_t flags,
56 * @brief async version of connect(2)
57 * @param[in] mem_ctx The memory context to hang the result off
58 * @param[in] ev The event context to work from
59 * @param[in] fd The socket to recv from
60 * @param[in] address Where to connect?
61 * @param[in] address_len Length of *address
62 * @retval The async request
64 * This function sets the socket into non-blocking state to be able to call
65 * connect in an async state. This will be reset when the request is finished.
68 struct tevent_req *async_connect_send(
69 TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd,
70 const struct sockaddr *address, socklen_t address_len,
71 void (*before_connect)(void *private_data),
72 void (*after_connect)(void *private_data),
75 struct tevent_req *req;
76 struct async_connect_state *state;
79 req = tevent_req_create(mem_ctx, &state, struct async_connect_state);
85 * We have to set the socket to nonblocking for async connect(2). Keep
86 * the old sockflags around.
90 state->before_connect = before_connect;
91 state->after_connect = after_connect;
92 state->private_data = private_data;
94 state->old_sockflags = fcntl(fd, F_GETFL, 0);
95 if (state->old_sockflags == -1) {
96 tevent_req_error(req, errno);
97 return tevent_req_post(req, ev);
100 tevent_req_set_cleanup_fn(req, async_connect_cleanup);
102 state->address_len = address_len;
103 if (address_len > sizeof(state->address)) {
104 tevent_req_error(req, EINVAL);
105 return tevent_req_post(req, ev);
107 memcpy(&state->address, address, address_len);
109 ret = set_blocking(fd, false);
111 tevent_req_error(req, errno);
112 return tevent_req_post(req, ev);
115 if (state->before_connect != NULL) {
116 state->before_connect(state->private_data);
119 state->result = connect(fd, address, address_len);
121 if (state->after_connect != NULL) {
122 state->after_connect(state->private_data);
125 if (state->result == 0) {
126 tevent_req_done(req);
127 return tevent_req_post(req, ev);
131 * The only errno indicating that an initial connect is still
132 * in flight is EINPROGRESS.
134 * This allows callers like open_socket_out_send() to reuse
135 * fds and call us with an fd for which the connect is still
136 * in flight. The proper thing to do for callers would be
137 * closing the fd and starting from scratch with a fresh
141 if (errno != EINPROGRESS) {
142 tevent_req_error(req, errno);
143 return tevent_req_post(req, ev);
147 * Note for historic reasons TEVENT_FD_WRITE is not enough
148 * to get notified for POLLERR or EPOLLHUP even if they
149 * come together with POLLOUT. That means we need to
150 * use TEVENT_FD_READ in addition until we have
153 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ|TEVENT_FD_WRITE,
154 async_connect_connected, req);
155 if (state->fde == NULL) {
156 tevent_req_error(req, ENOMEM);
157 return tevent_req_post(req, ev);
162 static void async_connect_cleanup(struct tevent_req *req,
163 enum tevent_req_state req_state)
165 struct async_connect_state *state =
166 tevent_req_data(req, struct async_connect_state);
168 TALLOC_FREE(state->fde);
169 if (state->fd != -1) {
172 ret = fcntl(state->fd, F_SETFL, state->old_sockflags);
182 * fde event handler for connect(2)
183 * @param[in] ev The event context that sent us here
184 * @param[in] fde The file descriptor event associated with the connect
185 * @param[in] flags Indicate read/writeability of the socket
186 * @param[in] priv private data, "struct async_req *" in this case
189 static void async_connect_connected(struct tevent_context *ev,
190 struct tevent_fd *fde, uint16_t flags,
193 struct tevent_req *req = talloc_get_type_abort(
194 priv, struct tevent_req);
195 struct async_connect_state *state =
196 tevent_req_data(req, struct async_connect_state);
198 int socket_error = 0;
199 socklen_t slen = sizeof(socket_error);
201 ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
202 &socket_error, &slen);
206 * According to Stevens this is the Solaris behaviour
207 * in case the connection encountered an error:
208 * getsockopt() fails, error is in errno
210 tevent_req_error(req, errno);
214 if (socket_error != 0) {
216 * Berkeley derived implementations (including) Linux
217 * return the pending error via socket_error.
219 tevent_req_error(req, socket_error);
223 tevent_req_done(req);
227 int async_connect_recv(struct tevent_req *req, int *perrno)
229 int err = tevent_req_simple_recv_unix(req);
239 struct writev_state {
240 struct tevent_context *ev;
241 struct tevent_queue_entry *queue_entry;
243 struct tevent_fd *fde;
248 bool err_on_readability;
251 static void writev_cleanup(struct tevent_req *req,
252 enum tevent_req_state req_state);
253 static bool writev_cancel(struct tevent_req *req);
254 static void writev_trigger(struct tevent_req *req, void *private_data);
255 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
256 uint16_t flags, void *private_data);
258 struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
259 struct tevent_queue *queue, int fd,
260 bool err_on_readability,
261 struct iovec *iov, int count)
263 struct tevent_req *req;
264 struct writev_state *state;
266 req = tevent_req_create(mem_ctx, &state, struct writev_state);
272 state->total_size = 0;
273 state->count = count;
274 state->iov = (struct iovec *)talloc_memdup(
275 state, iov, sizeof(struct iovec) * count);
276 if (tevent_req_nomem(state->iov, req)) {
277 return tevent_req_post(req, ev);
279 state->flags = TEVENT_FD_WRITE|TEVENT_FD_READ;
280 state->err_on_readability = err_on_readability;
282 tevent_req_set_cleanup_fn(req, writev_cleanup);
283 tevent_req_set_cancel_fn(req, writev_cancel);
286 state->fde = tevent_add_fd(state->ev, state, state->fd,
287 state->flags, writev_handler, req);
288 if (tevent_req_nomem(state->fde, req)) {
289 return tevent_req_post(req, ev);
294 state->queue_entry = tevent_queue_add_optimize_empty(
295 queue, ev, req, writev_trigger, NULL);
296 if (tevent_req_nomem(state->queue_entry, req)) {
297 return tevent_req_post(req, ev);
302 static void writev_cleanup(struct tevent_req *req,
303 enum tevent_req_state req_state)
305 struct writev_state *state = tevent_req_data(req, struct writev_state);
307 TALLOC_FREE(state->queue_entry);
308 TALLOC_FREE(state->fde);
311 static bool writev_cancel(struct tevent_req *req)
313 struct writev_state *state = tevent_req_data(req, struct writev_state);
315 if (state->total_size > 0) {
317 * We've already started to write :-(
322 TALLOC_FREE(state->queue_entry);
323 TALLOC_FREE(state->fde);
325 tevent_req_defer_callback(req, state->ev);
326 tevent_req_error(req, ECANCELED);
330 static void writev_trigger(struct tevent_req *req, void *private_data)
332 struct writev_state *state = tevent_req_data(req, struct writev_state);
334 state->queue_entry = NULL;
336 state->fde = tevent_add_fd(state->ev, state, state->fd, state->flags,
337 writev_handler, req);
338 if (tevent_req_nomem(state->fde, req)) {
343 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
344 uint16_t flags, void *private_data)
346 struct tevent_req *req = talloc_get_type_abort(
347 private_data, struct tevent_req);
348 struct writev_state *state =
349 tevent_req_data(req, struct writev_state);
353 if ((state->flags & TEVENT_FD_READ) && (flags & TEVENT_FD_READ)) {
356 if (state->err_on_readability) {
357 /* Readable and the caller wants an error on read. */
358 tevent_req_error(req, EPIPE);
362 /* Might be an error. Check if there are bytes to read */
363 ret = ioctl(state->fd, FIONREAD, &value);
364 /* FIXME - should we also check
365 for ret == 0 and value == 0 here ? */
367 /* There's an error. */
368 tevent_req_error(req, EPIPE);
371 /* A request for TEVENT_FD_READ will succeed from now and
372 forevermore until the bytes are read so if there was
373 an error we'll wait until we do read, then get it in
374 the read callback function. Until then, remove TEVENT_FD_READ
375 from the flags we're waiting for. */
376 state->flags &= ~TEVENT_FD_READ;
377 TEVENT_FD_NOT_READABLE(fde);
379 /* If not writable, we're done. */
380 if (!(flags & TEVENT_FD_WRITE)) {
385 written = writev(state->fd, state->iov, state->count);
386 if ((written == -1) && (errno == EINTR)) {
391 tevent_req_error(req, errno);
395 tevent_req_error(req, EPIPE);
398 state->total_size += written;
400 ok = iov_advance(&state->iov, &state->count, written);
402 tevent_req_error(req, EIO);
406 if (state->count == 0) {
407 tevent_req_done(req);
412 ssize_t writev_recv(struct tevent_req *req, int *perrno)
414 struct writev_state *state =
415 tevent_req_data(req, struct writev_state);
418 if (tevent_req_is_unix_error(req, perrno)) {
419 tevent_req_received(req);
422 ret = state->total_size;
423 tevent_req_received(req);
427 struct read_packet_state {
429 struct tevent_fd *fde;
432 ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
436 static void read_packet_cleanup(struct tevent_req *req,
437 enum tevent_req_state req_state);
438 static void read_packet_handler(struct tevent_context *ev,
439 struct tevent_fd *fde,
440 uint16_t flags, void *private_data);
442 struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
443 struct tevent_context *ev,
444 int fd, size_t initial,
445 ssize_t (*more)(uint8_t *buf,
450 struct tevent_req *req;
451 struct read_packet_state *state;
453 req = tevent_req_create(mem_ctx, &state, struct read_packet_state);
460 state->private_data = private_data;
462 tevent_req_set_cleanup_fn(req, read_packet_cleanup);
464 state->buf = talloc_array(state, uint8_t, initial);
465 if (tevent_req_nomem(state->buf, req)) {
466 return tevent_req_post(req, ev);
469 state->fde = tevent_add_fd(ev, state, fd,
470 TEVENT_FD_READ, read_packet_handler,
472 if (tevent_req_nomem(state->fde, req)) {
473 return tevent_req_post(req, ev);
478 static void read_packet_cleanup(struct tevent_req *req,
479 enum tevent_req_state req_state)
481 struct read_packet_state *state =
482 tevent_req_data(req, struct read_packet_state);
484 TALLOC_FREE(state->fde);
487 static void read_packet_handler(struct tevent_context *ev,
488 struct tevent_fd *fde,
489 uint16_t flags, void *private_data)
491 struct tevent_req *req = talloc_get_type_abort(
492 private_data, struct tevent_req);
493 struct read_packet_state *state =
494 tevent_req_data(req, struct read_packet_state);
495 size_t total = talloc_get_size(state->buf);
499 nread = recv(state->fd, state->buf+state->nread, total-state->nread,
501 if ((nread == -1) && (errno == ENOTSOCK)) {
502 nread = read(state->fd, state->buf+state->nread,
505 if ((nread == -1) && (errno == EINTR)) {
510 tevent_req_error(req, errno);
514 tevent_req_error(req, EPIPE);
518 state->nread += nread;
519 if (state->nread < total) {
520 /* Come back later */
525 * We got what was initially requested. See if "more" asks for -- more.
527 if (state->more == NULL) {
528 /* Nobody to ask, this is a async read_data */
529 tevent_req_done(req);
533 more = state->more(state->buf, total, state->private_data);
535 /* We got an invalid packet, tell the caller */
536 tevent_req_error(req, EIO);
540 /* We're done, full packet received */
541 tevent_req_done(req);
545 if (total + more < total) {
546 tevent_req_error(req, EMSGSIZE);
550 tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
551 if (tevent_req_nomem(tmp, req)) {
557 ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
558 uint8_t **pbuf, int *perrno)
560 struct read_packet_state *state =
561 tevent_req_data(req, struct read_packet_state);
563 if (tevent_req_is_unix_error(req, perrno)) {
564 tevent_req_received(req);
567 *pbuf = talloc_move(mem_ctx, &state->buf);
568 tevent_req_received(req);
569 return talloc_get_size(*pbuf);
572 struct wait_for_read_state {
573 struct tevent_fd *fde;
578 static void wait_for_read_cleanup(struct tevent_req *req,
579 enum tevent_req_state req_state);
580 static void wait_for_read_done(struct tevent_context *ev,
581 struct tevent_fd *fde,
585 struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
586 struct tevent_context *ev, int fd,
589 struct tevent_req *req;
590 struct wait_for_read_state *state;
592 req = tevent_req_create(mem_ctx, &state, struct wait_for_read_state);
597 tevent_req_set_cleanup_fn(req, wait_for_read_cleanup);
599 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
600 wait_for_read_done, req);
601 if (tevent_req_nomem(state->fde, req)) {
602 return tevent_req_post(req, ev);
606 state->check_errors = check_errors;
610 static void wait_for_read_cleanup(struct tevent_req *req,
611 enum tevent_req_state req_state)
613 struct wait_for_read_state *state =
614 tevent_req_data(req, struct wait_for_read_state);
616 TALLOC_FREE(state->fde);
619 static void wait_for_read_done(struct tevent_context *ev,
620 struct tevent_fd *fde,
624 struct tevent_req *req = talloc_get_type_abort(
625 private_data, struct tevent_req);
626 struct wait_for_read_state *state =
627 tevent_req_data(req, struct wait_for_read_state);
631 if ((flags & TEVENT_FD_READ) == 0) {
635 if (!state->check_errors) {
636 tevent_req_done(req);
640 nread = recv(state->fd, &c, 1, MSG_PEEK);
643 tevent_req_error(req, EPIPE);
647 if ((nread == -1) && (errno == EINTR)) {
648 /* come back later */
652 if ((nread == -1) && (errno == ENOTSOCK)) {
653 /* Ignore this specific error on pipes */
654 tevent_req_done(req);
659 tevent_req_error(req, errno);
663 tevent_req_done(req);
666 bool wait_for_read_recv(struct tevent_req *req, int *perr)
668 int err = tevent_req_simple_recv_unix(req);
678 struct accept_state {
679 struct tevent_fd *fde;
682 struct sockaddr_storage addr;
686 static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
687 uint16_t flags, void *private_data);
689 struct tevent_req *accept_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
692 struct tevent_req *req;
693 struct accept_state *state;
695 req = tevent_req_create(mem_ctx, &state, struct accept_state);
700 state->listen_sock = listen_sock;
702 state->fde = tevent_add_fd(ev, state, listen_sock, TEVENT_FD_READ,
703 accept_handler, req);
704 if (tevent_req_nomem(state->fde, req)) {
705 return tevent_req_post(req, ev);
710 static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
711 uint16_t flags, void *private_data)
713 struct tevent_req *req = talloc_get_type_abort(
714 private_data, struct tevent_req);
715 struct accept_state *state = tevent_req_data(req, struct accept_state);
718 TALLOC_FREE(state->fde);
720 if ((flags & TEVENT_FD_READ) == 0) {
721 tevent_req_error(req, EIO);
724 state->addrlen = sizeof(state->addr);
726 ret = accept(state->listen_sock, (struct sockaddr *)&state->addr,
728 if ((ret == -1) && (errno == EINTR)) {
733 tevent_req_error(req, errno);
736 smb_set_close_on_exec(ret);
738 tevent_req_done(req);
741 int accept_recv(struct tevent_req *req, struct sockaddr_storage *paddr,
742 socklen_t *paddrlen, int *perr)
744 struct accept_state *state = tevent_req_data(req, struct accept_state);
747 if (tevent_req_is_unix_error(req, &err)) {
754 memcpy(paddr, &state->addr, state->addrlen);
756 if (paddrlen != NULL) {
757 *paddrlen = state->addrlen;