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 65925 : 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 620 : struct tevent_req *req;
77 620 : struct async_connect_state *state;
78 620 : int ret;
79 :
80 65925 : req = tevent_req_create(mem_ctx, &state, struct async_connect_state);
81 65925 : 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 65925 : state->fd = fd;
91 65925 : state->before_connect = before_connect;
92 65925 : state->after_connect = after_connect;
93 65925 : state->private_data = private_data;
94 :
95 65925 : state->old_sockflags = fcntl(fd, F_GETFL, 0);
96 65925 : if (state->old_sockflags == -1) {
97 0 : tevent_req_error(req, errno);
98 0 : return tevent_req_post(req, ev);
99 : }
100 :
101 65925 : tevent_req_set_cleanup_fn(req, async_connect_cleanup);
102 :
103 65925 : state->address_len = address_len;
104 65925 : if (address_len > sizeof(state->address)) {
105 0 : tevent_req_error(req, EINVAL);
106 0 : return tevent_req_post(req, ev);
107 : }
108 65925 : memcpy(&state->address, address, address_len);
109 :
110 65925 : ret = set_blocking(fd, false);
111 65925 : if (ret == -1) {
112 0 : tevent_req_error(req, errno);
113 0 : return tevent_req_post(req, ev);
114 : }
115 :
116 65925 : if (state->before_connect != NULL) {
117 47759 : state->before_connect(state->private_data);
118 : }
119 :
120 65925 : state->result = connect(fd, address, address_len);
121 :
122 65925 : if (state->after_connect != NULL) {
123 47759 : state->after_connect(state->private_data);
124 : }
125 :
126 65925 : if (state->result == 0) {
127 65653 : tevent_req_done(req);
128 65653 : 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 272 : if (errno != EINPROGRESS) {
143 272 : tevent_req_error(req, errno);
144 272 : 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,
155 : TEVENT_FD_ERROR|TEVENT_FD_WRITE,
156 : async_connect_connected, req);
157 0 : if (state->fde == NULL) {
158 0 : tevent_req_error(req, ENOMEM);
159 0 : return tevent_req_post(req, ev);
160 : }
161 0 : return req;
162 : }
163 :
164 131850 : static void async_connect_cleanup(struct tevent_req *req,
165 : enum tevent_req_state req_state)
166 : {
167 1240 : struct async_connect_state *state =
168 131850 : tevent_req_data(req, struct async_connect_state);
169 :
170 131850 : TALLOC_FREE(state->fde);
171 131850 : if (state->fd != -1) {
172 620 : int ret;
173 :
174 65925 : ret = fcntl(state->fd, F_SETFL, state->old_sockflags);
175 65925 : if (ret == -1) {
176 0 : abort();
177 : }
178 :
179 65925 : state->fd = -1;
180 : }
181 131850 : }
182 :
183 : /**
184 : * fde event handler for connect(2)
185 : * @param[in] ev The event context that sent us here
186 : * @param[in] fde The file descriptor event associated with the connect
187 : * @param[in] flags Indicate read/writeability of the socket
188 : * @param[in] priv private data, "struct async_req *" in this case
189 : */
190 :
191 0 : static void async_connect_connected(struct tevent_context *ev,
192 : struct tevent_fd *fde, uint16_t flags,
193 : void *priv)
194 : {
195 0 : struct tevent_req *req = talloc_get_type_abort(
196 : priv, struct tevent_req);
197 0 : struct async_connect_state *state =
198 0 : tevent_req_data(req, struct async_connect_state);
199 0 : int ret;
200 0 : int socket_error = 0;
201 0 : socklen_t slen = sizeof(socket_error);
202 :
203 0 : ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR,
204 : &socket_error, &slen);
205 :
206 0 : if (ret != 0) {
207 : /*
208 : * According to Stevens this is the Solaris behaviour
209 : * in case the connection encountered an error:
210 : * getsockopt() fails, error is in errno
211 : */
212 0 : tevent_req_error(req, errno);
213 0 : return;
214 : }
215 :
216 0 : if (socket_error != 0) {
217 : /*
218 : * Berkeley derived implementations (including) Linux
219 : * return the pending error via socket_error.
220 : */
221 0 : tevent_req_error(req, socket_error);
222 0 : return;
223 : }
224 :
225 0 : tevent_req_done(req);
226 0 : return;
227 : }
228 :
229 65925 : int async_connect_recv(struct tevent_req *req, int *perrno)
230 : {
231 65925 : int err = tevent_req_simple_recv_unix(req);
232 :
233 65925 : if (err != 0) {
234 272 : *perrno = err;
235 272 : return -1;
236 : }
237 :
238 65033 : return 0;
239 : }
240 :
241 : struct writev_state {
242 : struct tevent_context *ev;
243 : struct tevent_queue_entry *queue_entry;
244 : int fd;
245 : struct tevent_fd *fde;
246 : struct iovec *iov;
247 : int count;
248 : size_t total_size;
249 : uint16_t flags;
250 : bool err_on_readability;
251 : };
252 :
253 : static void writev_cleanup(struct tevent_req *req,
254 : enum tevent_req_state req_state);
255 : static bool writev_cancel(struct tevent_req *req);
256 : static void writev_trigger(struct tevent_req *req, void *private_data);
257 : static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
258 : uint16_t flags, void *private_data);
259 :
260 3165071 : struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
261 : struct tevent_queue *queue, int fd,
262 : bool err_on_readability,
263 : struct iovec *iov, int count)
264 : {
265 19826 : struct tevent_req *req;
266 19826 : struct writev_state *state;
267 :
268 3165071 : req = tevent_req_create(mem_ctx, &state, struct writev_state);
269 3165071 : if (req == NULL) {
270 0 : return NULL;
271 : }
272 3165071 : state->ev = ev;
273 3165071 : state->fd = fd;
274 3165071 : state->total_size = 0;
275 3165071 : state->count = count;
276 3165071 : state->iov = (struct iovec *)talloc_memdup(
277 : state, iov, sizeof(struct iovec) * count);
278 3165071 : if (tevent_req_nomem(state->iov, req)) {
279 0 : return tevent_req_post(req, ev);
280 : }
281 3165071 : state->flags = TEVENT_FD_WRITE | TEVENT_FD_ERROR;
282 3165071 : if (err_on_readability) {
283 344630 : state->flags |= TEVENT_FD_READ;
284 : }
285 :
286 3165071 : tevent_req_set_cleanup_fn(req, writev_cleanup);
287 3165071 : tevent_req_set_cancel_fn(req, writev_cancel);
288 :
289 3165071 : if (queue == NULL) {
290 125049 : state->fde = tevent_add_fd(state->ev, state, state->fd,
291 : state->flags, writev_handler, req);
292 125049 : if (tevent_req_nomem(state->fde, req)) {
293 0 : return tevent_req_post(req, ev);
294 : }
295 125049 : return req;
296 : }
297 :
298 : /*
299 : * writev_trigger tries a nonblocking write. If that succeeds,
300 : * we can't directly notify the callback to call
301 : * writev_recv. The callback would TALLOC_FREE(req) after
302 : * calling writev_recv even before writev_trigger can inspect
303 : * it for success.
304 : */
305 3040022 : tevent_req_defer_callback(req, ev);
306 :
307 3040022 : state->queue_entry = tevent_queue_add_optimize_empty(
308 : queue, ev, req, writev_trigger, NULL);
309 3040022 : if (tevent_req_nomem(state->queue_entry, req)) {
310 0 : return tevent_req_post(req, ev);
311 : }
312 3040022 : if (!tevent_req_is_in_progress(req)) {
313 2997869 : return tevent_req_post(req, ev);
314 : }
315 41166 : return req;
316 : }
317 :
318 6330142 : static void writev_cleanup(struct tevent_req *req,
319 : enum tevent_req_state req_state)
320 : {
321 6330142 : struct writev_state *state = tevent_req_data(req, struct writev_state);
322 :
323 6330142 : TALLOC_FREE(state->queue_entry);
324 6330142 : TALLOC_FREE(state->fde);
325 6330142 : }
326 :
327 6986 : static bool writev_cancel(struct tevent_req *req)
328 : {
329 6986 : struct writev_state *state = tevent_req_data(req, struct writev_state);
330 :
331 6986 : if (state->total_size > 0) {
332 : /*
333 : * We've already started to write :-(
334 : */
335 6093 : return false;
336 : }
337 :
338 506 : TALLOC_FREE(state->queue_entry);
339 506 : TALLOC_FREE(state->fde);
340 :
341 506 : tevent_req_defer_callback(req, state->ev);
342 506 : tevent_req_error(req, ECANCELED);
343 506 : return true;
344 : }
345 :
346 3685055 : static void writev_do(struct tevent_req *req, struct writev_state *state)
347 : {
348 22637 : ssize_t written;
349 22637 : bool ok;
350 :
351 3685055 : written = writev(state->fd, state->iov, state->count);
352 3685055 : if ((written == -1) &&
353 2 : ((errno == EINTR) ||
354 2 : (errno == EAGAIN) ||
355 2 : (errno == EWOULDBLOCK))) {
356 : /* retry after going through the tevent loop */
357 0 : return;
358 : }
359 3685055 : if (written == -1) {
360 2 : tevent_req_error(req, errno);
361 2 : return;
362 : }
363 3685053 : if (written == 0) {
364 0 : tevent_req_error(req, EPIPE);
365 0 : return;
366 : }
367 3685053 : state->total_size += written;
368 :
369 3685053 : ok = iov_advance(&state->iov, &state->count, written);
370 3685053 : if (!ok) {
371 0 : tevent_req_error(req, EIO);
372 0 : return;
373 : }
374 :
375 3685053 : if (state->count == 0) {
376 3164563 : tevent_req_done(req);
377 3164563 : return;
378 : }
379 : }
380 :
381 3039516 : static void writev_trigger(struct tevent_req *req, void *private_data)
382 : {
383 3039516 : struct writev_state *state = tevent_req_data(req, struct writev_state);
384 :
385 3039516 : state->queue_entry = NULL;
386 :
387 3039516 : writev_do(req, state);
388 3039516 : if (!tevent_req_is_in_progress(req)) {
389 2986065 : return;
390 : }
391 :
392 34610 : state->fde = tevent_add_fd(state->ev, state, state->fd, state->flags,
393 : writev_handler, req);
394 34610 : if (tevent_req_nomem(state->fde, req)) {
395 0 : return;
396 : }
397 : }
398 :
399 645539 : static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
400 : uint16_t flags, void *private_data)
401 : {
402 645539 : struct tevent_req *req = talloc_get_type_abort(
403 : private_data, struct tevent_req);
404 2886 : struct writev_state *state =
405 645539 : tevent_req_data(req, struct writev_state);
406 :
407 645539 : if (flags & TEVENT_FD_ERROR) {
408 : /*
409 : * There's an error, for legacy reasons
410 : * we just use EPIPE instead of a more
411 : * detailed error using
412 : * samba_socket_poll_or_sock_error().
413 : */
414 0 : tevent_req_error(req, EPIPE);
415 0 : return;
416 : }
417 :
418 645539 : if (flags & TEVENT_FD_READ) {
419 : /* Readable and the caller wants an error on read. */
420 0 : tevent_req_error(req, EPIPE);
421 0 : return;
422 : }
423 :
424 645539 : writev_do(req, state);
425 : }
426 :
427 3164565 : ssize_t writev_recv(struct tevent_req *req, int *perrno)
428 : {
429 19751 : struct writev_state *state =
430 3164565 : tevent_req_data(req, struct writev_state);
431 19751 : ssize_t ret;
432 :
433 3164565 : if (tevent_req_is_unix_error(req, perrno)) {
434 2 : tevent_req_received(req);
435 2 : return -1;
436 : }
437 3164563 : ret = state->total_size;
438 3164563 : tevent_req_received(req);
439 3164563 : return ret;
440 : }
441 :
442 : struct read_packet_state {
443 : int fd;
444 : struct tevent_fd *fde;
445 : uint8_t *buf;
446 : size_t nread;
447 : ssize_t (*more)(uint8_t *buf, size_t buflen, void *private_data);
448 : void *private_data;
449 : };
450 :
451 : static void read_packet_cleanup(struct tevent_req *req,
452 : enum tevent_req_state req_state);
453 : static void read_packet_handler(struct tevent_context *ev,
454 : struct tevent_fd *fde,
455 : uint16_t flags, void *private_data);
456 :
457 3396281 : struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
458 : struct tevent_context *ev,
459 : int fd, size_t initial,
460 : ssize_t (*more)(uint8_t *buf,
461 : size_t buflen,
462 : void *private_data),
463 : void *private_data)
464 : {
465 23858 : struct tevent_req *req;
466 23858 : struct read_packet_state *state;
467 :
468 3396281 : req = tevent_req_create(mem_ctx, &state, struct read_packet_state);
469 3396281 : if (req == NULL) {
470 0 : return NULL;
471 : }
472 3396281 : state->fd = fd;
473 3396281 : state->nread = 0;
474 3396281 : state->more = more;
475 3396281 : state->private_data = private_data;
476 :
477 3396281 : tevent_req_set_cleanup_fn(req, read_packet_cleanup);
478 :
479 3396281 : state->buf = talloc_array(state, uint8_t, initial);
480 3396281 : if (tevent_req_nomem(state->buf, req)) {
481 0 : return tevent_req_post(req, ev);
482 : }
483 :
484 3396281 : state->fde = tevent_add_fd(ev, state, fd,
485 : TEVENT_FD_READ, read_packet_handler,
486 : req);
487 3396281 : if (tevent_req_nomem(state->fde, req)) {
488 0 : return tevent_req_post(req, ev);
489 : }
490 3372423 : return req;
491 : }
492 :
493 6697835 : static void read_packet_cleanup(struct tevent_req *req,
494 : enum tevent_req_state req_state)
495 : {
496 46044 : struct read_packet_state *state =
497 6697835 : tevent_req_data(req, struct read_packet_state);
498 :
499 6697835 : TALLOC_FREE(state->fde);
500 6697835 : }
501 :
502 7082822 : static void read_packet_handler(struct tevent_context *ev,
503 : struct tevent_fd *fde,
504 : uint16_t flags, void *private_data)
505 : {
506 7082822 : struct tevent_req *req = talloc_get_type_abort(
507 : private_data, struct tevent_req);
508 44786 : struct read_packet_state *state =
509 7082822 : tevent_req_data(req, struct read_packet_state);
510 7082822 : size_t total = talloc_get_size(state->buf);
511 44786 : ssize_t nread, more;
512 44786 : uint8_t *tmp;
513 :
514 7082822 : nread = recv(state->fd, state->buf+state->nread, total-state->nread,
515 : 0);
516 7082822 : if ((nread == -1) && (errno == ENOTSOCK)) {
517 44954 : nread = read(state->fd, state->buf+state->nread,
518 168 : total-state->nread);
519 : }
520 7082822 : if ((nread == -1) && (errno == EINTR)) {
521 : /* retry */
522 0 : return;
523 : }
524 7082822 : if (nread == -1) {
525 6 : tevent_req_error(req, errno);
526 6 : return;
527 : }
528 7082816 : if (nread == 0) {
529 8109 : tevent_req_error(req, EPIPE);
530 8109 : return;
531 : }
532 :
533 7074707 : state->nread += nread;
534 7074707 : if (state->nread < total) {
535 : /* Come back later */
536 505714 : return;
537 : }
538 :
539 : /*
540 : * We got what was initially requested. See if "more" asks for -- more.
541 : */
542 6568579 : if (state->more == NULL) {
543 : /* Nobody to ask, this is a async read_data */
544 26112 : tevent_req_done(req);
545 26112 : return;
546 : }
547 :
548 6542467 : more = state->more(state->buf, total, state->private_data);
549 6542467 : if (more == -1) {
550 : /* We got an invalid packet, tell the caller */
551 0 : tevent_req_error(req, EIO);
552 0 : return;
553 : }
554 6542467 : if (more == 0) {
555 : /* We're done, full packet received */
556 3267362 : tevent_req_done(req);
557 3267362 : return;
558 : }
559 :
560 3275105 : if (total + more < total) {
561 0 : tevent_req_error(req, EMSGSIZE);
562 0 : return;
563 : }
564 :
565 3275105 : tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
566 3275105 : if (tevent_req_nomem(tmp, req)) {
567 0 : return;
568 : }
569 3275105 : state->buf = tmp;
570 : }
571 :
572 3301589 : ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
573 : uint8_t **pbuf, int *perrno)
574 : {
575 22186 : struct read_packet_state *state =
576 3301589 : tevent_req_data(req, struct read_packet_state);
577 :
578 3301589 : if (tevent_req_is_unix_error(req, perrno)) {
579 8115 : tevent_req_received(req);
580 8115 : return -1;
581 : }
582 3293474 : *pbuf = talloc_move(mem_ctx, &state->buf);
583 3293474 : tevent_req_received(req);
584 3293474 : return talloc_get_size(*pbuf);
585 : }
586 :
587 : struct wait_for_read_state {
588 : struct tevent_fd *fde;
589 : int fd;
590 : bool check_errors;
591 : };
592 :
593 : static void wait_for_read_cleanup(struct tevent_req *req,
594 : enum tevent_req_state req_state);
595 : static void wait_for_read_done(struct tevent_context *ev,
596 : struct tevent_fd *fde,
597 : uint16_t flags,
598 : void *private_data);
599 :
600 264471 : struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
601 : struct tevent_context *ev, int fd,
602 : bool check_errors)
603 : {
604 5 : struct tevent_req *req;
605 5 : struct wait_for_read_state *state;
606 :
607 264471 : req = tevent_req_create(mem_ctx, &state, struct wait_for_read_state);
608 264471 : if (req == NULL) {
609 0 : return NULL;
610 : }
611 :
612 264471 : tevent_req_set_cleanup_fn(req, wait_for_read_cleanup);
613 :
614 264471 : state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
615 : wait_for_read_done, req);
616 264471 : if (tevent_req_nomem(state->fde, req)) {
617 0 : return tevent_req_post(req, ev);
618 : }
619 :
620 264471 : state->fd = fd;
621 264471 : state->check_errors = check_errors;
622 264471 : return req;
623 : }
624 :
625 265918 : static void wait_for_read_cleanup(struct tevent_req *req,
626 : enum tevent_req_state req_state)
627 : {
628 5 : struct wait_for_read_state *state =
629 265918 : tevent_req_data(req, struct wait_for_read_state);
630 :
631 265918 : TALLOC_FREE(state->fde);
632 265918 : }
633 :
634 1452 : static void wait_for_read_done(struct tevent_context *ev,
635 : struct tevent_fd *fde,
636 : uint16_t flags,
637 : void *private_data)
638 : {
639 1452 : struct tevent_req *req = talloc_get_type_abort(
640 : private_data, struct tevent_req);
641 5 : struct wait_for_read_state *state =
642 1452 : tevent_req_data(req, struct wait_for_read_state);
643 5 : int ret, available;
644 :
645 1452 : if ((flags & TEVENT_FD_READ) == 0) {
646 1452 : return;
647 : }
648 :
649 1452 : if (!state->check_errors) {
650 1446 : tevent_req_done(req);
651 1446 : return;
652 : }
653 :
654 6 : ret = ioctl(state->fd, FIONREAD, &available);
655 :
656 6 : if ((ret == -1) && (errno == EINTR)) {
657 : /* come back later */
658 0 : return;
659 : }
660 :
661 6 : if (ret == -1) {
662 0 : tevent_req_error(req, errno);
663 0 : return;
664 : }
665 :
666 6 : if (available == 0) {
667 6 : tevent_req_error(req, EPIPE);
668 6 : return;
669 : }
670 :
671 0 : tevent_req_done(req);
672 : }
673 :
674 1441 : bool wait_for_read_recv(struct tevent_req *req, int *perr)
675 : {
676 1441 : int err = tevent_req_simple_recv_unix(req);
677 :
678 1441 : if (err != 0) {
679 0 : *perr = err;
680 0 : return false;
681 : }
682 :
683 1441 : return true;
684 : }
685 :
686 : struct accept_state {
687 : struct tevent_fd *fde;
688 : int listen_sock;
689 : struct samba_sockaddr addr;
690 : int sock;
691 : };
692 :
693 : static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
694 : uint16_t flags, void *private_data);
695 :
696 44632 : struct tevent_req *accept_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
697 : int listen_sock)
698 : {
699 0 : struct tevent_req *req;
700 0 : struct accept_state *state;
701 :
702 44632 : req = tevent_req_create(mem_ctx, &state, struct accept_state);
703 44632 : if (req == NULL) {
704 0 : return NULL;
705 : }
706 :
707 44632 : state->listen_sock = listen_sock;
708 :
709 44632 : state->fde = tevent_add_fd(ev, state, listen_sock, TEVENT_FD_READ,
710 : accept_handler, req);
711 44632 : if (tevent_req_nomem(state->fde, req)) {
712 0 : return tevent_req_post(req, ev);
713 : }
714 44632 : return req;
715 : }
716 :
717 43005 : static void accept_handler(struct tevent_context *ev, struct tevent_fd *fde,
718 : uint16_t flags, void *private_data)
719 : {
720 43005 : struct tevent_req *req = talloc_get_type_abort(
721 : private_data, struct tevent_req);
722 43005 : struct accept_state *state = tevent_req_data(req, struct accept_state);
723 0 : int ret;
724 :
725 43005 : TALLOC_FREE(state->fde);
726 :
727 43005 : if ((flags & TEVENT_FD_READ) == 0) {
728 0 : tevent_req_error(req, EIO);
729 0 : return;
730 : }
731 :
732 43005 : state->addr.sa_socklen = sizeof(state->addr.u);
733 :
734 43005 : ret = accept(state->listen_sock,
735 43005 : &state->addr.u.sa,
736 : &state->addr.sa_socklen);
737 43005 : if ((ret == -1) && (errno == EINTR)) {
738 : /* retry */
739 0 : return;
740 : }
741 43005 : if (ret == -1) {
742 0 : tevent_req_error(req, errno);
743 0 : return;
744 : }
745 43005 : smb_set_close_on_exec(ret);
746 43005 : state->sock = ret;
747 43005 : tevent_req_done(req);
748 : }
749 :
750 43005 : int accept_recv(struct tevent_req *req,
751 : int *listen_sock,
752 : struct samba_sockaddr *paddr,
753 : int *perr)
754 : {
755 43005 : struct accept_state *state = tevent_req_data(req, struct accept_state);
756 43005 : int sock = state->sock;
757 0 : int err;
758 :
759 43005 : if (tevent_req_is_unix_error(req, &err)) {
760 0 : if (perr != NULL) {
761 0 : *perr = err;
762 : }
763 0 : tevent_req_received(req);
764 0 : return -1;
765 : }
766 43005 : if (listen_sock != NULL) {
767 43005 : *listen_sock = state->listen_sock;
768 : }
769 43005 : if (paddr != NULL) {
770 43005 : *paddr = state->addr;
771 : }
772 43005 : tevent_req_received(req);
773 43005 : return sock;
774 : }
|