Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Stefan Metzmacher 2009
5 :
6 : ** NOTE! The following LGPL license applies to the tsocket
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 : Lesser General Public License for more details.
19 :
20 : You should have received a copy of the GNU Lesser General Public
21 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "replace.h"
25 : #include "system/filesys.h"
26 : #include "system/network.h"
27 : #include "tsocket.h"
28 : #include "tsocket_internal.h"
29 : #include "lib/util/iov_buf.h"
30 : #include "lib/util/blocking.h"
31 : #include "lib/util/util_net.h"
32 :
33 21184014 : static int tsocket_bsd_error_from_errno(int ret,
34 : int sys_errno,
35 : bool *retry)
36 : {
37 21250252 : *retry = false;
38 :
39 21250252 : if (ret >= 0) {
40 21143575 : return 0;
41 : }
42 :
43 40447 : if (ret != -1) {
44 0 : return EIO;
45 : }
46 :
47 40447 : if (sys_errno == 0) {
48 0 : return EIO;
49 : }
50 :
51 40447 : if (sys_errno == EINTR) {
52 0 : *retry = true;
53 0 : return sys_errno;
54 : }
55 :
56 40447 : if (sys_errno == EINPROGRESS) {
57 0 : *retry = true;
58 0 : return sys_errno;
59 : }
60 :
61 40447 : if (sys_errno == EAGAIN) {
62 40374 : *retry = true;
63 40374 : return sys_errno;
64 : }
65 :
66 : /* ENOMEM is retryable on Solaris/illumos, and possibly other systems. */
67 65 : if (sys_errno == ENOMEM) {
68 0 : *retry = true;
69 0 : return sys_errno;
70 : }
71 :
72 : #ifdef EWOULDBLOCK
73 65 : if (sys_errno == EWOULDBLOCK) {
74 0 : *retry = true;
75 0 : return sys_errno;
76 : }
77 : #endif
78 :
79 65 : return sys_errno;
80 : }
81 :
82 18706 : static int tsocket_bsd_common_prepare_fd(int fd, bool high_fd)
83 : {
84 : int i;
85 18706 : int sys_errno = 0;
86 : int fds[3];
87 18706 : int num_fds = 0;
88 :
89 : int result;
90 : bool ok;
91 :
92 18706 : if (fd == -1) {
93 0 : return -1;
94 : }
95 :
96 : /* first make a fd >= 3 */
97 18706 : if (high_fd) {
98 32977 : while (fd < 3) {
99 0 : fds[num_fds++] = fd;
100 0 : fd = dup(fd);
101 0 : if (fd == -1) {
102 0 : sys_errno = errno;
103 0 : break;
104 : }
105 : }
106 18706 : for (i=0; i<num_fds; i++) {
107 0 : close(fds[i]);
108 : }
109 18706 : if (fd == -1) {
110 0 : errno = sys_errno;
111 0 : return fd;
112 : }
113 : }
114 :
115 18706 : result = set_blocking(fd, false);
116 18706 : if (result == -1) {
117 0 : goto fail;
118 : }
119 :
120 18706 : ok = smb_set_close_on_exec(fd);
121 18706 : if (!ok) {
122 0 : goto fail;
123 : }
124 :
125 18012 : return fd;
126 :
127 0 : fail:
128 0 : if (fd != -1) {
129 0 : sys_errno = errno;
130 0 : close(fd);
131 0 : errno = sys_errno;
132 : }
133 0 : return -1;
134 : }
135 :
136 : #ifdef HAVE_LINUX_RTNETLINK_H
137 : /**
138 : * Get the amount of pending bytes from a netlink socket
139 : *
140 : * For some reason netlink sockets don't support querying the amount of pending
141 : * data via ioctl with FIONREAD, which is what we use in tsocket_bsd_pending()
142 : * below.
143 : *
144 : * We know we are on Linux as we're using netlink, which means we have a working
145 : * MSG_TRUNC flag to recvmsg() as well, so we use that together with MSG_PEEK.
146 : **/
147 0 : static ssize_t tsocket_bsd_netlink_pending(int fd)
148 : {
149 : struct iovec iov;
150 : struct msghdr msg;
151 : char buf[1];
152 :
153 0 : iov = (struct iovec) {
154 : .iov_base = buf,
155 : .iov_len = sizeof(buf)
156 : };
157 :
158 0 : msg = (struct msghdr) {
159 : .msg_iov = &iov,
160 : .msg_iovlen = 1
161 : };
162 :
163 0 : return recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC);
164 : }
165 : #else
166 : static ssize_t tsocket_bsd_netlink_pending(int fd)
167 : {
168 : errno = ENOSYS;
169 : return -1;
170 : }
171 : #endif
172 :
173 135233 : static ssize_t tsocket_bsd_pending(int fd)
174 : {
175 : int ret, error;
176 135233 : int value = 0;
177 : socklen_t len;
178 :
179 135233 : ret = ioctl(fd, FIONREAD, &value);
180 135233 : if (ret == -1) {
181 0 : return ret;
182 : }
183 :
184 135233 : if (ret != 0) {
185 : /* this should not be reached */
186 0 : errno = EIO;
187 0 : return -1;
188 : }
189 :
190 135233 : if (value != 0) {
191 129961 : return value;
192 : }
193 :
194 5272 : error = 0;
195 5272 : len = sizeof(error);
196 :
197 : /*
198 : * if no data is available check if the socket is in error state. For
199 : * dgram sockets it's the way to return ICMP error messages of
200 : * connected sockets to the caller.
201 : */
202 5272 : ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
203 5272 : if (ret == -1) {
204 0 : return ret;
205 : }
206 5272 : if (error != 0) {
207 0 : errno = error;
208 0 : return -1;
209 : }
210 5257 : return 0;
211 : }
212 :
213 : static const struct tsocket_address_ops tsocket_address_bsd_ops;
214 :
215 792297 : int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
216 : const struct sockaddr *sa,
217 : size_t sa_socklen,
218 : struct tsocket_address **_addr,
219 : const char *location)
220 : {
221 : struct tsocket_address *addr;
222 792297 : struct samba_sockaddr *bsda = NULL;
223 :
224 792297 : if (sa_socklen < sizeof(sa->sa_family)) {
225 0 : errno = EINVAL;
226 0 : return -1;
227 : }
228 :
229 792297 : switch (sa->sa_family) {
230 43119 : case AF_UNIX:
231 43119 : if (sa_socklen > sizeof(struct sockaddr_un)) {
232 0 : sa_socklen = sizeof(struct sockaddr_un);
233 : }
234 40566 : break;
235 721208 : case AF_INET:
236 721208 : if (sa_socklen < sizeof(struct sockaddr_in)) {
237 0 : errno = EINVAL;
238 0 : return -1;
239 : }
240 709362 : sa_socklen = sizeof(struct sockaddr_in);
241 709362 : break;
242 : #ifdef HAVE_IPV6
243 27970 : case AF_INET6:
244 27970 : if (sa_socklen < sizeof(struct sockaddr_in6)) {
245 0 : errno = EINVAL;
246 0 : return -1;
247 : }
248 27701 : sa_socklen = sizeof(struct sockaddr_in6);
249 27701 : break;
250 : #endif
251 0 : default:
252 0 : errno = EAFNOSUPPORT;
253 0 : return -1;
254 : }
255 :
256 777629 : if (sa_socklen > sizeof(struct sockaddr_storage)) {
257 0 : errno = EINVAL;
258 0 : return -1;
259 : }
260 :
261 792297 : addr = tsocket_address_create(mem_ctx,
262 : &tsocket_address_bsd_ops,
263 : &bsda,
264 : struct samba_sockaddr,
265 : location);
266 792297 : if (!addr) {
267 0 : errno = ENOMEM;
268 0 : return -1;
269 : }
270 :
271 792297 : ZERO_STRUCTP(bsda);
272 :
273 806965 : memcpy(&bsda->u.ss, sa, sa_socklen);
274 :
275 792297 : bsda->sa_socklen = sa_socklen;
276 : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
277 : bsda->u.sa.sa_len = bsda->sa_socklen;
278 : #endif
279 :
280 792297 : *_addr = addr;
281 792297 : return 0;
282 : }
283 :
284 4 : int _tsocket_address_bsd_from_samba_sockaddr(TALLOC_CTX *mem_ctx,
285 : const struct samba_sockaddr *xs_addr,
286 : struct tsocket_address **t_addr,
287 : const char *location)
288 : {
289 4 : return _tsocket_address_bsd_from_sockaddr(mem_ctx,
290 : &xs_addr->u.sa,
291 4 : xs_addr->sa_socklen,
292 : t_addr,
293 : location);
294 : }
295 :
296 116474 : ssize_t tsocket_address_bsd_sockaddr(const struct tsocket_address *addr,
297 : struct sockaddr *sa,
298 : size_t sa_socklen)
299 : {
300 116474 : struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
301 : struct samba_sockaddr);
302 :
303 116474 : if (!bsda) {
304 0 : errno = EINVAL;
305 0 : return -1;
306 : }
307 :
308 116474 : if (sa_socklen < bsda->sa_socklen) {
309 0 : errno = EINVAL;
310 0 : return -1;
311 : }
312 :
313 116474 : if (sa_socklen > bsda->sa_socklen) {
314 116115 : memset(sa, 0, sa_socklen);
315 116115 : sa_socklen = bsda->sa_socklen;
316 : }
317 :
318 118978 : memcpy(sa, &bsda->u.ss, sa_socklen);
319 : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
320 : sa->sa_len = sa_socklen;
321 : #endif
322 116474 : return sa_socklen;
323 : }
324 :
325 144985 : bool tsocket_address_is_inet(const struct tsocket_address *addr, const char *fam)
326 : {
327 144985 : struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
328 : struct samba_sockaddr);
329 :
330 144985 : if (!bsda) {
331 0 : return false;
332 : }
333 :
334 144985 : switch (bsda->u.sa.sa_family) {
335 140751 : case AF_INET:
336 140751 : if (strcasecmp(fam, "ip") == 0) {
337 134617 : return true;
338 : }
339 :
340 3714 : if (strcasecmp(fam, "ipv4") == 0) {
341 2338 : return true;
342 : }
343 :
344 1338 : return false;
345 : #ifdef HAVE_IPV6
346 1794 : case AF_INET6:
347 1794 : if (strcasecmp(fam, "ip") == 0) {
348 1052 : return true;
349 : }
350 :
351 740 : if (strcasecmp(fam, "ipv6") == 0) {
352 368 : return true;
353 : }
354 :
355 370 : return false;
356 : #endif
357 : }
358 :
359 2436 : return false;
360 : }
361 :
362 82706 : int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
363 : const char *fam,
364 : const char *addr,
365 : uint16_t port,
366 : struct tsocket_address **_addr,
367 : const char *location)
368 : {
369 : struct addrinfo hints;
370 82706 : struct addrinfo *result = NULL;
371 : char port_str[6];
372 : int ret;
373 :
374 82706 : ZERO_STRUCT(hints);
375 : /*
376 : * we use SOCKET_STREAM here to get just one result
377 : * back from getaddrinfo().
378 : */
379 82706 : hints.ai_socktype = SOCK_STREAM;
380 82706 : hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
381 :
382 82706 : if (strcasecmp(fam, "ip") == 0) {
383 68718 : hints.ai_family = AF_UNSPEC;
384 68718 : if (!addr) {
385 : #ifdef HAVE_IPV6
386 4652 : addr = "::";
387 : #else
388 : addr = "0.0.0.0";
389 : #endif
390 : }
391 13988 : } else if (strcasecmp(fam, "ipv4") == 0) {
392 2669 : hints.ai_family = AF_INET;
393 2669 : if (!addr) {
394 1294 : addr = "0.0.0.0";
395 : }
396 : #ifdef HAVE_IPV6
397 11319 : } else if (strcasecmp(fam, "ipv6") == 0) {
398 11318 : hints.ai_family = AF_INET6;
399 11318 : if (!addr) {
400 326 : addr = "::";
401 : }
402 : #endif
403 : } else {
404 1 : errno = EAFNOSUPPORT;
405 1 : return -1;
406 : }
407 :
408 84629 : snprintf(port_str, sizeof(port_str), "%u", port);
409 :
410 82705 : ret = getaddrinfo(addr, port_str, &hints, &result);
411 82705 : if (ret != 0) {
412 409 : switch (ret) {
413 412 : case EAI_FAIL:
414 : case EAI_NONAME:
415 : #ifdef EAI_ADDRFAMILY
416 : case EAI_ADDRFAMILY:
417 : #endif
418 412 : errno = EINVAL;
419 412 : break;
420 : }
421 409 : ret = -1;
422 409 : goto done;
423 : }
424 :
425 82293 : if (result->ai_socktype != SOCK_STREAM) {
426 0 : errno = EINVAL;
427 0 : ret = -1;
428 0 : goto done;
429 : }
430 :
431 148398 : ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
432 82293 : result->ai_addr,
433 82293 : result->ai_addrlen,
434 : _addr,
435 : location);
436 :
437 82705 : done:
438 82705 : if (result) {
439 82293 : freeaddrinfo(result);
440 : }
441 80781 : return ret;
442 : }
443 :
444 847348 : char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
445 : TALLOC_CTX *mem_ctx)
446 : {
447 847348 : struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
448 : struct samba_sockaddr);
449 : char addr_str[INET6_ADDRSTRLEN+1];
450 : const char *str;
451 :
452 847348 : if (!bsda) {
453 0 : errno = EINVAL;
454 0 : return NULL;
455 : }
456 :
457 847348 : switch (bsda->u.sa.sa_family) {
458 823168 : case AF_INET:
459 823168 : str = inet_ntop(bsda->u.in.sin_family,
460 823168 : &bsda->u.in.sin_addr,
461 : addr_str, sizeof(addr_str));
462 823168 : break;
463 : #ifdef HAVE_IPV6
464 24180 : case AF_INET6:
465 24180 : str = inet_ntop(bsda->u.in6.sin6_family,
466 24180 : &bsda->u.in6.sin6_addr,
467 : addr_str, sizeof(addr_str));
468 24180 : break;
469 : #endif
470 0 : default:
471 0 : errno = EINVAL;
472 0 : return NULL;
473 : }
474 :
475 847348 : if (!str) {
476 0 : return NULL;
477 : }
478 :
479 847348 : return talloc_strdup(mem_ctx, str);
480 : }
481 :
482 672439 : uint16_t tsocket_address_inet_port(const struct tsocket_address *addr)
483 : {
484 672439 : struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
485 : struct samba_sockaddr);
486 672439 : uint16_t port = 0;
487 :
488 672439 : if (!bsda) {
489 0 : errno = EINVAL;
490 0 : return 0;
491 : }
492 :
493 672439 : switch (bsda->u.sa.sa_family) {
494 660792 : case AF_INET:
495 660792 : port = ntohs(bsda->u.in.sin_port);
496 643950 : break;
497 : #ifdef HAVE_IPV6
498 11647 : case AF_INET6:
499 11647 : port = ntohs(bsda->u.in6.sin6_port);
500 11634 : break;
501 : #endif
502 0 : default:
503 0 : errno = EINVAL;
504 0 : return 0;
505 : }
506 :
507 655584 : return port;
508 : }
509 :
510 0 : int tsocket_address_inet_set_port(struct tsocket_address *addr,
511 : uint16_t port)
512 : {
513 0 : struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
514 : struct samba_sockaddr);
515 :
516 0 : if (!bsda) {
517 0 : errno = EINVAL;
518 0 : return -1;
519 : }
520 :
521 0 : switch (bsda->u.sa.sa_family) {
522 0 : case AF_INET:
523 0 : bsda->u.in.sin_port = htons(port);
524 0 : break;
525 : #ifdef HAVE_IPV6
526 0 : case AF_INET6:
527 0 : bsda->u.in6.sin6_port = htons(port);
528 0 : break;
529 : #endif
530 0 : default:
531 0 : errno = EINVAL;
532 0 : return -1;
533 : }
534 :
535 0 : return 0;
536 : }
537 :
538 0 : bool tsocket_address_is_unix(const struct tsocket_address *addr)
539 : {
540 0 : struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
541 : struct samba_sockaddr);
542 :
543 0 : if (!bsda) {
544 0 : return false;
545 : }
546 :
547 0 : switch (bsda->u.sa.sa_family) {
548 0 : case AF_UNIX:
549 0 : return true;
550 : }
551 :
552 0 : return false;
553 : }
554 :
555 21847 : int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
556 : const char *path,
557 : struct tsocket_address **_addr,
558 : const char *location)
559 : {
560 : struct sockaddr_un un;
561 21847 : void *p = &un;
562 : int ret;
563 :
564 21847 : if (!path) {
565 764 : path = "";
566 : }
567 :
568 21847 : if (strlen(path) > sizeof(un.sun_path)-1) {
569 0 : errno = ENAMETOOLONG;
570 0 : return -1;
571 : }
572 :
573 21847 : ZERO_STRUCT(un);
574 21847 : un.sun_family = AF_UNIX;
575 21847 : strncpy(un.sun_path, path, sizeof(un.sun_path)-1);
576 :
577 21847 : ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
578 : (struct sockaddr *)p,
579 : sizeof(un),
580 : _addr,
581 : location);
582 :
583 21847 : return ret;
584 : }
585 :
586 2592 : char *tsocket_address_unix_path(const struct tsocket_address *addr,
587 : TALLOC_CTX *mem_ctx)
588 : {
589 2592 : struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
590 : struct samba_sockaddr);
591 : const char *str;
592 :
593 2592 : if (!bsda) {
594 0 : errno = EINVAL;
595 0 : return NULL;
596 : }
597 :
598 2592 : switch (bsda->u.sa.sa_family) {
599 2592 : case AF_UNIX:
600 2592 : str = bsda->u.un.sun_path;
601 2584 : break;
602 0 : default:
603 0 : errno = EINVAL;
604 0 : return NULL;
605 : }
606 :
607 2592 : return talloc_strdup(mem_ctx, str);
608 : }
609 :
610 636168 : static char *tsocket_address_bsd_string(const struct tsocket_address *addr,
611 : TALLOC_CTX *mem_ctx)
612 : {
613 636168 : struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
614 : struct samba_sockaddr);
615 : char *str;
616 : char *addr_str;
617 636168 : const char *prefix = NULL;
618 : uint16_t port;
619 :
620 636168 : switch (bsda->u.sa.sa_family) {
621 22854 : case AF_UNIX:
622 22854 : return talloc_asprintf(mem_ctx, "unix:%s",
623 22854 : bsda->u.un.sun_path);
624 587175 : case AF_INET:
625 587175 : prefix = "ipv4";
626 587175 : break;
627 : #ifdef HAVE_IPV6
628 11331 : case AF_INET6:
629 11331 : prefix = "ipv6";
630 11331 : break;
631 : #endif
632 0 : default:
633 0 : errno = EINVAL;
634 0 : return NULL;
635 : }
636 :
637 613314 : addr_str = tsocket_address_inet_addr_string(addr, mem_ctx);
638 613314 : if (!addr_str) {
639 0 : return NULL;
640 : }
641 :
642 613314 : port = tsocket_address_inet_port(addr);
643 :
644 613314 : str = talloc_asprintf(mem_ctx, "%s:%s:%u",
645 : prefix, addr_str, port);
646 613314 : talloc_free(addr_str);
647 :
648 613314 : return str;
649 : }
650 :
651 400717 : static struct tsocket_address *tsocket_address_bsd_copy(const struct tsocket_address *addr,
652 : TALLOC_CTX *mem_ctx,
653 : const char *location)
654 : {
655 400717 : struct samba_sockaddr *bsda = talloc_get_type(addr->private_data,
656 : struct samba_sockaddr);
657 : struct tsocket_address *copy;
658 : int ret;
659 :
660 744704 : ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
661 400717 : &bsda->u.sa,
662 400717 : bsda->sa_socklen,
663 : ©,
664 : location);
665 400717 : if (ret != 0) {
666 0 : return NULL;
667 : }
668 :
669 400717 : return copy;
670 : }
671 :
672 : static const struct tsocket_address_ops tsocket_address_bsd_ops = {
673 : .name = "bsd",
674 : .string = tsocket_address_bsd_string,
675 : .copy = tsocket_address_bsd_copy,
676 : };
677 :
678 : struct tdgram_bsd {
679 : int fd;
680 :
681 : void *event_ptr;
682 : struct tevent_fd *fde;
683 : bool optimize_recvfrom;
684 : bool netlink;
685 :
686 : void *readable_private;
687 : void (*readable_handler)(void *private_data);
688 : void *writeable_private;
689 : void (*writeable_handler)(void *private_data);
690 : };
691 :
692 0 : bool tdgram_bsd_optimize_recvfrom(struct tdgram_context *dgram,
693 : bool on)
694 : {
695 0 : struct tdgram_bsd *bsds =
696 0 : talloc_get_type(_tdgram_context_data(dgram),
697 : struct tdgram_bsd);
698 : bool old;
699 :
700 0 : if (bsds == NULL) {
701 : /* not a bsd socket */
702 0 : return false;
703 : }
704 :
705 0 : old = bsds->optimize_recvfrom;
706 0 : bsds->optimize_recvfrom = on;
707 :
708 0 : return old;
709 : }
710 :
711 135225 : static void tdgram_bsd_fde_handler(struct tevent_context *ev,
712 : struct tevent_fd *fde,
713 : uint16_t flags,
714 : void *private_data)
715 : {
716 135225 : struct tdgram_bsd *bsds = talloc_get_type_abort(private_data,
717 : struct tdgram_bsd);
718 :
719 135225 : if (flags & TEVENT_FD_WRITE) {
720 0 : bsds->writeable_handler(bsds->writeable_private);
721 0 : return;
722 : }
723 135225 : if (flags & TEVENT_FD_READ) {
724 135225 : if (!bsds->readable_handler) {
725 0 : TEVENT_FD_NOT_READABLE(bsds->fde);
726 0 : return;
727 : }
728 135225 : bsds->readable_handler(bsds->readable_private);
729 135225 : return;
730 : }
731 : }
732 :
733 254737 : static int tdgram_bsd_set_readable_handler(struct tdgram_bsd *bsds,
734 : struct tevent_context *ev,
735 : void (*handler)(void *private_data),
736 : void *private_data)
737 : {
738 254737 : if (ev == NULL) {
739 127213 : if (handler) {
740 0 : errno = EINVAL;
741 0 : return -1;
742 : }
743 128035 : if (!bsds->readable_handler) {
744 0 : return 0;
745 : }
746 128035 : bsds->readable_handler = NULL;
747 128035 : bsds->readable_private = NULL;
748 :
749 127213 : return 0;
750 : }
751 :
752 : /* read and write must use the same tevent_context */
753 127524 : if (bsds->event_ptr != ev) {
754 6100 : if (bsds->readable_handler || bsds->writeable_handler) {
755 0 : errno = EINVAL;
756 0 : return -1;
757 : }
758 6100 : bsds->event_ptr = NULL;
759 6100 : TALLOC_FREE(bsds->fde);
760 : }
761 :
762 127524 : if (tevent_fd_get_flags(bsds->fde) == 0) {
763 6388 : TALLOC_FREE(bsds->fde);
764 :
765 6388 : bsds->fde = tevent_add_fd(ev, bsds,
766 : bsds->fd, TEVENT_FD_READ,
767 : tdgram_bsd_fde_handler,
768 : bsds);
769 6388 : if (!bsds->fde) {
770 0 : errno = ENOMEM;
771 0 : return -1;
772 : }
773 :
774 : /* cache the event context we're running on */
775 6388 : bsds->event_ptr = ev;
776 121136 : } else if (!bsds->readable_handler) {
777 121136 : TEVENT_FD_READABLE(bsds->fde);
778 : }
779 :
780 127524 : bsds->readable_handler = handler;
781 127524 : bsds->readable_private = private_data;
782 :
783 127524 : return 0;
784 : }
785 :
786 126537 : static int tdgram_bsd_set_writeable_handler(struct tdgram_bsd *bsds,
787 : struct tevent_context *ev,
788 : void (*handler)(void *private_data),
789 : void *private_data)
790 : {
791 126537 : if (ev == NULL) {
792 126537 : if (handler) {
793 0 : errno = EINVAL;
794 0 : return -1;
795 : }
796 126537 : if (!bsds->writeable_handler) {
797 125807 : return 0;
798 : }
799 0 : bsds->writeable_handler = NULL;
800 0 : bsds->writeable_private = NULL;
801 0 : TEVENT_FD_NOT_WRITEABLE(bsds->fde);
802 :
803 0 : return 0;
804 : }
805 :
806 : /* read and write must use the same tevent_context */
807 0 : if (bsds->event_ptr != ev) {
808 0 : if (bsds->readable_handler || bsds->writeable_handler) {
809 0 : errno = EINVAL;
810 0 : return -1;
811 : }
812 0 : bsds->event_ptr = NULL;
813 0 : TALLOC_FREE(bsds->fde);
814 : }
815 :
816 0 : if (tevent_fd_get_flags(bsds->fde) == 0) {
817 0 : TALLOC_FREE(bsds->fde);
818 :
819 0 : bsds->fde = tevent_add_fd(ev, bsds,
820 : bsds->fd, TEVENT_FD_WRITE,
821 : tdgram_bsd_fde_handler,
822 : bsds);
823 0 : if (!bsds->fde) {
824 0 : errno = ENOMEM;
825 0 : return -1;
826 : }
827 :
828 : /* cache the event context we're running on */
829 0 : bsds->event_ptr = ev;
830 0 : } else if (!bsds->writeable_handler) {
831 0 : TEVENT_FD_WRITEABLE(bsds->fde);
832 : }
833 :
834 0 : bsds->writeable_handler = handler;
835 0 : bsds->writeable_private = private_data;
836 :
837 0 : return 0;
838 : }
839 :
840 : struct tdgram_bsd_recvfrom_state {
841 : struct tdgram_context *dgram;
842 : bool first_try;
843 : uint8_t *buf;
844 : size_t len;
845 : struct tsocket_address *src;
846 : };
847 :
848 128035 : static int tdgram_bsd_recvfrom_destructor(struct tdgram_bsd_recvfrom_state *state)
849 : {
850 128035 : struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
851 : struct tdgram_bsd);
852 :
853 128035 : tdgram_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
854 :
855 128035 : return 0;
856 : }
857 :
858 : static void tdgram_bsd_recvfrom_handler(void *private_data);
859 :
860 127524 : static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx,
861 : struct tevent_context *ev,
862 : struct tdgram_context *dgram)
863 : {
864 : struct tevent_req *req;
865 : struct tdgram_bsd_recvfrom_state *state;
866 127524 : struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
867 : int ret;
868 :
869 127524 : req = tevent_req_create(mem_ctx, &state,
870 : struct tdgram_bsd_recvfrom_state);
871 127524 : if (!req) {
872 0 : return NULL;
873 : }
874 :
875 127524 : state->dgram = dgram;
876 127524 : state->first_try= true;
877 127524 : state->buf = NULL;
878 127524 : state->len = 0;
879 127524 : state->src = NULL;
880 :
881 127524 : talloc_set_destructor(state, tdgram_bsd_recvfrom_destructor);
882 :
883 127524 : if (bsds->fd == -1) {
884 0 : tevent_req_error(req, ENOTCONN);
885 0 : goto post;
886 : }
887 :
888 :
889 : /*
890 : * this is a fast path, not waiting for the
891 : * socket to become explicit readable gains
892 : * about 10%-20% performance in benchmark tests.
893 : */
894 127524 : if (bsds->optimize_recvfrom) {
895 : /*
896 : * We only do the optimization on
897 : * recvfrom if the caller asked for it.
898 : *
899 : * This is needed because in most cases
900 : * we prefer to flush send buffers before
901 : * receiving incoming requests.
902 : */
903 0 : tdgram_bsd_recvfrom_handler(req);
904 0 : if (!tevent_req_is_in_progress(req)) {
905 0 : goto post;
906 : }
907 : }
908 :
909 127524 : ret = tdgram_bsd_set_readable_handler(bsds, ev,
910 : tdgram_bsd_recvfrom_handler,
911 : req);
912 127524 : if (ret == -1) {
913 0 : tevent_req_error(req, errno);
914 0 : goto post;
915 : }
916 :
917 126760 : return req;
918 :
919 0 : post:
920 0 : tevent_req_post(req, ev);
921 0 : return req;
922 : }
923 :
924 135225 : static void tdgram_bsd_recvfrom_handler(void *private_data)
925 : {
926 135225 : struct tevent_req *req = talloc_get_type_abort(private_data,
927 : struct tevent_req);
928 135225 : struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
929 : struct tdgram_bsd_recvfrom_state);
930 135225 : struct tdgram_context *dgram = state->dgram;
931 135225 : struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
932 135225 : struct samba_sockaddr *bsda = NULL;
933 : ssize_t ret;
934 : int err;
935 : bool retry;
936 :
937 135225 : if (bsds->netlink) {
938 0 : ret = tsocket_bsd_netlink_pending(bsds->fd);
939 : } else {
940 135225 : ret = tsocket_bsd_pending(bsds->fd);
941 : }
942 :
943 135225 : if (state->first_try && ret == 0) {
944 968 : state->first_try = false;
945 : /* retry later */
946 10082 : return;
947 : }
948 134257 : state->first_try = false;
949 :
950 134257 : err = tsocket_bsd_error_from_errno(ret, errno, &retry);
951 133520 : if (retry) {
952 : /* retry later */
953 0 : return;
954 : }
955 134257 : if (tevent_req_error(req, err)) {
956 0 : return;
957 : }
958 :
959 : /* note that 'ret' can be 0 here */
960 134257 : state->buf = talloc_array(state, uint8_t, ret);
961 134257 : if (tevent_req_nomem(state->buf, req)) {
962 0 : return;
963 : }
964 134257 : state->len = ret;
965 :
966 134257 : state->src = tsocket_address_create(state,
967 : &tsocket_address_bsd_ops,
968 : &bsda,
969 : struct samba_sockaddr,
970 : __location__ "bsd_recvfrom");
971 134257 : if (tevent_req_nomem(state->src, req)) {
972 0 : return;
973 : }
974 :
975 134257 : ZERO_STRUCTP(bsda);
976 134257 : bsda->sa_socklen = sizeof(bsda->u.ss);
977 : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
978 : bsda->u.sa.sa_len = bsda->sa_socklen;
979 : #endif
980 :
981 214479 : ret = recvfrom(bsds->fd, state->buf, state->len, 0,
982 213005 : &bsda->u.sa, &bsda->sa_socklen);
983 134257 : err = tsocket_bsd_error_from_errno(ret, errno, &retry);
984 133520 : if (retry) {
985 : /* retry later */
986 8135 : return;
987 : }
988 126115 : if (tevent_req_error(req, err)) {
989 0 : return;
990 : }
991 :
992 : /*
993 : * Some systems (FreeBSD, see bug #7115) return too much
994 : * bytes in tsocket_bsd_pending()/ioctl(fd, FIONREAD, ...),
995 : * the return value includes some IP/UDP header bytes,
996 : * while recvfrom() just returns the payload.
997 : */
998 126115 : state->buf = talloc_realloc(state, state->buf, uint8_t, ret);
999 126115 : if (tevent_req_nomem(state->buf, req)) {
1000 6 : return;
1001 : }
1002 126109 : state->len = ret;
1003 :
1004 126109 : tevent_req_done(req);
1005 : }
1006 :
1007 126115 : static ssize_t tdgram_bsd_recvfrom_recv(struct tevent_req *req,
1008 : int *perrno,
1009 : TALLOC_CTX *mem_ctx,
1010 : uint8_t **buf,
1011 : struct tsocket_address **src)
1012 : {
1013 126115 : struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
1014 : struct tdgram_bsd_recvfrom_state);
1015 : ssize_t ret;
1016 :
1017 126115 : ret = tsocket_simple_int_recv(req, perrno);
1018 126115 : if (ret == 0) {
1019 126109 : *buf = talloc_move(mem_ctx, &state->buf);
1020 126109 : ret = state->len;
1021 126109 : if (src) {
1022 126109 : *src = talloc_move(mem_ctx, &state->src);
1023 : }
1024 : }
1025 :
1026 126115 : tevent_req_received(req);
1027 126115 : return ret;
1028 : }
1029 :
1030 : struct tdgram_bsd_sendto_state {
1031 : struct tdgram_context *dgram;
1032 :
1033 : const uint8_t *buf;
1034 : size_t len;
1035 : const struct tsocket_address *dst;
1036 :
1037 : ssize_t ret;
1038 : };
1039 :
1040 126537 : static int tdgram_bsd_sendto_destructor(struct tdgram_bsd_sendto_state *state)
1041 : {
1042 126537 : struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
1043 : struct tdgram_bsd);
1044 :
1045 126537 : tdgram_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
1046 :
1047 126537 : return 0;
1048 : }
1049 :
1050 : static void tdgram_bsd_sendto_handler(void *private_data);
1051 :
1052 126537 : static struct tevent_req *tdgram_bsd_sendto_send(TALLOC_CTX *mem_ctx,
1053 : struct tevent_context *ev,
1054 : struct tdgram_context *dgram,
1055 : const uint8_t *buf,
1056 : size_t len,
1057 : const struct tsocket_address *dst)
1058 : {
1059 : struct tevent_req *req;
1060 : struct tdgram_bsd_sendto_state *state;
1061 126537 : struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
1062 : int ret;
1063 :
1064 126537 : req = tevent_req_create(mem_ctx, &state,
1065 : struct tdgram_bsd_sendto_state);
1066 126537 : if (!req) {
1067 0 : return NULL;
1068 : }
1069 :
1070 126537 : state->dgram = dgram;
1071 126537 : state->buf = buf;
1072 126537 : state->len = len;
1073 126537 : state->dst = dst;
1074 126537 : state->ret = -1;
1075 :
1076 126537 : talloc_set_destructor(state, tdgram_bsd_sendto_destructor);
1077 :
1078 126537 : if (bsds->fd == -1) {
1079 0 : tevent_req_error(req, ENOTCONN);
1080 0 : goto post;
1081 : }
1082 :
1083 : /*
1084 : * this is a fast path, not waiting for the
1085 : * socket to become explicit writeable gains
1086 : * about 10%-20% performance in benchmark tests.
1087 : */
1088 126537 : tdgram_bsd_sendto_handler(req);
1089 126537 : if (!tevent_req_is_in_progress(req)) {
1090 125807 : goto post;
1091 : }
1092 :
1093 0 : ret = tdgram_bsd_set_writeable_handler(bsds, ev,
1094 : tdgram_bsd_sendto_handler,
1095 : req);
1096 0 : if (ret == -1) {
1097 0 : tevent_req_error(req, errno);
1098 0 : goto post;
1099 : }
1100 :
1101 0 : return req;
1102 :
1103 127267 : post:
1104 126537 : tevent_req_post(req, ev);
1105 126537 : return req;
1106 : }
1107 :
1108 126537 : static void tdgram_bsd_sendto_handler(void *private_data)
1109 : {
1110 126537 : struct tevent_req *req = talloc_get_type_abort(private_data,
1111 : struct tevent_req);
1112 126537 : struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
1113 : struct tdgram_bsd_sendto_state);
1114 126537 : struct tdgram_context *dgram = state->dgram;
1115 126537 : struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
1116 126537 : struct sockaddr *sa = NULL;
1117 126537 : socklen_t sa_socklen = 0;
1118 : ssize_t ret;
1119 : int err;
1120 : bool retry;
1121 :
1122 126537 : if (state->dst) {
1123 68189 : struct samba_sockaddr *bsda =
1124 121801 : talloc_get_type(state->dst->private_data,
1125 : struct samba_sockaddr);
1126 :
1127 121801 : sa = &bsda->u.sa;
1128 121801 : sa_socklen = bsda->sa_socklen;
1129 : }
1130 :
1131 126537 : ret = sendto(bsds->fd, state->buf, state->len, 0, sa, sa_socklen);
1132 126537 : err = tsocket_bsd_error_from_errno(ret, errno, &retry);
1133 125807 : if (retry) {
1134 : /* retry later */
1135 60 : return;
1136 : }
1137 :
1138 126537 : if (err == EMSGSIZE) {
1139 : /* round up in 1K increments */
1140 0 : int bufsize = ((state->len + 1023) & (~1023));
1141 :
1142 0 : ret = setsockopt(bsds->fd, SOL_SOCKET, SO_SNDBUF, &bufsize,
1143 : sizeof(bufsize));
1144 0 : if (ret == 0) {
1145 : /*
1146 : * We do the retry here, rather then via the
1147 : * handler, as we only want to retry once for
1148 : * this condition, so if there is a mismatch
1149 : * between what setsockopt() accepts and what can
1150 : * actually be sent, we do not end up in a
1151 : * loop.
1152 : */
1153 :
1154 0 : ret = sendto(bsds->fd, state->buf, state->len,
1155 : 0, sa, sa_socklen);
1156 0 : err = tsocket_bsd_error_from_errno(ret, errno, &retry);
1157 0 : if (retry) { /* retry later */
1158 0 : return;
1159 : }
1160 : }
1161 : }
1162 :
1163 126537 : if (tevent_req_error(req, err)) {
1164 60 : return;
1165 : }
1166 :
1167 126477 : state->ret = ret;
1168 :
1169 126477 : tevent_req_done(req);
1170 : }
1171 :
1172 126537 : static ssize_t tdgram_bsd_sendto_recv(struct tevent_req *req, int *perrno)
1173 : {
1174 126537 : struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
1175 : struct tdgram_bsd_sendto_state);
1176 : ssize_t ret;
1177 :
1178 126537 : ret = tsocket_simple_int_recv(req, perrno);
1179 126537 : if (ret == 0) {
1180 126477 : ret = state->ret;
1181 : }
1182 :
1183 126537 : tevent_req_received(req);
1184 126537 : return ret;
1185 : }
1186 :
1187 : struct tdgram_bsd_disconnect_state {
1188 : uint8_t __dummy;
1189 : };
1190 :
1191 0 : static struct tevent_req *tdgram_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
1192 : struct tevent_context *ev,
1193 : struct tdgram_context *dgram)
1194 : {
1195 0 : struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
1196 : struct tevent_req *req;
1197 : struct tdgram_bsd_disconnect_state *state;
1198 : int ret;
1199 : int err;
1200 : bool dummy;
1201 :
1202 0 : req = tevent_req_create(mem_ctx, &state,
1203 : struct tdgram_bsd_disconnect_state);
1204 0 : if (req == NULL) {
1205 0 : return NULL;
1206 : }
1207 :
1208 0 : if (bsds->fd == -1) {
1209 0 : tevent_req_error(req, ENOTCONN);
1210 0 : goto post;
1211 : }
1212 :
1213 0 : TALLOC_FREE(bsds->fde);
1214 0 : ret = close(bsds->fd);
1215 0 : bsds->fd = -1;
1216 0 : err = tsocket_bsd_error_from_errno(ret, errno, &dummy);
1217 0 : if (tevent_req_error(req, err)) {
1218 0 : goto post;
1219 : }
1220 :
1221 0 : tevent_req_done(req);
1222 0 : post:
1223 0 : tevent_req_post(req, ev);
1224 0 : return req;
1225 : }
1226 :
1227 0 : static int tdgram_bsd_disconnect_recv(struct tevent_req *req,
1228 : int *perrno)
1229 : {
1230 : int ret;
1231 :
1232 0 : ret = tsocket_simple_int_recv(req, perrno);
1233 :
1234 0 : tevent_req_received(req);
1235 0 : return ret;
1236 : }
1237 :
1238 : static const struct tdgram_context_ops tdgram_bsd_ops = {
1239 : .name = "bsd",
1240 :
1241 : .recvfrom_send = tdgram_bsd_recvfrom_send,
1242 : .recvfrom_recv = tdgram_bsd_recvfrom_recv,
1243 :
1244 : .sendto_send = tdgram_bsd_sendto_send,
1245 : .sendto_recv = tdgram_bsd_sendto_recv,
1246 :
1247 : .disconnect_send = tdgram_bsd_disconnect_send,
1248 : .disconnect_recv = tdgram_bsd_disconnect_recv,
1249 : };
1250 :
1251 6603 : static int tdgram_bsd_destructor(struct tdgram_bsd *bsds)
1252 : {
1253 6603 : TALLOC_FREE(bsds->fde);
1254 6603 : if (bsds->fd != -1) {
1255 6603 : close(bsds->fd);
1256 6603 : bsds->fd = -1;
1257 : }
1258 6603 : return 0;
1259 : }
1260 :
1261 6019 : static int tdgram_bsd_dgram_socket(const struct tsocket_address *local,
1262 : const struct tsocket_address *remote,
1263 : bool broadcast,
1264 : TALLOC_CTX *mem_ctx,
1265 : struct tdgram_context **_dgram,
1266 : const char *location)
1267 : {
1268 4511 : struct samba_sockaddr *lbsda =
1269 6019 : talloc_get_type_abort(local->private_data,
1270 : struct samba_sockaddr);
1271 6019 : struct samba_sockaddr *rbsda = NULL;
1272 : struct tdgram_context *dgram;
1273 : struct tdgram_bsd *bsds;
1274 : int fd;
1275 : int ret;
1276 6019 : bool do_bind = false;
1277 6019 : bool do_reuseaddr = false;
1278 6019 : bool do_ipv6only = false;
1279 6019 : bool is_inet = false;
1280 6019 : int sa_fam = lbsda->u.sa.sa_family;
1281 :
1282 6019 : if (remote) {
1283 4420 : rbsda = talloc_get_type_abort(remote->private_data,
1284 : struct samba_sockaddr);
1285 : }
1286 :
1287 6019 : switch (lbsda->u.sa.sa_family) {
1288 0 : case AF_UNIX:
1289 0 : if (broadcast) {
1290 0 : errno = EINVAL;
1291 0 : return -1;
1292 : }
1293 0 : if (lbsda->u.un.sun_path[0] != 0) {
1294 0 : do_reuseaddr = true;
1295 0 : do_bind = true;
1296 : }
1297 0 : break;
1298 2481 : case AF_INET:
1299 2481 : if (lbsda->u.in.sin_port != 0) {
1300 428 : do_reuseaddr = true;
1301 428 : do_bind = true;
1302 : }
1303 2481 : if (lbsda->u.in.sin_addr.s_addr != INADDR_ANY) {
1304 216 : do_bind = true;
1305 : }
1306 2429 : is_inet = true;
1307 2429 : break;
1308 : #ifdef HAVE_IPV6
1309 3538 : case AF_INET6:
1310 3538 : if (lbsda->u.in6.sin6_port != 0) {
1311 412 : do_reuseaddr = true;
1312 412 : do_bind = true;
1313 : }
1314 3538 : if (memcmp(&in6addr_any,
1315 3538 : &lbsda->u.in6.sin6_addr,
1316 : sizeof(in6addr_any)) != 0) {
1317 200 : do_bind = true;
1318 : }
1319 3522 : is_inet = true;
1320 3522 : do_ipv6only = true;
1321 3522 : break;
1322 : #endif
1323 0 : default:
1324 0 : errno = EINVAL;
1325 0 : return -1;
1326 : }
1327 :
1328 6019 : if (!do_bind && is_inet && rbsda) {
1329 4420 : sa_fam = rbsda->u.sa.sa_family;
1330 4420 : switch (sa_fam) {
1331 2798 : case AF_INET:
1332 2798 : do_ipv6only = false;
1333 2798 : break;
1334 : #ifdef HAVE_IPV6
1335 1622 : case AF_INET6:
1336 1622 : do_ipv6only = true;
1337 1622 : break;
1338 : #endif
1339 : }
1340 : }
1341 :
1342 6019 : fd = socket(sa_fam, SOCK_DGRAM, 0);
1343 6019 : if (fd < 0) {
1344 0 : return -1;
1345 : }
1346 :
1347 6019 : fd = tsocket_bsd_common_prepare_fd(fd, true);
1348 6019 : if (fd < 0) {
1349 0 : return -1;
1350 : }
1351 :
1352 6019 : dgram = tdgram_context_create(mem_ctx,
1353 : &tdgram_bsd_ops,
1354 : &bsds,
1355 : struct tdgram_bsd,
1356 : location);
1357 6019 : if (!dgram) {
1358 0 : int saved_errno = errno;
1359 0 : close(fd);
1360 0 : errno = saved_errno;
1361 0 : return -1;
1362 : }
1363 6019 : ZERO_STRUCTP(bsds);
1364 6019 : bsds->fd = fd;
1365 6019 : talloc_set_destructor(bsds, tdgram_bsd_destructor);
1366 :
1367 : #ifdef HAVE_IPV6
1368 6019 : if (do_ipv6only) {
1369 2034 : int val = 1;
1370 :
1371 2034 : ret = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
1372 : (const void *)&val, sizeof(val));
1373 2034 : if (ret == -1) {
1374 0 : int saved_errno = errno;
1375 0 : talloc_free(dgram);
1376 0 : errno = saved_errno;
1377 0 : return -1;
1378 : }
1379 : }
1380 : #endif
1381 :
1382 6019 : if (broadcast) {
1383 759 : int val = 1;
1384 :
1385 759 : ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
1386 : (const void *)&val, sizeof(val));
1387 759 : if (ret == -1) {
1388 0 : int saved_errno = errno;
1389 0 : talloc_free(dgram);
1390 0 : errno = saved_errno;
1391 0 : return -1;
1392 : }
1393 : }
1394 :
1395 6019 : if (do_reuseaddr) {
1396 840 : int val = 1;
1397 :
1398 840 : ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
1399 : (const void *)&val, sizeof(val));
1400 840 : if (ret == -1) {
1401 0 : int saved_errno = errno;
1402 0 : talloc_free(dgram);
1403 0 : errno = saved_errno;
1404 0 : return -1;
1405 : }
1406 : }
1407 :
1408 6019 : if (do_bind) {
1409 840 : ret = bind(fd, &lbsda->u.sa, lbsda->sa_socklen);
1410 840 : if (ret == -1) {
1411 0 : int saved_errno = errno;
1412 0 : talloc_free(dgram);
1413 0 : errno = saved_errno;
1414 0 : return -1;
1415 : }
1416 : }
1417 :
1418 6019 : if (rbsda) {
1419 4420 : if (rbsda->u.sa.sa_family != sa_fam) {
1420 0 : talloc_free(dgram);
1421 0 : errno = EINVAL;
1422 0 : return -1;
1423 : }
1424 :
1425 4420 : ret = connect(fd, &rbsda->u.sa, rbsda->sa_socklen);
1426 4420 : if (ret == -1) {
1427 0 : int saved_errno = errno;
1428 0 : talloc_free(dgram);
1429 0 : errno = saved_errno;
1430 0 : return -1;
1431 : }
1432 : }
1433 :
1434 6019 : *_dgram = dgram;
1435 6019 : return 0;
1436 : }
1437 :
1438 73 : int _tdgram_bsd_existing_socket(TALLOC_CTX *mem_ctx,
1439 : int fd,
1440 : struct tdgram_context **_dgram,
1441 : const char *location)
1442 : {
1443 : struct tdgram_context *dgram;
1444 : struct tdgram_bsd *bsds;
1445 : #ifdef HAVE_LINUX_RTNETLINK_H
1446 : int result;
1447 : struct sockaddr sa;
1448 73 : socklen_t sa_len = sizeof(struct sockaddr);
1449 : #endif
1450 :
1451 73 : dgram = tdgram_context_create(mem_ctx,
1452 : &tdgram_bsd_ops,
1453 : &bsds,
1454 : struct tdgram_bsd,
1455 : location);
1456 73 : if (!dgram) {
1457 0 : return -1;
1458 : }
1459 73 : ZERO_STRUCTP(bsds);
1460 73 : bsds->fd = fd;
1461 73 : talloc_set_destructor(bsds, tdgram_bsd_destructor);
1462 :
1463 73 : *_dgram = dgram;
1464 :
1465 : #ifdef HAVE_LINUX_RTNETLINK_H
1466 : /*
1467 : * Try to determine the protocol family and remember if it's
1468 : * AF_NETLINK. We don't care if this fails.
1469 : */
1470 73 : result = getsockname(fd, &sa, &sa_len);
1471 73 : if (result == 0 && sa.sa_family == AF_NETLINK) {
1472 73 : bsds->netlink = true;
1473 : }
1474 : #endif
1475 :
1476 71 : return 0;
1477 : }
1478 :
1479 5260 : int _tdgram_inet_udp_socket(const struct tsocket_address *local,
1480 : const struct tsocket_address *remote,
1481 : TALLOC_CTX *mem_ctx,
1482 : struct tdgram_context **dgram,
1483 : const char *location)
1484 : {
1485 3853 : struct samba_sockaddr *lbsda =
1486 5260 : talloc_get_type_abort(local->private_data,
1487 : struct samba_sockaddr);
1488 : int ret;
1489 :
1490 5260 : switch (lbsda->u.sa.sa_family) {
1491 1670 : case AF_INET:
1492 1670 : break;
1493 : #ifdef HAVE_IPV6
1494 3522 : case AF_INET6:
1495 3522 : break;
1496 : #endif
1497 0 : default:
1498 0 : errno = EINVAL;
1499 0 : return -1;
1500 : }
1501 :
1502 5260 : ret = tdgram_bsd_dgram_socket(local, remote, false,
1503 : mem_ctx, dgram, location);
1504 :
1505 5260 : return ret;
1506 : }
1507 :
1508 759 : int _tdgram_inet_udp_broadcast_socket(const struct tsocket_address *local,
1509 : TALLOC_CTX *mem_ctx,
1510 : struct tdgram_context **dgram,
1511 : const char *location)
1512 : {
1513 658 : struct samba_sockaddr *lbsda =
1514 759 : talloc_get_type_abort(local->private_data,
1515 : struct samba_sockaddr);
1516 : int ret;
1517 :
1518 759 : switch (lbsda->u.sa.sa_family) {
1519 759 : case AF_INET:
1520 759 : break;
1521 : #ifdef HAVE_IPV6
1522 0 : case AF_INET6:
1523 : /* only ipv4 */
1524 0 : errno = EINVAL;
1525 0 : return -1;
1526 : #endif
1527 0 : default:
1528 0 : errno = EINVAL;
1529 0 : return -1;
1530 : }
1531 :
1532 759 : ret = tdgram_bsd_dgram_socket(local, NULL, true,
1533 : mem_ctx, dgram, location);
1534 :
1535 759 : return ret;
1536 : }
1537 :
1538 0 : int _tdgram_unix_socket(const struct tsocket_address *local,
1539 : const struct tsocket_address *remote,
1540 : TALLOC_CTX *mem_ctx,
1541 : struct tdgram_context **dgram,
1542 : const char *location)
1543 : {
1544 0 : struct samba_sockaddr *lbsda =
1545 0 : talloc_get_type_abort(local->private_data,
1546 : struct samba_sockaddr);
1547 : int ret;
1548 :
1549 0 : switch (lbsda->u.sa.sa_family) {
1550 0 : case AF_UNIX:
1551 0 : break;
1552 0 : default:
1553 0 : errno = EINVAL;
1554 0 : return -1;
1555 : }
1556 :
1557 0 : ret = tdgram_bsd_dgram_socket(local, remote, false,
1558 : mem_ctx, dgram, location);
1559 :
1560 0 : return ret;
1561 : }
1562 :
1563 : struct tstream_bsd {
1564 : int fd;
1565 :
1566 : void *event_ptr;
1567 : struct tevent_fd *fde;
1568 : bool optimize_readv;
1569 :
1570 : void *readable_private;
1571 : void (*readable_handler)(void *private_data);
1572 : void *writeable_private;
1573 : void (*writeable_handler)(void *private_data);
1574 : };
1575 :
1576 5637852 : bool tstream_bsd_optimize_readv(struct tstream_context *stream,
1577 : bool on)
1578 : {
1579 4587540 : struct tstream_bsd *bsds =
1580 5637852 : talloc_get_type(_tstream_context_data(stream),
1581 : struct tstream_bsd);
1582 : bool old;
1583 :
1584 5637852 : if (bsds == NULL) {
1585 : /* not a bsd socket */
1586 1801032 : return false;
1587 : }
1588 :
1589 3796722 : old = bsds->optimize_readv;
1590 3796722 : bsds->optimize_readv = on;
1591 :
1592 3796722 : return old;
1593 : }
1594 :
1595 16884368 : static void tstream_bsd_fde_handler(struct tevent_context *ev,
1596 : struct tevent_fd *fde,
1597 : uint16_t flags,
1598 : void *private_data)
1599 : {
1600 16884368 : struct tstream_bsd *bsds = talloc_get_type_abort(private_data,
1601 : struct tstream_bsd);
1602 :
1603 16884368 : if (flags & TEVENT_FD_WRITE) {
1604 6156509 : bsds->writeable_handler(bsds->writeable_private);
1605 6156509 : return;
1606 : }
1607 10727859 : if (flags & TEVENT_FD_READ) {
1608 10727859 : if (!bsds->readable_handler) {
1609 7194 : if (bsds->writeable_handler) {
1610 0 : bsds->writeable_handler(bsds->writeable_private);
1611 0 : return;
1612 : }
1613 7194 : TEVENT_FD_NOT_READABLE(bsds->fde);
1614 7194 : return;
1615 : }
1616 10720665 : bsds->readable_handler(bsds->readable_private);
1617 10720358 : return;
1618 : }
1619 : }
1620 :
1621 13409071 : static int tstream_bsd_set_readable_handler(struct tstream_bsd *bsds,
1622 : struct tevent_context *ev,
1623 : void (*handler)(void *private_data),
1624 : void *private_data)
1625 : {
1626 13409071 : if (ev == NULL) {
1627 7491076 : if (handler) {
1628 0 : errno = EINVAL;
1629 0 : return -1;
1630 : }
1631 7532101 : if (!bsds->readable_handler) {
1632 1595621 : return 0;
1633 : }
1634 5919493 : bsds->readable_handler = NULL;
1635 5919493 : bsds->readable_private = NULL;
1636 :
1637 5895455 : return 0;
1638 : }
1639 :
1640 : /* read and write must use the same tevent_context */
1641 5917995 : if (bsds->event_ptr != ev) {
1642 187779 : if (bsds->readable_handler || bsds->writeable_handler) {
1643 0 : errno = EINVAL;
1644 0 : return -1;
1645 : }
1646 187779 : bsds->event_ptr = NULL;
1647 187779 : TALLOC_FREE(bsds->fde);
1648 : }
1649 :
1650 5917995 : if (tevent_fd_get_flags(bsds->fde) == 0) {
1651 221961 : TALLOC_FREE(bsds->fde);
1652 :
1653 221961 : bsds->fde = tevent_add_fd(ev, bsds,
1654 : bsds->fd, TEVENT_FD_READ,
1655 : tstream_bsd_fde_handler,
1656 : bsds);
1657 221961 : if (!bsds->fde) {
1658 0 : errno = ENOMEM;
1659 0 : return -1;
1660 : }
1661 :
1662 : /* cache the event context we're running on */
1663 221961 : bsds->event_ptr = ev;
1664 5696034 : } else if (!bsds->readable_handler) {
1665 5696034 : TEVENT_FD_READABLE(bsds->fde);
1666 : }
1667 :
1668 5917995 : bsds->readable_handler = handler;
1669 5917995 : bsds->readable_private = private_data;
1670 :
1671 5917995 : return 0;
1672 : }
1673 :
1674 2508036 : static int tstream_bsd_set_writeable_handler(struct tstream_bsd *bsds,
1675 : struct tevent_context *ev,
1676 : void (*handler)(void *private_data),
1677 : void *private_data)
1678 : {
1679 2508036 : if (ev == NULL) {
1680 2144331 : if (handler) {
1681 0 : errno = EINVAL;
1682 0 : return -1;
1683 : }
1684 2144331 : if (!bsds->writeable_handler) {
1685 1763274 : return 0;
1686 : }
1687 363705 : bsds->writeable_handler = NULL;
1688 363705 : bsds->writeable_private = NULL;
1689 363705 : TEVENT_FD_NOT_WRITEABLE(bsds->fde);
1690 :
1691 363705 : return 0;
1692 : }
1693 :
1694 : /* read and write must use the same tevent_context */
1695 363705 : if (bsds->event_ptr != ev) {
1696 4231 : if (bsds->readable_handler || bsds->writeable_handler) {
1697 0 : errno = EINVAL;
1698 0 : return -1;
1699 : }
1700 4231 : bsds->event_ptr = NULL;
1701 4231 : TALLOC_FREE(bsds->fde);
1702 : }
1703 :
1704 363705 : if (tevent_fd_get_flags(bsds->fde) == 0) {
1705 4231 : TALLOC_FREE(bsds->fde);
1706 :
1707 4231 : bsds->fde = tevent_add_fd(ev, bsds,
1708 : bsds->fd,
1709 : TEVENT_FD_READ | TEVENT_FD_WRITE,
1710 : tstream_bsd_fde_handler,
1711 : bsds);
1712 4231 : if (!bsds->fde) {
1713 0 : errno = ENOMEM;
1714 0 : return -1;
1715 : }
1716 :
1717 : /* cache the event context we're running on */
1718 4231 : bsds->event_ptr = ev;
1719 359474 : } else if (!bsds->writeable_handler) {
1720 359474 : uint16_t flags = tevent_fd_get_flags(bsds->fde);
1721 359474 : flags |= TEVENT_FD_READ | TEVENT_FD_WRITE;
1722 359474 : tevent_fd_set_flags(bsds->fde, flags);
1723 : }
1724 :
1725 363705 : bsds->writeable_handler = handler;
1726 363705 : bsds->writeable_private = private_data;
1727 :
1728 363705 : return 0;
1729 : }
1730 :
1731 8 : static ssize_t tstream_bsd_pending_bytes(struct tstream_context *stream)
1732 : {
1733 8 : struct tstream_bsd *bsds = tstream_context_data(stream,
1734 : struct tstream_bsd);
1735 : ssize_t ret;
1736 :
1737 8 : if (bsds->fd == -1) {
1738 0 : errno = ENOTCONN;
1739 0 : return -1;
1740 : }
1741 :
1742 8 : ret = tsocket_bsd_pending(bsds->fd);
1743 :
1744 8 : return ret;
1745 : }
1746 :
1747 : struct tstream_bsd_readv_state {
1748 : struct tstream_context *stream;
1749 :
1750 : struct iovec *vector;
1751 : size_t count;
1752 :
1753 : int ret;
1754 : };
1755 :
1756 7532101 : static int tstream_bsd_readv_destructor(struct tstream_bsd_readv_state *state)
1757 : {
1758 7532101 : struct tstream_bsd *bsds = tstream_context_data(state->stream,
1759 : struct tstream_bsd);
1760 :
1761 7532101 : tstream_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
1762 :
1763 7532101 : return 0;
1764 : }
1765 :
1766 : static void tstream_bsd_readv_handler(void *private_data);
1767 :
1768 7530603 : static struct tevent_req *tstream_bsd_readv_send(TALLOC_CTX *mem_ctx,
1769 : struct tevent_context *ev,
1770 : struct tstream_context *stream,
1771 : struct iovec *vector,
1772 : size_t count)
1773 : {
1774 : struct tevent_req *req;
1775 : struct tstream_bsd_readv_state *state;
1776 7530603 : struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
1777 : int ret;
1778 :
1779 7530603 : req = tevent_req_create(mem_ctx, &state,
1780 : struct tstream_bsd_readv_state);
1781 7530603 : if (!req) {
1782 0 : return NULL;
1783 : }
1784 :
1785 7530603 : state->stream = stream;
1786 : /* we make a copy of the vector so that we can modify it */
1787 7530603 : state->vector = talloc_array(state, struct iovec, count);
1788 7530603 : if (tevent_req_nomem(state->vector, req)) {
1789 0 : goto post;
1790 : }
1791 7571628 : memcpy(state->vector, vector, sizeof(struct iovec)*count);
1792 7530603 : state->count = count;
1793 7530603 : state->ret = 0;
1794 :
1795 7530603 : talloc_set_destructor(state, tstream_bsd_readv_destructor);
1796 :
1797 7530603 : if (bsds->fd == -1) {
1798 0 : tevent_req_error(req, ENOTCONN);
1799 0 : goto post;
1800 : }
1801 :
1802 : /*
1803 : * this is a fast path, not waiting for the
1804 : * socket to become explicit readable gains
1805 : * about 10%-20% performance in benchmark tests.
1806 : */
1807 7530603 : if (bsds->optimize_readv) {
1808 : /*
1809 : * We only do the optimization on
1810 : * readv if the caller asked for it.
1811 : *
1812 : * This is needed because in most cases
1813 : * we prefer to flush send buffers before
1814 : * receiving incoming requests.
1815 : */
1816 1898361 : tstream_bsd_readv_handler(req);
1817 1898361 : if (!tevent_req_is_in_progress(req)) {
1818 1595621 : goto post;
1819 : }
1820 : }
1821 :
1822 5917995 : ret = tstream_bsd_set_readable_handler(bsds, ev,
1823 : tstream_bsd_readv_handler,
1824 : req);
1825 5917995 : if (ret == -1) {
1826 0 : tevent_req_error(req, errno);
1827 0 : goto post;
1828 : }
1829 :
1830 5893957 : return req;
1831 :
1832 1629595 : post:
1833 1612608 : tevent_req_post(req, ev);
1834 1612608 : return req;
1835 : }
1836 :
1837 12619026 : static void tstream_bsd_readv_handler(void *private_data)
1838 : {
1839 12619026 : struct tevent_req *req = talloc_get_type_abort(private_data,
1840 : struct tevent_req);
1841 12619026 : struct tstream_bsd_readv_state *state = tevent_req_data(req,
1842 : struct tstream_bsd_readv_state);
1843 12619026 : struct tstream_context *stream = state->stream;
1844 12619026 : struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
1845 : int ret;
1846 : int err;
1847 : int _count;
1848 : bool ok, retry;
1849 :
1850 12619026 : ret = readv(bsds->fd, state->vector, state->count);
1851 12619026 : if (ret == 0) {
1852 : /* propagate end of file */
1853 94154 : tevent_req_error(req, EPIPE);
1854 1217038 : return;
1855 : }
1856 12524872 : err = tsocket_bsd_error_from_errno(ret, errno, &retry);
1857 12484161 : if (retry) {
1858 : /* retry later */
1859 32152 : return;
1860 : }
1861 12492720 : if (tevent_req_error(req, err)) {
1862 3 : return;
1863 : }
1864 :
1865 12492717 : state->ret += ret;
1866 :
1867 12492717 : _count = state->count; /* tstream has size_t count, readv has int */
1868 12492717 : ok = iov_advance(&state->vector, &_count, ret);
1869 12492717 : state->count = _count;
1870 :
1871 12492717 : if (!ok) {
1872 0 : tevent_req_error(req, EINVAL);
1873 0 : return;
1874 : }
1875 :
1876 12492717 : if (state->count > 0) {
1877 : /* we have more to read */
1878 5063047 : return;
1879 : }
1880 :
1881 7427595 : tevent_req_done(req);
1882 : }
1883 :
1884 7521752 : static int tstream_bsd_readv_recv(struct tevent_req *req,
1885 : int *perrno)
1886 : {
1887 7521752 : struct tstream_bsd_readv_state *state = tevent_req_data(req,
1888 : struct tstream_bsd_readv_state);
1889 : int ret;
1890 :
1891 7521752 : ret = tsocket_simple_int_recv(req, perrno);
1892 7521752 : if (ret == 0) {
1893 7427595 : ret = state->ret;
1894 : }
1895 :
1896 7521752 : tevent_req_received(req);
1897 7521752 : return ret;
1898 : }
1899 :
1900 : struct tstream_bsd_writev_state {
1901 : struct tstream_context *stream;
1902 :
1903 : struct iovec *vector;
1904 : size_t count;
1905 :
1906 : int ret;
1907 : };
1908 :
1909 2144331 : static int tstream_bsd_writev_destructor(struct tstream_bsd_writev_state *state)
1910 : {
1911 2144331 : struct tstream_bsd *bsds = tstream_context_data(state->stream,
1912 : struct tstream_bsd);
1913 :
1914 2144331 : tstream_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
1915 :
1916 2144331 : return 0;
1917 : }
1918 :
1919 : static void tstream_bsd_writev_handler(void *private_data);
1920 :
1921 2144331 : static struct tevent_req *tstream_bsd_writev_send(TALLOC_CTX *mem_ctx,
1922 : struct tevent_context *ev,
1923 : struct tstream_context *stream,
1924 : const struct iovec *vector,
1925 : size_t count)
1926 : {
1927 : struct tevent_req *req;
1928 : struct tstream_bsd_writev_state *state;
1929 2144331 : struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
1930 : int ret;
1931 :
1932 2144331 : req = tevent_req_create(mem_ctx, &state,
1933 : struct tstream_bsd_writev_state);
1934 2144331 : if (!req) {
1935 0 : return NULL;
1936 : }
1937 :
1938 2144331 : state->stream = stream;
1939 : /* we make a copy of the vector so that we can modify it */
1940 2144331 : state->vector = talloc_array(state, struct iovec, count);
1941 2144331 : if (tevent_req_nomem(state->vector, req)) {
1942 0 : goto post;
1943 : }
1944 2163527 : memcpy(state->vector, vector, sizeof(struct iovec)*count);
1945 2144331 : state->count = count;
1946 2144331 : state->ret = 0;
1947 :
1948 2144331 : talloc_set_destructor(state, tstream_bsd_writev_destructor);
1949 :
1950 2144331 : if (bsds->fd == -1) {
1951 0 : tevent_req_error(req, ENOTCONN);
1952 0 : goto post;
1953 : }
1954 :
1955 : /*
1956 : * this is a fast path, not waiting for the
1957 : * socket to become explicit writeable gains
1958 : * about 10%-20% performance in benchmark tests.
1959 : */
1960 2144331 : tstream_bsd_writev_handler(req);
1961 2144331 : if (!tevent_req_is_in_progress(req)) {
1962 1763274 : goto post;
1963 : }
1964 :
1965 363705 : ret = tstream_bsd_set_writeable_handler(bsds, ev,
1966 : tstream_bsd_writev_handler,
1967 : req);
1968 363705 : if (ret == -1) {
1969 0 : tevent_req_error(req, errno);
1970 0 : goto post;
1971 : }
1972 :
1973 361861 : return req;
1974 :
1975 1797978 : post:
1976 1780626 : tevent_req_post(req, ev);
1977 1780626 : return req;
1978 : }
1979 :
1980 8300840 : static void tstream_bsd_writev_handler(void *private_data)
1981 : {
1982 8300840 : struct tevent_req *req = talloc_get_type_abort(private_data,
1983 : struct tevent_req);
1984 8300840 : struct tstream_bsd_writev_state *state = tevent_req_data(req,
1985 : struct tstream_bsd_writev_state);
1986 8300840 : struct tstream_context *stream = state->stream;
1987 8300840 : struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
1988 : ssize_t ret;
1989 : int err;
1990 : int _count;
1991 : bool ok, retry;
1992 :
1993 8300840 : ret = writev(bsds->fd, state->vector, state->count);
1994 8300840 : if (ret == 0) {
1995 : /* propagate end of file */
1996 0 : tevent_req_error(req, EPIPE);
1997 1103758 : return;
1998 : }
1999 8300840 : err = tsocket_bsd_error_from_errno(ret, errno, &retry);
2000 8277889 : if (retry) {
2001 : /* retry later */
2002 87 : return;
2003 : }
2004 8300752 : if (tevent_req_error(req, err)) {
2005 2 : return;
2006 : }
2007 :
2008 8300750 : state->ret += ret;
2009 :
2010 8300750 : _count = state->count; /* tstream has size_t count, writev has int */
2011 8300750 : ok = iov_advance(&state->vector, &_count, ret);
2012 8300750 : state->count = _count;
2013 :
2014 8300750 : if (!ok) {
2015 0 : tevent_req_error(req, EINVAL);
2016 0 : return;
2017 : }
2018 :
2019 8300750 : if (state->count > 0) {
2020 : /* we have more to read */
2021 6152667 : return;
2022 : }
2023 :
2024 2144329 : tevent_req_done(req);
2025 : }
2026 :
2027 2144263 : static int tstream_bsd_writev_recv(struct tevent_req *req, int *perrno)
2028 : {
2029 2144263 : struct tstream_bsd_writev_state *state = tevent_req_data(req,
2030 : struct tstream_bsd_writev_state);
2031 : int ret;
2032 :
2033 2144263 : ret = tsocket_simple_int_recv(req, perrno);
2034 2144263 : if (ret == 0) {
2035 2144261 : ret = state->ret;
2036 : }
2037 :
2038 2144263 : tevent_req_received(req);
2039 2144263 : return ret;
2040 : }
2041 :
2042 : struct tstream_bsd_disconnect_state {
2043 : void *__dummy;
2044 : };
2045 :
2046 29489 : static struct tevent_req *tstream_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
2047 : struct tevent_context *ev,
2048 : struct tstream_context *stream)
2049 : {
2050 29489 : struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
2051 : struct tevent_req *req;
2052 : struct tstream_bsd_disconnect_state *state;
2053 : int ret;
2054 : int err;
2055 : bool dummy;
2056 :
2057 29489 : req = tevent_req_create(mem_ctx, &state,
2058 : struct tstream_bsd_disconnect_state);
2059 29489 : if (req == NULL) {
2060 0 : return NULL;
2061 : }
2062 :
2063 29489 : if (bsds->fd == -1) {
2064 0 : tevent_req_error(req, ENOTCONN);
2065 0 : goto post;
2066 : }
2067 :
2068 29489 : TALLOC_FREE(bsds->fde);
2069 29489 : ret = close(bsds->fd);
2070 29489 : bsds->fd = -1;
2071 29861 : err = tsocket_bsd_error_from_errno(ret, errno, &dummy);
2072 29489 : if (tevent_req_error(req, err)) {
2073 0 : goto post;
2074 : }
2075 :
2076 29489 : tevent_req_done(req);
2077 29489 : post:
2078 29489 : tevent_req_post(req, ev);
2079 29489 : return req;
2080 : }
2081 :
2082 18965 : static int tstream_bsd_disconnect_recv(struct tevent_req *req,
2083 : int *perrno)
2084 : {
2085 : int ret;
2086 :
2087 18965 : ret = tsocket_simple_int_recv(req, perrno);
2088 :
2089 18965 : tevent_req_received(req);
2090 18965 : return ret;
2091 : }
2092 :
2093 : static const struct tstream_context_ops tstream_bsd_ops = {
2094 : .name = "bsd",
2095 :
2096 : .pending_bytes = tstream_bsd_pending_bytes,
2097 :
2098 : .readv_send = tstream_bsd_readv_send,
2099 : .readv_recv = tstream_bsd_readv_recv,
2100 :
2101 : .writev_send = tstream_bsd_writev_send,
2102 : .writev_recv = tstream_bsd_writev_recv,
2103 :
2104 : .disconnect_send = tstream_bsd_disconnect_send,
2105 : .disconnect_recv = tstream_bsd_disconnect_recv,
2106 : };
2107 :
2108 369576 : static int tstream_bsd_destructor(struct tstream_bsd *bsds)
2109 : {
2110 369576 : TALLOC_FREE(bsds->fde);
2111 369576 : if (bsds->fd != -1) {
2112 340087 : close(bsds->fd);
2113 340087 : bsds->fd = -1;
2114 : }
2115 369576 : return 0;
2116 : }
2117 :
2118 153022 : int _tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
2119 : int fd,
2120 : struct tstream_context **_stream,
2121 : const char *location)
2122 : {
2123 : struct tstream_context *stream;
2124 : struct tstream_bsd *bsds;
2125 :
2126 153022 : stream = tstream_context_create(mem_ctx,
2127 : &tstream_bsd_ops,
2128 : &bsds,
2129 : struct tstream_bsd,
2130 : location);
2131 153022 : if (!stream) {
2132 0 : return -1;
2133 : }
2134 153022 : ZERO_STRUCTP(bsds);
2135 153022 : bsds->fd = fd;
2136 153022 : talloc_set_destructor(bsds, tstream_bsd_destructor);
2137 :
2138 153022 : *_stream = stream;
2139 153022 : return 0;
2140 : }
2141 :
2142 : struct tstream_bsd_connect_state {
2143 : int fd;
2144 : struct tevent_fd *fde;
2145 : struct tstream_conext *stream;
2146 : struct tsocket_address *local;
2147 : };
2148 :
2149 12687 : static int tstream_bsd_connect_destructor(struct tstream_bsd_connect_state *state)
2150 : {
2151 12687 : TALLOC_FREE(state->fde);
2152 12687 : if (state->fd != -1) {
2153 706 : close(state->fd);
2154 706 : state->fd = -1;
2155 : }
2156 :
2157 12687 : return 0;
2158 : }
2159 :
2160 : static void tstream_bsd_connect_fde_handler(struct tevent_context *ev,
2161 : struct tevent_fd *fde,
2162 : uint16_t flags,
2163 : void *private_data);
2164 :
2165 12687 : static struct tevent_req *tstream_bsd_connect_send(TALLOC_CTX *mem_ctx,
2166 : struct tevent_context *ev,
2167 : int sys_errno,
2168 : const struct tsocket_address *local,
2169 : const struct tsocket_address *remote)
2170 : {
2171 : struct tevent_req *req;
2172 : struct tstream_bsd_connect_state *state;
2173 10454 : struct samba_sockaddr *lbsda =
2174 12687 : talloc_get_type_abort(local->private_data,
2175 : struct samba_sockaddr);
2176 12687 : struct samba_sockaddr *lrbsda = NULL;
2177 10454 : struct samba_sockaddr *rbsda =
2178 12687 : talloc_get_type_abort(remote->private_data,
2179 : struct samba_sockaddr);
2180 : int ret;
2181 12687 : bool do_bind = false;
2182 12687 : bool do_reuseaddr = false;
2183 12687 : bool do_ipv6only = false;
2184 12687 : bool is_inet = false;
2185 12687 : int sa_fam = lbsda->u.sa.sa_family;
2186 :
2187 12687 : req = tevent_req_create(mem_ctx, &state,
2188 : struct tstream_bsd_connect_state);
2189 12687 : if (!req) {
2190 0 : return NULL;
2191 : }
2192 12687 : state->fd = -1;
2193 12687 : state->fde = NULL;
2194 :
2195 12687 : talloc_set_destructor(state, tstream_bsd_connect_destructor);
2196 :
2197 : /* give the wrappers a chance to report an error */
2198 12687 : if (sys_errno != 0) {
2199 0 : tevent_req_error(req, sys_errno);
2200 0 : goto post;
2201 : }
2202 :
2203 12687 : switch (lbsda->u.sa.sa_family) {
2204 10162 : case AF_UNIX:
2205 10162 : if (lbsda->u.un.sun_path[0] != 0) {
2206 0 : do_reuseaddr = true;
2207 0 : do_bind = true;
2208 : }
2209 9536 : break;
2210 679 : case AF_INET:
2211 679 : if (lbsda->u.in.sin_port != 0) {
2212 0 : do_reuseaddr = true;
2213 0 : do_bind = true;
2214 : }
2215 679 : if (lbsda->u.in.sin_addr.s_addr != INADDR_ANY) {
2216 679 : do_bind = true;
2217 : }
2218 679 : is_inet = true;
2219 679 : break;
2220 : #ifdef HAVE_IPV6
2221 1846 : case AF_INET6:
2222 1846 : if (lbsda->u.in6.sin6_port != 0) {
2223 0 : do_reuseaddr = true;
2224 0 : do_bind = true;
2225 : }
2226 1846 : if (memcmp(&in6addr_any,
2227 1846 : &lbsda->u.in6.sin6_addr,
2228 : sizeof(in6addr_any)) != 0) {
2229 0 : do_bind = true;
2230 : }
2231 1846 : is_inet = true;
2232 1846 : do_ipv6only = true;
2233 1846 : break;
2234 : #endif
2235 0 : default:
2236 0 : tevent_req_error(req, EINVAL);
2237 0 : goto post;
2238 : }
2239 :
2240 12687 : if (!do_bind && is_inet) {
2241 1846 : sa_fam = rbsda->u.sa.sa_family;
2242 1846 : switch (sa_fam) {
2243 22 : case AF_INET:
2244 22 : do_ipv6only = false;
2245 22 : break;
2246 : #ifdef HAVE_IPV6
2247 1824 : case AF_INET6:
2248 1824 : do_ipv6only = true;
2249 1824 : break;
2250 : #endif
2251 : }
2252 : }
2253 :
2254 12687 : if (is_inet) {
2255 2525 : state->local = tsocket_address_create(state,
2256 : &tsocket_address_bsd_ops,
2257 : &lrbsda,
2258 : struct samba_sockaddr,
2259 : __location__ "bsd_connect");
2260 2525 : if (tevent_req_nomem(state->local, req)) {
2261 0 : goto post;
2262 : }
2263 :
2264 2525 : ZERO_STRUCTP(lrbsda);
2265 2525 : lrbsda->sa_socklen = sizeof(lrbsda->u.ss);
2266 : #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
2267 : lrbsda->u.sa.sa_len = lrbsda->sa_socklen;
2268 : #endif
2269 : }
2270 :
2271 12687 : state->fd = socket(sa_fam, SOCK_STREAM, 0);
2272 12687 : if (state->fd == -1) {
2273 0 : tevent_req_error(req, errno);
2274 0 : goto post;
2275 : }
2276 :
2277 12687 : state->fd = tsocket_bsd_common_prepare_fd(state->fd, true);
2278 12687 : if (state->fd == -1) {
2279 0 : tevent_req_error(req, errno);
2280 0 : goto post;
2281 : }
2282 :
2283 : #ifdef HAVE_IPV6
2284 12687 : if (do_ipv6only) {
2285 1824 : int val = 1;
2286 :
2287 1824 : ret = setsockopt(state->fd, IPPROTO_IPV6, IPV6_V6ONLY,
2288 : (const void *)&val, sizeof(val));
2289 1824 : if (ret == -1) {
2290 0 : tevent_req_error(req, errno);
2291 0 : goto post;
2292 : }
2293 : }
2294 : #endif
2295 :
2296 12687 : if (do_reuseaddr) {
2297 0 : int val = 1;
2298 :
2299 0 : ret = setsockopt(state->fd, SOL_SOCKET, SO_REUSEADDR,
2300 : (const void *)&val, sizeof(val));
2301 0 : if (ret == -1) {
2302 0 : tevent_req_error(req, errno);
2303 0 : goto post;
2304 : }
2305 : }
2306 :
2307 12687 : if (do_bind) {
2308 679 : ret = bind(state->fd, &lbsda->u.sa, lbsda->sa_socklen);
2309 679 : if (ret == -1) {
2310 0 : tevent_req_error(req, errno);
2311 0 : goto post;
2312 : }
2313 : }
2314 :
2315 12687 : if (rbsda->u.sa.sa_family != sa_fam) {
2316 0 : tevent_req_error(req, EINVAL);
2317 0 : goto post;
2318 : }
2319 :
2320 12687 : ret = connect(state->fd, &rbsda->u.sa, rbsda->sa_socklen);
2321 12687 : if (ret == -1) {
2322 706 : if (errno == EINPROGRESS) {
2323 0 : goto async;
2324 : }
2325 706 : tevent_req_error(req, errno);
2326 706 : goto post;
2327 : }
2328 :
2329 11981 : if (!state->local) {
2330 9466 : tevent_req_done(req);
2331 8840 : goto post;
2332 : }
2333 :
2334 2515 : if (lrbsda != NULL) {
2335 5030 : ret = getsockname(state->fd,
2336 2515 : &lrbsda->u.sa,
2337 2515 : &lrbsda->sa_socklen);
2338 2515 : if (ret == -1) {
2339 0 : tevent_req_error(req, errno);
2340 0 : goto post;
2341 : }
2342 : }
2343 :
2344 2515 : tevent_req_done(req);
2345 2515 : goto post;
2346 :
2347 0 : async:
2348 :
2349 : /*
2350 : * Note for historic reasons TEVENT_FD_WRITE is not enough
2351 : * to get notified for POLLERR or EPOLLHUP even if they
2352 : * come together with POLLOUT. That means we need to
2353 : * use TEVENT_FD_READ in addition until we have
2354 : * TEVENT_FD_ERROR.
2355 : */
2356 0 : state->fde = tevent_add_fd(ev, state,
2357 : state->fd,
2358 : TEVENT_FD_READ | TEVENT_FD_WRITE,
2359 : tstream_bsd_connect_fde_handler,
2360 : req);
2361 0 : if (tevent_req_nomem(state->fde, req)) {
2362 0 : goto post;
2363 : }
2364 :
2365 0 : return req;
2366 :
2367 12687 : post:
2368 12687 : tevent_req_post(req, ev);
2369 12061 : return req;
2370 : }
2371 :
2372 0 : static void tstream_bsd_connect_fde_handler(struct tevent_context *ev,
2373 : struct tevent_fd *fde,
2374 : uint16_t flags,
2375 : void *private_data)
2376 : {
2377 0 : struct tevent_req *req = talloc_get_type_abort(private_data,
2378 : struct tevent_req);
2379 0 : struct tstream_bsd_connect_state *state = tevent_req_data(req,
2380 : struct tstream_bsd_connect_state);
2381 0 : struct samba_sockaddr *lrbsda = NULL;
2382 : int ret;
2383 0 : int error=0;
2384 0 : socklen_t len = sizeof(error);
2385 : int err;
2386 : bool retry;
2387 :
2388 0 : ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR, &error, &len);
2389 0 : if (ret == 0) {
2390 0 : if (error != 0) {
2391 0 : errno = error;
2392 0 : ret = -1;
2393 : }
2394 : }
2395 0 : err = tsocket_bsd_error_from_errno(ret, errno, &retry);
2396 0 : if (retry) {
2397 : /* retry later */
2398 0 : return;
2399 : }
2400 0 : if (tevent_req_error(req, err)) {
2401 0 : return;
2402 : }
2403 :
2404 0 : if (!state->local) {
2405 0 : tevent_req_done(req);
2406 0 : return;
2407 : }
2408 :
2409 0 : lrbsda = talloc_get_type_abort(state->local->private_data,
2410 : struct samba_sockaddr);
2411 :
2412 0 : ret = getsockname(state->fd, &lrbsda->u.sa, &lrbsda->sa_socklen);
2413 0 : if (ret == -1) {
2414 0 : tevent_req_error(req, errno);
2415 0 : return;
2416 : }
2417 :
2418 0 : tevent_req_done(req);
2419 : }
2420 :
2421 12687 : static int tstream_bsd_connect_recv(struct tevent_req *req,
2422 : int *perrno,
2423 : TALLOC_CTX *mem_ctx,
2424 : struct tstream_context **stream,
2425 : struct tsocket_address **local,
2426 : const char *location)
2427 : {
2428 12687 : struct tstream_bsd_connect_state *state = tevent_req_data(req,
2429 : struct tstream_bsd_connect_state);
2430 : int ret;
2431 :
2432 12687 : ret = tsocket_simple_int_recv(req, perrno);
2433 12687 : if (ret == 0) {
2434 11981 : ret = _tstream_bsd_existing_socket(mem_ctx,
2435 : state->fd,
2436 : stream,
2437 : location);
2438 11981 : if (ret == -1) {
2439 0 : *perrno = errno;
2440 0 : goto done;
2441 : }
2442 11981 : TALLOC_FREE(state->fde);
2443 11981 : state->fd = -1;
2444 :
2445 11981 : if (local) {
2446 0 : *local = talloc_move(mem_ctx, &state->local);
2447 : }
2448 : }
2449 :
2450 23141 : done:
2451 12687 : tevent_req_received(req);
2452 12687 : return ret;
2453 : }
2454 :
2455 2525 : struct tevent_req * tstream_inet_tcp_connect_send(TALLOC_CTX *mem_ctx,
2456 : struct tevent_context *ev,
2457 : const struct tsocket_address *local,
2458 : const struct tsocket_address *remote)
2459 : {
2460 2525 : struct samba_sockaddr *lbsda =
2461 2525 : talloc_get_type_abort(local->private_data,
2462 : struct samba_sockaddr);
2463 : struct tevent_req *req;
2464 2525 : int sys_errno = 0;
2465 :
2466 2525 : switch (lbsda->u.sa.sa_family) {
2467 679 : case AF_INET:
2468 679 : break;
2469 : #ifdef HAVE_IPV6
2470 1846 : case AF_INET6:
2471 1846 : break;
2472 : #endif
2473 0 : default:
2474 0 : sys_errno = EINVAL;
2475 0 : break;
2476 : }
2477 :
2478 2525 : req = tstream_bsd_connect_send(mem_ctx, ev, sys_errno, local, remote);
2479 :
2480 2525 : return req;
2481 : }
2482 :
2483 2525 : int _tstream_inet_tcp_connect_recv(struct tevent_req *req,
2484 : int *perrno,
2485 : TALLOC_CTX *mem_ctx,
2486 : struct tstream_context **stream,
2487 : struct tsocket_address **local,
2488 : const char *location)
2489 : {
2490 2525 : return tstream_bsd_connect_recv(req, perrno,
2491 : mem_ctx, stream, local,
2492 : location);
2493 : }
2494 :
2495 10162 : struct tevent_req * tstream_unix_connect_send(TALLOC_CTX *mem_ctx,
2496 : struct tevent_context *ev,
2497 : const struct tsocket_address *local,
2498 : const struct tsocket_address *remote)
2499 : {
2500 7929 : struct samba_sockaddr *lbsda =
2501 10162 : talloc_get_type_abort(local->private_data,
2502 : struct samba_sockaddr);
2503 : struct tevent_req *req;
2504 10162 : int sys_errno = 0;
2505 :
2506 10162 : switch (lbsda->u.sa.sa_family) {
2507 9536 : case AF_UNIX:
2508 9536 : break;
2509 0 : default:
2510 0 : sys_errno = EINVAL;
2511 0 : break;
2512 : }
2513 :
2514 10162 : req = tstream_bsd_connect_send(mem_ctx, ev, sys_errno, local, remote);
2515 :
2516 10162 : return req;
2517 : }
2518 :
2519 10162 : int _tstream_unix_connect_recv(struct tevent_req *req,
2520 : int *perrno,
2521 : TALLOC_CTX *mem_ctx,
2522 : struct tstream_context **stream,
2523 : const char *location)
2524 : {
2525 10162 : return tstream_bsd_connect_recv(req, perrno,
2526 : mem_ctx, stream, NULL,
2527 : location);
2528 : }
2529 :
2530 0 : int _tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
2531 : struct tstream_context **_stream1,
2532 : TALLOC_CTX *mem_ctx2,
2533 : struct tstream_context **_stream2,
2534 : const char *location)
2535 : {
2536 : int ret;
2537 : int fds[2];
2538 : int fd1;
2539 : int fd2;
2540 0 : struct tstream_context *stream1 = NULL;
2541 0 : struct tstream_context *stream2 = NULL;
2542 :
2543 0 : ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
2544 0 : if (ret == -1) {
2545 0 : return -1;
2546 : }
2547 0 : fd1 = fds[0];
2548 0 : fd2 = fds[1];
2549 :
2550 0 : fd1 = tsocket_bsd_common_prepare_fd(fd1, true);
2551 0 : if (fd1 == -1) {
2552 0 : int sys_errno = errno;
2553 0 : close(fd2);
2554 0 : errno = sys_errno;
2555 0 : return -1;
2556 : }
2557 :
2558 0 : fd2 = tsocket_bsd_common_prepare_fd(fd2, true);
2559 0 : if (fd2 == -1) {
2560 0 : int sys_errno = errno;
2561 0 : close(fd1);
2562 0 : errno = sys_errno;
2563 0 : return -1;
2564 : }
2565 :
2566 0 : ret = _tstream_bsd_existing_socket(mem_ctx1,
2567 : fd1,
2568 : &stream1,
2569 : location);
2570 0 : if (ret == -1) {
2571 0 : int sys_errno = errno;
2572 0 : close(fd1);
2573 0 : close(fd2);
2574 0 : errno = sys_errno;
2575 0 : return -1;
2576 : }
2577 :
2578 0 : ret = _tstream_bsd_existing_socket(mem_ctx2,
2579 : fd2,
2580 : &stream2,
2581 : location);
2582 0 : if (ret == -1) {
2583 0 : int sys_errno = errno;
2584 0 : talloc_free(stream1);
2585 0 : close(fd2);
2586 0 : errno = sys_errno;
2587 0 : return -1;
2588 : }
2589 :
2590 0 : *_stream1 = stream1;
2591 0 : *_stream2 = stream2;
2592 0 : return 0;
2593 : }
2594 :
|