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