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;
78 req = tevent_req_create(mem_ctx, &state, struct async_connect_state);
84 * We have to set the socket to nonblocking for async connect(2). Keep
85 * the old sockflags around.
89 state->before_connect = before_connect;
90 state->after_connect = after_connect;
91 state->private_data = private_data;
93 state->old_sockflags = fcntl(fd, F_GETFL, 0);
94 if (state->old_sockflags == -1) {
95 tevent_req_error(req, errno);
96 return tevent_req_post(req, ev);
99 tevent_req_set_cleanup_fn(req, async_connect_cleanup);
101 state->address_len = address_len;
102 if (address_len > sizeof(state->address)) {
103 tevent_req_error(req, EINVAL);
104 return tevent_req_post(req, ev);
106 memcpy(&state->address, address, address_len);
108 set_blocking(fd, false);
110 if (state->before_connect != NULL) {
111 state->before_connect(state->private_data);
114 state->result = connect(fd, address, address_len);
116 if (state->after_connect != NULL) {
117 state->after_connect(state->private_data);
120 if (state->result == 0) {
121 tevent_req_done(req);
122 return tevent_req_post(req, ev);
126 * A number of error messages show that something good is progressing
127 * and that we have to wait for readability.
129 * If none of them are present, bail out.
132 if (!(errno == EINPROGRESS || errno == EALREADY ||
136 errno == EAGAIN || errno == EINTR)) {
137 tevent_req_error(req, errno);
138 return tevent_req_post(req, ev);
141 state->fde = tevent_add_fd(ev, state, fd,
142 TEVENT_FD_READ | TEVENT_FD_WRITE,
143 async_connect_connected, req);
144 if (state->fde == NULL) {
145 tevent_req_error(req, ENOMEM);
146 return tevent_req_post(req, ev);
151 static void async_connect_cleanup(struct tevent_req *req,
152 enum tevent_req_state req_state)
154 struct async_connect_state *state =
155 tevent_req_data(req, struct async_connect_state);
157 TALLOC_FREE(state->fde);
158 if (state->fd != -1) {
159 fcntl(state->fd, F_SETFL, state->old_sockflags);
165 * fde event handler for connect(2)
166 * @param[in] ev The event context that sent us here
167 * @param[in] fde The file descriptor event associated with the connect
168 * @param[in] flags Indicate read/writeability of the socket
169 * @param[in] priv private data, "struct async_req *" in this case
172 static void async_connect_connected(struct tevent_context *ev,
173 struct tevent_fd *fde, uint16_t flags,
176 struct tevent_req *req = talloc_get_type_abort(
177 priv, struct tevent_req);
178 struct async_connect_state *state =
179 tevent_req_data(req, struct async_connect_state);
182 if (state->before_connect != NULL) {
183 state->before_connect(state->private_data);
186 ret = connect(state->fd, (struct sockaddr *)(void *)&state->address,
189 if (state->after_connect != NULL) {
190 state->after_connect(state->private_data);
194 tevent_req_done(req);
197 if (errno == EINPROGRESS) {
198 /* Try again later, leave the fde around */
201 tevent_req_error(req, errno);
205 int async_connect_recv(struct tevent_req *req, int *perrno)
207 int err = tevent_req_simple_recv_unix(req);
217 struct writev_state {
218 struct tevent_context *ev;
220 struct tevent_fd *fde;
225 bool err_on_readability;
228 static void writev_cleanup(struct tevent_req *req,
229 enum tevent_req_state req_state);
230 static void writev_trigger(struct tevent_req *req, void *private_data);
231 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
232 uint16_t flags, void *private_data);
234 struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
235 struct tevent_queue *queue, int fd,
236 bool err_on_readability,
237 struct iovec *iov, int count)
239 struct tevent_req *req;
240 struct writev_state *state;
242 req = tevent_req_create(mem_ctx, &state, struct writev_state);
248 state->total_size = 0;
249 state->count = count;
250 state->iov = (struct iovec *)talloc_memdup(
251 state, iov, sizeof(struct iovec) * count);
252 if (tevent_req_nomem(state->iov, req)) {
253 return tevent_req_post(req, ev);
255 state->flags = TEVENT_FD_WRITE|TEVENT_FD_READ;
256 state->err_on_readability = err_on_readability;
258 tevent_req_set_cleanup_fn(req, writev_cleanup);
261 state->fde = tevent_add_fd(state->ev, state, state->fd,
262 state->flags, writev_handler, req);
263 if (tevent_req_nomem(state->fde, req)) {
264 return tevent_req_post(req, ev);
269 if (!tevent_queue_add(queue, ev, req, writev_trigger, NULL)) {
270 tevent_req_nomem(NULL, req);
271 return tevent_req_post(req, ev);
276 static void writev_cleanup(struct tevent_req *req,
277 enum tevent_req_state req_state)
279 struct writev_state *state = tevent_req_data(req, struct writev_state);
281 TALLOC_FREE(state->fde);
284 static void writev_trigger(struct tevent_req *req, void *private_data)
286 struct writev_state *state = tevent_req_data(req, struct writev_state);
288 state->fde = tevent_add_fd(state->ev, state, state->fd, state->flags,
289 writev_handler, req);
290 if (tevent_req_nomem(state->fde, req)) {
295 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
296 uint16_t flags, void *private_data)
298 struct tevent_req *req = talloc_get_type_abort(
299 private_data, struct tevent_req);
300 struct writev_state *state =
301 tevent_req_data(req, struct writev_state);
305 if ((state->flags & TEVENT_FD_READ) && (flags & TEVENT_FD_READ)) {
308 if (state->err_on_readability) {
309 /* Readable and the caller wants an error on read. */
310 tevent_req_error(req, EPIPE);
314 /* Might be an error. Check if there are bytes to read */
315 ret = ioctl(state->fd, FIONREAD, &value);
316 /* FIXME - should we also check
317 for ret == 0 and value == 0 here ? */
319 /* There's an error. */
320 tevent_req_error(req, EPIPE);
323 /* A request for TEVENT_FD_READ will succeed from now and
324 forevermore until the bytes are read so if there was
325 an error we'll wait until we do read, then get it in
326 the read callback function. Until then, remove TEVENT_FD_READ
327 from the flags we're waiting for. */
328 state->flags &= ~TEVENT_FD_READ;
329 TEVENT_FD_NOT_READABLE(fde);
331 /* If not writable, we're done. */
332 if (!(flags & TEVENT_FD_WRITE)) {
337 written = writev(state->fd, state->iov, state->count);
338 if ((written == -1) && (errno == EINTR)) {
343 tevent_req_error(req, errno);
347 tevent_req_error(req, EPIPE);
350 state->total_size += written;
352 ok = iov_advance(&state->iov, &state->count, written);
354 tevent_req_error(req, EIO);
358 if (state->count == 0) {
359 tevent_req_done(req);
364 ssize_t writev_recv(struct tevent_req *req, int *perrno)
366 struct writev_state *state =
367 tevent_req_data(req, struct writev_state);
370 if (tevent_req_is_unix_error(req, perrno)) {
371 tevent_req_received(req);
374 ret = state->total_size;
375 tevent_req_received(req);
379 struct read_packet_state {
383 ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
387 static void read_packet_handler(struct tevent_context *ev,
388 struct tevent_fd *fde,
389 uint16_t flags, void *private_data);
391 struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
392 struct tevent_context *ev,
393 int fd, size_t initial,
394 ssize_t (*more)(uint8_t *buf,
399 struct tevent_req *result;
400 struct read_packet_state *state;
401 struct tevent_fd *fde;
403 result = tevent_req_create(mem_ctx, &state, struct read_packet_state);
404 if (result == NULL) {
410 state->private_data = private_data;
412 state->buf = talloc_array(state, uint8_t, initial);
413 if (state->buf == NULL) {
417 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler,
428 static void read_packet_handler(struct tevent_context *ev,
429 struct tevent_fd *fde,
430 uint16_t flags, void *private_data)
432 struct tevent_req *req = talloc_get_type_abort(
433 private_data, struct tevent_req);
434 struct read_packet_state *state =
435 tevent_req_data(req, struct read_packet_state);
436 size_t total = talloc_get_size(state->buf);
440 nread = recv(state->fd, state->buf+state->nread, total-state->nread,
442 if ((nread == -1) && (errno == ENOTSOCK)) {
443 nread = read(state->fd, state->buf+state->nread,
446 if ((nread == -1) && (errno == EINTR)) {
451 tevent_req_error(req, errno);
455 tevent_req_error(req, EPIPE);
459 state->nread += nread;
460 if (state->nread < total) {
461 /* Come back later */
466 * We got what was initially requested. See if "more" asks for -- more.
468 if (state->more == NULL) {
469 /* Nobody to ask, this is a async read_data */
470 tevent_req_done(req);
474 more = state->more(state->buf, total, state->private_data);
476 /* We got an invalid packet, tell the caller */
477 tevent_req_error(req, EIO);
481 /* We're done, full packet received */
482 tevent_req_done(req);
486 if (total + more < total) {
487 tevent_req_error(req, EMSGSIZE);
491 tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
492 if (tevent_req_nomem(tmp, req)) {
498 ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
499 uint8_t **pbuf, int *perrno)
501 struct read_packet_state *state =
502 tevent_req_data(req, struct read_packet_state);
504 if (tevent_req_is_unix_error(req, perrno)) {
507 *pbuf = talloc_move(mem_ctx, &state->buf);
508 return talloc_get_size(*pbuf);
511 struct wait_for_read_state {
512 struct tevent_req *req;
513 struct tevent_fd *fde;
516 static void wait_for_read_done(struct tevent_context *ev,
517 struct tevent_fd *fde,
521 struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
522 struct tevent_context *ev,
525 struct tevent_req *req;
526 struct wait_for_read_state *state;
528 req = tevent_req_create(mem_ctx, &state, struct wait_for_read_state);
533 state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
534 wait_for_read_done, state);
535 if (tevent_req_nomem(state->fde, req)) {
536 return tevent_req_post(req, ev);
541 static void wait_for_read_done(struct tevent_context *ev,
542 struct tevent_fd *fde,
546 struct wait_for_read_state *state = talloc_get_type_abort(
547 private_data, struct wait_for_read_state);
549 if (flags & TEVENT_FD_READ) {
550 TALLOC_FREE(state->fde);
551 tevent_req_done(state->req);
555 bool wait_for_read_recv(struct tevent_req *req, int *perr)
559 if (tevent_req_is_unix_error(req, &err)) {