Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : async socket syscalls
4 : Copyright (C) Volker Lendecke 2008
5 :
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
9 :
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.
14 :
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.
19 :
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/>.
22 : */
23 :
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"
30 : #include "lib/util/iov_buf.h"
31 : #include "lib/util/util_net.h"
32 :
33 : /* Note: lib/util/ is currently GPL */
34 : #include "lib/util/tevent_unix.h"
35 : #include "lib/util/samba_util.h"
36 :
37 : struct async_connect_state {
38 : int fd;
39 : struct tevent_fd *fde;
40 : int result;
41 : long old_sockflags;
42 : socklen_t address_len;
43 : struct sockaddr_storage address;
44 :
45 : void (*before_connect)(void *private_data);
46 : void (*after_connect)(void *private_data);
47 : void *private_data;
48 : };
49 :
50 : static void async_connect_cleanup(struct tevent_req *req,
51 : enum tevent_req_state req_state);
52 : static void async_connect_connected(struct tevent_context *ev,
53 : struct tevent_fd *fde, uint16_t flags,
54 : void *priv);
55 :
56 : /**
57 : * @brief async version of connect(2)
58 : * @param[in] mem_ctx The memory context to hang the result off
59 : * @param[in] ev The event context to work from
60 : * @param[in] fd The socket to recv from
61 : * @param[in] address Where to connect?
62 : * @param[in] address_len Length of *address
63 : * @retval The async request
64 : *
65 : * This function sets the socket into non-blocking state to be able to call
66 : * connect in an async state. This will be reset when the request is finished.
67 : */
68 :
69 6135 : struct tevent_req *async_connect_send(
70 : TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd,
71 : const struct sockaddr *address, socklen_t address_len,
72 : void (*before_connect)(void *private_data),
73 : void (*after_connect)(void *private_data),
74 : void *private_data)
75 : {
76 : struct tevent_req *req;
77 : struct async_connect_state *state;
78 : int ret;
79 :
80 6135 : req = tevent_req_create(mem_ctx, &state, struct async_connect_state);
81 6135 : if (req == NULL) {
82 0 : return NULL;
83 : }
84 :
85 : /**
86 : * We have to set the socket to nonblocking for async connect(2). Keep
87 : * the old sockflags around.
88 : */
89 :
90 6135 : state->fd = fd;
91 6135 : state->before_connect = before_connect;
92 6135 : state->after_connect = after_connect;
93 6135 : state->private_data = private_data;
94 :
95 6135 : state->old_sockflags = fcntl(fd, F_GETFL, 0);
96 6135 : if (state->old_sockflags == -1) {
97 0 : tevent_req_error(req, errno);
98 0 : return tevent_req_post(req, ev);
99 : }
100 :
101 6135 : tevent_req_set_cleanup_fn(req, async_connect_cleanup);
102 :
103 6135 : state->address_len = address_len;
104 6135 : if (address_len > sizeof(state->address)) {
105 0 : tevent_req_error(req, EINVAL);
106 0 : return tevent_req_post(req, ev);
107 : }
108 6135 : memcpy(&state->address, address, address_len);
109 :
110 6135 : ret = set_blocking(fd, false);
111 6135 : if (ret == -1) {
112 0 : tevent_req_error(req, errno);
113 0 : return tevent_req_post(req, ev);
114 : }
115 :
116 6135 : if (state->before_connect != NULL) {
117 3536 : state->before_connect(state->private_data);
118 : }
119 :
120 6135 : state->result = connect(fd, address, address_len);
121 :
122 6135 : if (state->after_connect != NULL) {
123 3536 : state->after_connect(state->private_data);
124 : }
125 :
126 6135 : if (state->result == 0) {
127 6118 : tevent_req_done(req);
128 6118 : return tevent_req_post(req, ev);
129 : }
130 :
131 : /*
132 : * The only errno indicating that an initial connect is still
133 : * in flight is EINPROGRESS.
134 : *
135 : * This allows callers like open_socket_out_send() to reuse
136 : * fds and call us with an fd for which the connect is still
137 : * in flight. The proper thing to do for callers would be
138 : * closing the fd and starting from scratch with a fresh
139 : * socket.
140 : */
141 :
142 17 : if (errno != EINPROGRESS) {
143 17 : tevent_req_error(req, errno);
144 17 : return tevent_req_post(req, ev);
145 : }
146 :
147 : /*
148 : * Note for historic reasons TEVENT_FD_WRITE is not enough
149 : * to get notified for POLLERR or EPOLLHUP even if they
150 : * come together with POLLOUT. That means we need to
151 : * use TEVENT_FD_READ in addition until we have
152 : * TEVENT_FD_ERROR.
153 : */
154 0 : state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ|TEVENT_FD_WRITE,
155 : async_connect_connected, req);
156 0 : if (state->fde == NULL) {
157 0 : tevent_req_error(req, ENOMEM);
158 0 : return tevent_req_post(req, ev);
159 : }
160 0 : return req;
161 : }
162 :
163 12270 : static void async_connect_cleanup(struct tevent_req *req,
164 : enum tevent_req_state req_state)
165 : {
166 8666 : struct async_connect_state *state =
167 12270 : tevent_req_data(req, struct async_connect_state);
168 :
169 12270 : TALLOC_FREE(state->fde);
170 12270 : if (state->fd != -1) {
171 : int ret;
172 :
173 6135 : ret = fcntl(state->fd, F_SETFL, state->old_sockflags);
174 6135 : if (ret == -1) {
175 0 : abort();
176 : }
177 :
178 6135 : state->fd = -1;
179 : }
180 12270 : }
181 :
182 : /**
183 : * fde event handler for connect(2)
184 : * @param[in] ev The event context that sent us here
185 : * @param[in] fde The file descriptor event associated with the connect
186 : * @param[in] flags Indicate read/writeability of the socket
187 : * @param[in] priv private data, "struct async_req *" in this case
188 : */
189 :
190 0 : static void async_connect_connected(struct tevent_context *ev,
191 : struct tevent_fd *fde, uint16_t flags,
192 : void *priv)
193 : {
194 0 : struct tevent_req *req = talloc_get_type_abort(
195 : priv, struct tevent_req);
196 0 : struct async_connect_state *state =
197 0 : tevent_req_data(req, struct async_connect_state);
198 : int ret;
199 0 : int socket_error = 0;
200 0 : socklen_t slen = sizeof(socket_error);
201 :
202 0 : ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
203 : &socket_error, &slen);
204 :
205 0 : if (ret != 0) {
206 : /*
207 : * According to Stevens this is the Solaris behaviour
208 : * in case the connection encountered an error:
209 : * getsockopt() fails, error is in errno
210 : */
211 0 : tevent_req_error(req, errno);
212 0 : return;
213 : }
214 :
215 0 : if (socket_error != 0) {
216 : /*
217 : * Berkeley derived implementations (including) Linux
218 : * return the pending error via socket_error.
219 : */
220 0 : tevent_req_error(req, socket_error);
221 0 : return;
222 : }
223 :
224 0 : tevent_req_done(req);
225 0 : return;
226 : }
227 :
228 6135 : int async_connect_recv(struct tevent_req *req, int *perrno)
229 : {
230 6135 : int err = tevent_req_simple_recv_unix(req);
231 :
232 6135 : if (err != 0) {
233 17 : *perrno = err;
234 17 : return -1;
235 : }
236 :
237 6118 : return 0;
238 : }
239 :
240 : struct writev_state {
241 : struct tevent_context *ev;
242 : struct tevent_queue_entry *queue_entry;
243 : int fd;
244 : struct tevent_fd *fde;
245 : struct iovec *iov;
246 : int count;
247 : size_t total_size;
248 : uint16_t flags;
249 : bool err_on_readability;
250 : };
251 :
252 : static void writev_cleanup(struct tevent_req *req,
253 : enum tevent_req_state req_state);
254 : static bool writev_cancel(struct tevent_req *req);
255 : static void writev_trigger(struct tevent_req *req, void *private_data);
256 : static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
257 : uint16_t flags, void *private_data);
258 :
259 1060632 : struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
260 : struct tevent_queue *queue, int fd,
261 : bool err_on_readability,
262 : struct iovec *iov, int count)
263 : {
264 : struct tevent_req *req;
265 : struct writev_state *state;
266 :
267 1060632 : req = tevent_req_create(mem_ctx, &state, struct writev_state);
268 1060632 : if (req == NULL) {
269 0 : return NULL;
270 : }
271 1060632 : state->ev = ev;
272 1060632 : state->fd = fd;
273 1060632 : state->total_size = 0;
274 1060632 : state->count = count;
275 1060632 : state->iov = (struct iovec *)talloc_memdup(
276 : state, iov, sizeof(struct iovec) * count);
277 1060632 : if (tevent_req_nomem(state->iov, req)) {
278 0 : return tevent_req_post(req, ev);
279 : }
280 1060632 : state->flags = TEVENT_FD_WRITE|TEVENT_FD_READ;
281 1060632 : state->err_on_readability = err_on_readability;
282 :
283 1060632 : tevent_req_set_cleanup_fn(req, writev_cleanup);
284 1060632 : tevent_req_set_cancel_fn(req, writev_cancel);
285 :
286 1060632 : if (queue == NULL) {
287 17576 : state->fde = tevent_add_fd(state->ev, state, state->fd,
288 : state->flags, writev_handler, req);
289 17576 : if (tevent_req_nomem(state->fde, req)) {
290 0 : return tevent_req_post(req, ev);
291 : }
292 17576 : return req;
293 : }
294 :
295 : /*
296 : * writev_trigger tries a nonblocking write. If that succeeds,
297 : * we can't directly notify the callback to call
298 : * writev_recv. The callback would TALLOC_FREE(req) after
299 : * calling writev_recv even before writev_trigger can inspect
300 : * it for success.
301 : */
302 1043056 : tevent_req_defer_callback(req, ev);
303 :
304 1043056 : state->queue_entry = tevent_queue_add_optimize_empty(
305 : queue, ev, req, writev_trigger, NULL);
306 1043056 : if (tevent_req_nomem(state->queue_entry, req)) {
307 0 : return tevent_req_post(req, ev);
308 : }
309 1043056 : if (!tevent_req_is_in_progress(req)) {
310 1026463 : return tevent_req_post(req, ev);
311 : }
312 16593 : return req;
313 : }
314 :
315 2121262 : static void writev_cleanup(struct tevent_req *req,
316 : enum tevent_req_state req_state)
317 : {
318 2121262 : struct writev_state *state = tevent_req_data(req, struct writev_state);
319 :
320 2121262 : TALLOC_FREE(state->queue_entry);
321 2121262 : TALLOC_FREE(state->fde);
322 2121262 : }
323 :
324 3674 : static bool writev_cancel(struct tevent_req *req)
325 : {
326 3674 : struct writev_state *state = tevent_req_data(req, struct writev_state);
327 :
328 3674 : if (state->total_size > 0) {
329 : /*
330 : * We've already started to write :-(
331 : */
332 3471 : return false;
333 : }
334 :
335 203 : TALLOC_FREE(state->queue_entry);
336 203 : TALLOC_FREE(state->fde);
337 :
338 203 : tevent_req_defer_callback(req, state->ev);
339 203 : tevent_req_error(req, ECANCELED);
340 203 : return true;
341 : }
342 :
343 1211232 : static void writev_do(struct tevent_req *req, struct writev_state *state)
344 : {
345 : ssize_t written;
346 : bool ok;
347 :
348 1211232 : written = writev(state->fd, state->iov, state->count);
349 1211232 : if ((written == -1) &&
350 0 : ((errno == EINTR) ||
351 0 : (errno == EAGAIN) ||
352 0 : (errno == EWOULDBLOCK))) {
353 : /* retry after going through the tevent loop */
354 0 : return;
355 : }
356 1211232 : if (written == -1) {
357 0 : tevent_req_error(req, errno);
358 0 : return;
359 : }
360 1211232 : if (written == 0) {
361 0 : tevent_req_error(req, EPIPE);
362 0 : return;
363 : }
364 1211232 : state->total_size += written;
365 :
366 1211232 : ok = iov_advance(&state->iov, &state->count, written);
367 1211232 : if (!ok) {
368 0 : tevent_req_error(req, EIO);
369 0 : return;
370 : }
371 :
372 1211232 : if (state->count == 0) {
373 1060428 : tevent_req_done(req);
374 1060428 : return;
375 : }
376 : }
377 :
378 1042853 : static void writev_trigger(struct tevent_req *req, void *private_data)
379 : {
380 1042853 : struct writev_state *state = tevent_req_data(req, struct writev_state);
381 :
382 1042853 : state->queue_entry = NULL;
383 :
384 1042853 : writev_do(req, state);
385 1042853 : if (!tevent_req_is_in_progress(req)) {
386 1027434 : return;
387 : }
388 :
389 15419 : state->fde = tevent_add_fd(state->ev, state, state->fd, state->flags,
390 : writev_handler, req);
391 15419 : if (tevent_req_nomem(state->fde, req)) {
392 0 : return;
393 : }
394 : }
395 :
396 168379 : static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
397 : uint16_t flags, void *private_data)
398 : {
399 168379 : struct tevent_req *req = talloc_get_type_abort(
400 : private_data, struct tevent_req);
401 122344 : struct writev_state *state =
402 168379 : tevent_req_data(req, struct writev_state);
403 :
404 168379 : if ((state->flags & TEVENT_FD_READ) && (flags & TEVENT_FD_READ)) {
405 : int ret, value;
406 :
407 26 : if (state->err_on_readability) {
408 : /* Readable and the caller wants an error on read. */
409 0 : tevent_req_error(req, EPIPE);
410 0 : return;
411 : }
412 :
413 : /* Might be an error. Check if there are bytes to read */
414 26 : ret = ioctl(state->fd, FIONREAD, &value);
415 : /* FIXME - should we also check
416 : for ret == 0 and value == 0 here ? */
417 26 : if (ret == -1) {
418 : /* There's an error. */
419 0 : tevent_req_error(req, EPIPE);
420 0 : return;
421 : }
422 : /* A request for TEVENT_FD_READ will succeed from now and
423 : forevermore until the bytes are read so if there was
424 : an error we'll wait until we do read, then get it in
425 : the read callback function. Until then, remove TEVENT_FD_READ
426 : from the flags we're waiting for. */
427 26 : state->flags &= ~TEVENT_FD_READ;
428 26 : TEVENT_FD_NOT_READABLE(fde);
429 :
430 : /* If not writable, we're done. */
431 26 : if (!(flags & TEVENT_FD_WRITE)) {
432 0 : return;
433 : }
434 : }
435 :
436 168379 : writev_do(req, state);
437 : }
438 :
439 1060428 : ssize_t writev_recv(struct tevent_req *req, int *perrno)
440 : {
441 977918 : struct writev_state *state =
442 1060428 : tevent_req_data(req, struct writev_state);
443 : ssize_t ret;
444 :
445 1060428 : if (tevent_req_is_unix_error(req, perrno)) {
446 0 : tevent_req_received(req);
447 0 : return -1;
448 : }
449 1060428 : ret = state->total_size;
450 1060428 : tevent_req_received(req);
451 1060428 : return ret;
452 : }
453 :
454 : struct read_packet_state {
455 : int fd;
456 : struct tevent_fd *fde;
457 : uint8_t *buf;
458 : size_t nread;
459 : ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
460 : void *private_data;
461 : };
462 :
463 : static void read_packet_cleanup(struct tevent_req *req,
464 : enum tevent_req_state req_state);
465 : static void read_packet_handler(struct tevent_context *ev,
466 : struct tevent_fd *fde,
467 : uint16_t flags, void *private_data);
468 :
469 1170966 : struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
470 : struct tevent_context *ev,
471 : int fd, size_t initial,
472 : ssize_t (*more)(uint8_t *buf,
473 : size_t buflen,
474 : void *private_data),
475 : void *private_data)
476 : {
477 : struct tevent_req *req;
478 : struct read_packet_state *state;
479 :
480 1170966 : req = tevent_req_create(mem_ctx, &state, struct read_packet_state);
481 1170966 : if (req == NULL) {
482 0 : return NULL;
483 : }
484 1170966 : state->fd = fd;
485 1170966 : state->nread = 0;
486 1170966 : state->more = more;
487 1170966 : state->private_data = private_data;
488 :
489 1170966 : tevent_req_set_cleanup_fn(req, read_packet_cleanup);
490 :
491 1170966 : state->buf = talloc_array(state, uint8_t, initial);
492 1170966 : if (tevent_req_nomem(state->buf, req)) {
493 0 : return tevent_req_post(req, ev);
494 : }
495 :
496 1170966 : state->fde = tevent_add_fd(ev, state, fd,
497 : TEVENT_FD_READ, read_packet_handler,
498 : req);
499 1170966 : if (tevent_req_nomem(state->fde, req)) {
500 0 : return tevent_req_post(req, ev);
501 : }
502 1170966 : return req;
503 : }
504 :
505 2307542 : static void read_packet_cleanup(struct tevent_req *req,
506 : enum tevent_req_state req_state)
507 : {
508 2112623 : struct read_packet_state *state =
509 2307542 : tevent_req_data(req, struct read_packet_state);
510 :
511 2307542 : TALLOC_FREE(state->fde);
512 2307542 : }
513 :
514 2378959 : static void read_packet_handler(struct tevent_context *ev,
515 : struct tevent_fd *fde,
516 : uint16_t flags, void *private_data)
517 : {
518 2378959 : struct tevent_req *req = talloc_get_type_abort(
519 : private_data, struct tevent_req);
520 2152973 : struct read_packet_state *state =
521 2378959 : tevent_req_data(req, struct read_packet_state);
522 2378959 : size_t total = talloc_get_size(state->buf);
523 : ssize_t nread, more;
524 : uint8_t *tmp;
525 :
526 2378959 : nread = recv(state->fd, state->buf+state->nread, total-state->nread,
527 : 0);
528 2378959 : if ((nread == -1) && (errno == ENOTSOCK)) {
529 22 : nread = read(state->fd, state->buf+state->nread,
530 22 : total-state->nread);
531 : }
532 2378959 : if ((nread == -1) && (errno == EINTR)) {
533 : /* retry */
534 0 : return;
535 : }
536 2378959 : if (nread == -1) {
537 2 : tevent_req_error(req, errno);
538 2 : return;
539 : }
540 2378957 : if (nread == 0) {
541 8374 : tevent_req_error(req, EPIPE);
542 8374 : return;
543 : }
544 :
545 2370583 : state->nread += nread;
546 2370583 : if (state->nread < total) {
547 : /* Come back later */
548 105548 : return;
549 : }
550 :
551 : /*
552 : * We got what was initially requested. See if "more" asks for -- more.
553 : */
554 2265035 : if (state->more == NULL) {
555 : /* Nobody to ask, this is a async read_data */
556 22 : tevent_req_done(req);
557 22 : return;
558 : }
559 :
560 2265013 : more = state->more(state->buf, total, state->private_data);
561 2265013 : if (more == -1) {
562 : /* We got an invalid packet, tell the caller */
563 0 : tevent_req_error(req, EIO);
564 0 : return;
565 : }
566 2265013 : if (more == 0) {
567 : /* We're done, full packet received */
568 1128211 : tevent_req_done(req);
569 1128211 : return;
570 : }
571 :
572 1136802 : if (total + more < total) {
573 0 : tevent_req_error(req, EMSGSIZE);
574 0 : return;
575 : }
576 :
577 1136802 : tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
578 1136802 : if (tevent_req_nomem(tmp, req)) {
579 0 : return;
580 : }
581 1136802 : state->buf = tmp;
582 : }
583 :
584 1136609 : ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
585 : uint8_t **pbuf, int *perrno)
586 : {
587 1039642 : struct read_packet_state *state =
588 1136609 : tevent_req_data(req, struct read_packet_state);
589 :
590 1136609 : if (tevent_req_is_unix_error(req, perrno)) {
591 8376 : tevent_req_received(req);
592 8376 : return -1;
593 : }
594 1128233 : *pbuf = talloc_move(mem_ctx, &state->buf);
595 1128233 : tevent_req_received(req);
596 1128233 : return talloc_get_size(*pbuf);
597 : }
598 :
599 : struct wait_for_read_state {
600 : struct tevent_fd *fde;
601 : int fd;
602 : bool check_errors;
603 : };
604 :
605 : static void wait_for_read_cleanup(struct tevent_req *req,
606 : enum tevent_req_state req_state);
607 : static void wait_for_read_done(struct tevent_context *ev,
608 : struct tevent_fd *fde,
609 : uint16_t flags,
610 : void *private_data);
611 :
612 74434 : struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
613 : struct tevent_context *ev, int fd,
614 : bool check_errors)
615 : {
616 : struct tevent_req *req;
617 : struct wait_for_read_state *state;
618 :
619 74434 : req = tevent_req_create(mem_ctx, &state, struct wait_for_read_state);
620 74434 : if (req == NULL) {
621 0 : return NULL;
622 : }
623 :
624 74434 : tevent_req_set_cleanup_fn(req, wait_for_read_cleanup);
625 :
626 74434 : state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
627 : wait_for_read_done, req);
628 74434 : if (tevent_req_nomem(state->fde, req)) {
629 0 : return tevent_req_post(req, ev);
630 : }
631 :
632 74434 : state->fd = fd;
633 74434 : state->check_errors = check_errors;
634 74434 : return req;
635 : }
636 :
637 74952 : static void wait_for_read_cleanup(struct tevent_req *req,
638 : enum tevent_req_state req_state)
639 : {
640 45697 : struct wait_for_read_state *state =
641 74952 : tevent_req_data(req, struct wait_for_read_state);
642 :
643 74952 : TALLOC_FREE(state->fde);
644 74952 : }
645 :
646 544 : static void wait_for_read_done(struct tevent_context *ev,
647 : struct tevent_fd *fde,
648 : uint16_t flags,
649 : void *private_data)
650 : {
651 544 : struct tevent_req *req = talloc_get_type_abort(
652 : private_data, struct tevent_req);
653 368 : struct wait_for_read_state *state =
654 544 : tevent_req_data(req, struct wait_for_read_state);
655 : int ret, available;
656 :
657 544 : if ((flags & TEVENT_FD_READ) == 0) {
658 544 : return;
659 : }
660 :
661 544 : if (!state->check_errors) {
662 544 : tevent_req_done(req);
663 544 : return;
664 : }
665 :
666 0 : ret = ioctl(state->fd, FIONREAD, &available);
667 :
668 0 : if ((ret == -1) && (errno == EINTR)) {
669 : /* come back later */
670 0 : return;
671 : }
672 :
673 0 : if (ret == -1) {
674 0 : tevent_req_error(req, errno);
675 0 : return;
676 : }
677 :
678 0 : if (available == 0) {
679 0 : tevent_req_error(req, EPIPE);
680 0 : return;
681 : }
682 :
683 0 : tevent_req_done(req);
684 : }
685 :
686 544 : bool wait_for_read_recv(struct tevent_req *req, int *perr)
687 : {
688 544 : int err = tevent_req_simple_recv_unix(req);
689 :
690 544 : if (err != 0) {
691 0 : *perr = err;
692 0 : return false;
693 : }
694 :
695 544 : return true;
696 : }
697 :
698 : struct accept_state {
699 : struct tevent_fd *fde;
700 : int listen_sock;
701 : struct samba_sockaddr addr;
702 : int sock;
703 : };
704 :
705 : static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
706 : uint16_t flags, void *private_data);
707 :
708 1505 : struct tevent_req *accept_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
709 : int listen_sock)
710 : {
711 : struct tevent_req *req;
712 : struct accept_state *state;
713 :
714 1505 : req = tevent_req_create(mem_ctx, &state, struct accept_state);
715 1505 : if (req == NULL) {
716 0 : return NULL;
717 : }
718 :
719 1505 : state->listen_sock = listen_sock;
720 :
721 1505 : state->fde = tevent_add_fd(ev, state, listen_sock, TEVENT_FD_READ,
722 : accept_handler, req);
723 1505 : if (tevent_req_nomem(state->fde, req)) {
724 0 : return tevent_req_post(req, ev);
725 : }
726 1505 : return req;
727 : }
728 :
729 817 : static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
730 : uint16_t flags, void *private_data)
731 : {
732 817 : struct tevent_req *req = talloc_get_type_abort(
733 : private_data, struct tevent_req);
734 817 : struct accept_state *state = tevent_req_data(req, struct accept_state);
735 : int ret;
736 :
737 817 : TALLOC_FREE(state->fde);
738 :
739 817 : if ((flags & TEVENT_FD_READ) == 0) {
740 0 : tevent_req_error(req, EIO);
741 0 : return;
742 : }
743 :
744 817 : state->addr.sa_socklen = sizeof(state->addr.u);
745 :
746 1265 : ret = accept(state->listen_sock,
747 817 : &state->addr.u.sa,
748 : &state->addr.sa_socklen);
749 817 : if ((ret == -1) && (errno == EINTR)) {
750 : /* retry */
751 0 : return;
752 : }
753 817 : if (ret == -1) {
754 0 : tevent_req_error(req, errno);
755 0 : return;
756 : }
757 817 : smb_set_close_on_exec(ret);
758 817 : state->sock = ret;
759 817 : tevent_req_done(req);
760 : }
761 :
762 817 : int accept_recv(struct tevent_req *req,
763 : int *listen_sock,
764 : struct samba_sockaddr *paddr,
765 : int *perr)
766 : {
767 817 : struct accept_state *state = tevent_req_data(req, struct accept_state);
768 817 : int sock = state->sock;
769 : int err;
770 :
771 817 : if (tevent_req_is_unix_error(req, &err)) {
772 0 : if (perr != NULL) {
773 0 : *perr = err;
774 : }
775 0 : tevent_req_received(req);
776 0 : return -1;
777 : }
778 817 : if (listen_sock != NULL) {
779 817 : *listen_sock = state->listen_sock;
780 : }
781 817 : if (paddr != NULL) {
782 817 : *paddr = state->addr;
783 : }
784 817 : tevent_req_received(req);
785 817 : return sock;
786 : }
|