WHATSNEW: Start release notes for Samba 3.6.4.
[Samba.git] / lib / async_req / async_sock.c
blobbb8518f94856ed57ab722894e0311c13f27a060a
1 /*
2 Unix SMB/CIFS implementation.
3 async socket syscalls
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
8 ** under the LGPL
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/>.
24 #include "replace.h"
25 #include "system/network.h"
26 #include "system/filesys.h"
27 #include <talloc.h>
28 #include <tevent.h>
29 #include "lib/async_req/async_sock.h"
31 /* Note: lib/util/ is currently GPL */
32 #include "lib/util/tevent_unix.h"
33 #include "lib/util/util.h"
35 #ifndef TALLOC_FREE
36 #define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
37 #endif
39 struct sendto_state {
40 int fd;
41 const void *buf;
42 size_t len;
43 int flags;
44 const struct sockaddr_storage *addr;
45 socklen_t addr_len;
46 ssize_t sent;
49 static void sendto_handler(struct tevent_context *ev,
50 struct tevent_fd *fde,
51 uint16_t flags, void *private_data);
53 struct tevent_req *sendto_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
54 int fd, const void *buf, size_t len, int flags,
55 const struct sockaddr_storage *addr)
57 struct tevent_req *result;
58 struct sendto_state *state;
59 struct tevent_fd *fde;
61 result = tevent_req_create(mem_ctx, &state, struct sendto_state);
62 if (result == NULL) {
63 return result;
65 state->fd = fd;
66 state->buf = buf;
67 state->len = len;
68 state->flags = flags;
69 state->addr = addr;
71 switch (addr->ss_family) {
72 case AF_INET:
73 state->addr_len = sizeof(struct sockaddr_in);
74 break;
75 #if defined(HAVE_IPV6)
76 case AF_INET6:
77 state->addr_len = sizeof(struct sockaddr_in6);
78 break;
79 #endif
80 case AF_UNIX:
81 state->addr_len = sizeof(struct sockaddr_un);
82 break;
83 default:
84 state->addr_len = sizeof(struct sockaddr_storage);
85 break;
88 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, sendto_handler,
89 result);
90 if (fde == NULL) {
91 TALLOC_FREE(result);
92 return NULL;
94 return result;
97 static void sendto_handler(struct tevent_context *ev,
98 struct tevent_fd *fde,
99 uint16_t flags, void *private_data)
101 struct tevent_req *req = talloc_get_type_abort(
102 private_data, struct tevent_req);
103 struct sendto_state *state =
104 tevent_req_data(req, struct sendto_state);
106 state->sent = sendto(state->fd, state->buf, state->len, state->flags,
107 (struct sockaddr *)state->addr, state->addr_len);
108 if ((state->sent == -1) && (errno == EINTR)) {
109 /* retry */
110 return;
112 if (state->sent == -1) {
113 tevent_req_error(req, errno);
114 return;
116 tevent_req_done(req);
119 ssize_t sendto_recv(struct tevent_req *req, int *perrno)
121 struct sendto_state *state =
122 tevent_req_data(req, struct sendto_state);
124 if (tevent_req_is_unix_error(req, perrno)) {
125 return -1;
127 return state->sent;
130 struct recvfrom_state {
131 int fd;
132 void *buf;
133 size_t len;
134 int flags;
135 struct sockaddr_storage *addr;
136 socklen_t *addr_len;
137 ssize_t received;
140 static void recvfrom_handler(struct tevent_context *ev,
141 struct tevent_fd *fde,
142 uint16_t flags, void *private_data);
144 struct tevent_req *recvfrom_send(TALLOC_CTX *mem_ctx,
145 struct tevent_context *ev,
146 int fd, void *buf, size_t len, int flags,
147 struct sockaddr_storage *addr,
148 socklen_t *addr_len)
150 struct tevent_req *result;
151 struct recvfrom_state *state;
152 struct tevent_fd *fde;
154 result = tevent_req_create(mem_ctx, &state, struct recvfrom_state);
155 if (result == NULL) {
156 return result;
158 state->fd = fd;
159 state->buf = buf;
160 state->len = len;
161 state->flags = flags;
162 state->addr = addr;
163 state->addr_len = addr_len;
165 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, recvfrom_handler,
166 result);
167 if (fde == NULL) {
168 TALLOC_FREE(result);
169 return NULL;
171 return result;
174 static void recvfrom_handler(struct tevent_context *ev,
175 struct tevent_fd *fde,
176 uint16_t flags, void *private_data)
178 struct tevent_req *req = talloc_get_type_abort(
179 private_data, struct tevent_req);
180 struct recvfrom_state *state =
181 tevent_req_data(req, struct recvfrom_state);
183 state->received = recvfrom(state->fd, state->buf, state->len,
184 state->flags, (struct sockaddr *)state->addr,
185 state->addr_len);
186 if ((state->received == -1) && (errno == EINTR)) {
187 /* retry */
188 return;
190 if (state->received == 0) {
191 tevent_req_error(req, EPIPE);
192 return;
194 if (state->received == -1) {
195 tevent_req_error(req, errno);
196 return;
198 tevent_req_done(req);
201 ssize_t recvfrom_recv(struct tevent_req *req, int *perrno)
203 struct recvfrom_state *state =
204 tevent_req_data(req, struct recvfrom_state);
206 if (tevent_req_is_unix_error(req, perrno)) {
207 return -1;
209 return state->received;
212 struct async_connect_state {
213 int fd;
214 int result;
215 int sys_errno;
216 long old_sockflags;
217 socklen_t address_len;
218 struct sockaddr_storage address;
221 static void async_connect_connected(struct tevent_context *ev,
222 struct tevent_fd *fde, uint16_t flags,
223 void *priv);
226 * @brief async version of connect(2)
227 * @param[in] mem_ctx The memory context to hang the result off
228 * @param[in] ev The event context to work from
229 * @param[in] fd The socket to recv from
230 * @param[in] address Where to connect?
231 * @param[in] address_len Length of *address
232 * @retval The async request
234 * This function sets the socket into non-blocking state to be able to call
235 * connect in an async state. This will be reset when the request is finished.
238 struct tevent_req *async_connect_send(TALLOC_CTX *mem_ctx,
239 struct tevent_context *ev,
240 int fd, const struct sockaddr *address,
241 socklen_t address_len)
243 struct tevent_req *result;
244 struct async_connect_state *state;
245 struct tevent_fd *fde;
247 result = tevent_req_create(
248 mem_ctx, &state, struct async_connect_state);
249 if (result == NULL) {
250 return NULL;
254 * We have to set the socket to nonblocking for async connect(2). Keep
255 * the old sockflags around.
258 state->fd = fd;
259 state->sys_errno = 0;
261 state->old_sockflags = fcntl(fd, F_GETFL, 0);
262 if (state->old_sockflags == -1) {
263 goto post_errno;
266 state->address_len = address_len;
267 if (address_len > sizeof(state->address)) {
268 errno = EINVAL;
269 goto post_errno;
271 memcpy(&state->address, address, address_len);
273 set_blocking(fd, false);
275 state->result = connect(fd, address, address_len);
276 if (state->result == 0) {
277 tevent_req_done(result);
278 goto done;
282 * A number of error messages show that something good is progressing
283 * and that we have to wait for readability.
285 * If none of them are present, bail out.
288 if (!(errno == EINPROGRESS || errno == EALREADY ||
289 #ifdef EISCONN
290 errno == EISCONN ||
291 #endif
292 errno == EAGAIN || errno == EINTR)) {
293 state->sys_errno = errno;
294 goto post_errno;
297 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ | TEVENT_FD_WRITE,
298 async_connect_connected, result);
299 if (fde == NULL) {
300 state->sys_errno = ENOMEM;
301 goto post_errno;
303 return result;
305 post_errno:
306 tevent_req_error(result, state->sys_errno);
307 done:
308 fcntl(fd, F_SETFL, state->old_sockflags);
309 return tevent_req_post(result, ev);
313 * fde event handler for connect(2)
314 * @param[in] ev The event context that sent us here
315 * @param[in] fde The file descriptor event associated with the connect
316 * @param[in] flags Indicate read/writeability of the socket
317 * @param[in] priv private data, "struct async_req *" in this case
320 static void async_connect_connected(struct tevent_context *ev,
321 struct tevent_fd *fde, uint16_t flags,
322 void *priv)
324 struct tevent_req *req = talloc_get_type_abort(
325 priv, struct tevent_req);
326 struct async_connect_state *state =
327 tevent_req_data(req, struct async_connect_state);
328 int ret;
330 ret = connect(state->fd, (struct sockaddr *)(void *)&state->address,
331 state->address_len);
332 if (ret == 0) {
333 state->sys_errno = 0;
334 TALLOC_FREE(fde);
335 tevent_req_done(req);
336 return;
338 if (errno == EINPROGRESS) {
339 /* Try again later, leave the fde around */
340 return;
342 state->sys_errno = errno;
343 TALLOC_FREE(fde);
344 tevent_req_error(req, errno);
345 return;
348 int async_connect_recv(struct tevent_req *req, int *perrno)
350 struct async_connect_state *state =
351 tevent_req_data(req, struct async_connect_state);
352 int err;
354 fcntl(state->fd, F_SETFL, state->old_sockflags);
356 if (tevent_req_is_unix_error(req, &err)) {
357 *perrno = err;
358 return -1;
361 if (state->sys_errno == 0) {
362 return 0;
365 *perrno = state->sys_errno;
366 return -1;
369 struct writev_state {
370 struct tevent_context *ev;
371 int fd;
372 struct iovec *iov;
373 int count;
374 size_t total_size;
375 uint16_t flags;
376 bool err_on_readability;
379 static void writev_trigger(struct tevent_req *req, void *private_data);
380 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
381 uint16_t flags, void *private_data);
383 struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
384 struct tevent_queue *queue, int fd,
385 bool err_on_readability,
386 struct iovec *iov, int count)
388 struct tevent_req *req;
389 struct writev_state *state;
391 req = tevent_req_create(mem_ctx, &state, struct writev_state);
392 if (req == NULL) {
393 return NULL;
395 state->ev = ev;
396 state->fd = fd;
397 state->total_size = 0;
398 state->count = count;
399 state->iov = (struct iovec *)talloc_memdup(
400 state, iov, sizeof(struct iovec) * count);
401 if (state->iov == NULL) {
402 goto fail;
404 state->flags = TEVENT_FD_WRITE|TEVENT_FD_READ;
405 state->err_on_readability = err_on_readability;
407 if (queue == NULL) {
408 struct tevent_fd *fde;
409 fde = tevent_add_fd(state->ev, state, state->fd,
410 state->flags, writev_handler, req);
411 if (tevent_req_nomem(fde, req)) {
412 return tevent_req_post(req, ev);
414 return req;
417 if (!tevent_queue_add(queue, ev, req, writev_trigger, NULL)) {
418 goto fail;
420 return req;
421 fail:
422 TALLOC_FREE(req);
423 return NULL;
426 static void writev_trigger(struct tevent_req *req, void *private_data)
428 struct writev_state *state = tevent_req_data(req, struct writev_state);
429 struct tevent_fd *fde;
431 fde = tevent_add_fd(state->ev, state, state->fd, state->flags,
432 writev_handler, req);
433 if (fde == NULL) {
434 tevent_req_error(req, ENOMEM);
438 static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
439 uint16_t flags, void *private_data)
441 struct tevent_req *req = talloc_get_type_abort(
442 private_data, struct tevent_req);
443 struct writev_state *state =
444 tevent_req_data(req, struct writev_state);
445 size_t to_write, written;
446 int i;
448 to_write = 0;
450 if ((state->flags & TEVENT_FD_READ) && (flags & TEVENT_FD_READ)) {
451 int ret, value;
453 if (state->err_on_readability) {
454 /* Readable and the caller wants an error on read. */
455 tevent_req_error(req, EPIPE);
456 return;
459 /* Might be an error. Check if there are bytes to read */
460 ret = ioctl(state->fd, FIONREAD, &value);
461 /* FIXME - should we also check
462 for ret == 0 and value == 0 here ? */
463 if (ret == -1) {
464 /* There's an error. */
465 tevent_req_error(req, EPIPE);
466 return;
468 /* A request for TEVENT_FD_READ will succeed from now and
469 forevermore until the bytes are read so if there was
470 an error we'll wait until we do read, then get it in
471 the read callback function. Until then, remove TEVENT_FD_READ
472 from the flags we're waiting for. */
473 state->flags &= ~TEVENT_FD_READ;
474 TEVENT_FD_NOT_READABLE(fde);
476 /* If not writable, we're done. */
477 if (!(flags & TEVENT_FD_WRITE)) {
478 return;
482 for (i=0; i<state->count; i++) {
483 to_write += state->iov[i].iov_len;
486 written = writev(state->fd, state->iov, state->count);
487 if ((written == -1) && (errno == EINTR)) {
488 /* retry */
489 return;
491 if (written == -1) {
492 tevent_req_error(req, errno);
493 return;
495 if (written == 0) {
496 tevent_req_error(req, EPIPE);
497 return;
499 state->total_size += written;
501 if (written == to_write) {
502 tevent_req_done(req);
503 return;
507 * We've written less than we were asked to, drop stuff from
508 * state->iov.
511 while (written > 0) {
512 if (written < state->iov[0].iov_len) {
513 state->iov[0].iov_base =
514 (char *)state->iov[0].iov_base + written;
515 state->iov[0].iov_len -= written;
516 break;
518 written -= state->iov[0].iov_len;
519 state->iov += 1;
520 state->count -= 1;
524 ssize_t writev_recv(struct tevent_req *req, int *perrno)
526 struct writev_state *state =
527 tevent_req_data(req, struct writev_state);
529 if (tevent_req_is_unix_error(req, perrno)) {
530 return -1;
532 return state->total_size;
535 struct read_packet_state {
536 int fd;
537 uint8_t *buf;
538 size_t nread;
539 ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
540 void *private_data;
543 static void read_packet_handler(struct tevent_context *ev,
544 struct tevent_fd *fde,
545 uint16_t flags, void *private_data);
547 struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
548 struct tevent_context *ev,
549 int fd, size_t initial,
550 ssize_t (*more)(uint8_t *buf,
551 size_t buflen,
552 void *private_data),
553 void *private_data)
555 struct tevent_req *result;
556 struct read_packet_state *state;
557 struct tevent_fd *fde;
559 result = tevent_req_create(mem_ctx, &state, struct read_packet_state);
560 if (result == NULL) {
561 return NULL;
563 state->fd = fd;
564 state->nread = 0;
565 state->more = more;
566 state->private_data = private_data;
568 state->buf = talloc_array(state, uint8_t, initial);
569 if (state->buf == NULL) {
570 goto fail;
573 fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, read_packet_handler,
574 result);
575 if (fde == NULL) {
576 goto fail;
578 return result;
579 fail:
580 TALLOC_FREE(result);
581 return NULL;
584 static void read_packet_handler(struct tevent_context *ev,
585 struct tevent_fd *fde,
586 uint16_t flags, void *private_data)
588 struct tevent_req *req = talloc_get_type_abort(
589 private_data, struct tevent_req);
590 struct read_packet_state *state =
591 tevent_req_data(req, struct read_packet_state);
592 size_t total = talloc_get_size(state->buf);
593 ssize_t nread, more;
594 uint8_t *tmp;
596 nread = recv(state->fd, state->buf+state->nread, total-state->nread,
598 if ((nread == -1) && (errno == EINTR)) {
599 /* retry */
600 return;
602 if (nread == -1) {
603 tevent_req_error(req, errno);
604 return;
606 if (nread == 0) {
607 tevent_req_error(req, EPIPE);
608 return;
611 state->nread += nread;
612 if (state->nread < total) {
613 /* Come back later */
614 return;
618 * We got what was initially requested. See if "more" asks for -- more.
620 if (state->more == NULL) {
621 /* Nobody to ask, this is a async read_data */
622 tevent_req_done(req);
623 return;
626 more = state->more(state->buf, total, state->private_data);
627 if (more == -1) {
628 /* We got an invalid packet, tell the caller */
629 tevent_req_error(req, EIO);
630 return;
632 if (more == 0) {
633 /* We're done, full packet received */
634 tevent_req_done(req);
635 return;
638 tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
639 if (tevent_req_nomem(tmp, req)) {
640 return;
642 state->buf = tmp;
645 ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
646 uint8_t **pbuf, int *perrno)
648 struct read_packet_state *state =
649 tevent_req_data(req, struct read_packet_state);
651 if (tevent_req_is_unix_error(req, perrno)) {
652 return -1;
654 *pbuf = talloc_move(mem_ctx, &state->buf);
655 return talloc_get_size(*pbuf);