1 | /* Copyright (C) 1994-2022 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | #include <errno.h> |
19 | #include <sys/socket.h> |
20 | #include <sys/un.h> |
21 | #include <hurd.h> |
22 | #include <hurd/fd.h> |
23 | #include <hurd/ifsock.h> |
24 | #include <hurd/socket.h> |
25 | #include <sysdep-cancel.h> |
26 | #include "hurd/hurdsocket.h" |
27 | |
28 | /* Send N bytes of BUF on socket FD to peer at address ADDR (which is |
29 | ADDR_LEN bytes long). Returns the number sent, or -1 for errors. */ |
30 | ssize_t |
31 | __sendto (int fd, |
32 | const void *buf, |
33 | size_t n, |
34 | int flags, |
35 | const struct sockaddr_un *addr, |
36 | socklen_t addr_len) |
37 | { |
38 | addr_port_t aport = MACH_PORT_NULL; |
39 | error_t err; |
40 | size_t wrote; |
41 | |
42 | /* Get an address port for the desired destination address. */ |
43 | error_t create_address_port (io_t port, |
44 | const struct sockaddr_un *addr, |
45 | socklen_t addr_len, |
46 | addr_port_t *aport) |
47 | { |
48 | error_t err_port; |
49 | |
50 | if (addr->sun_family == AF_LOCAL) |
51 | { |
52 | char *name = _hurd_sun_path_dupa (addr, addr_len); |
53 | /* For the local domain, we must look up the name as a file and talk |
54 | to it with the ifsock protocol. */ |
55 | file_t file = __file_name_lookup (name, 0, 0); |
56 | if (file == MACH_PORT_NULL) |
57 | return errno; |
58 | err_port = __ifsock_getsockaddr (file, aport); |
59 | __mach_port_deallocate (__mach_task_self (), file); |
60 | if (err_port == MIG_BAD_ID || err_port == EOPNOTSUPP) |
61 | /* The file did not grok the ifsock protocol. */ |
62 | err_port = ENOTSOCK; |
63 | } |
64 | else |
65 | { |
66 | err_port = __socket_create_address (port, |
67 | addr->sun_family, |
68 | (char *) addr, |
69 | addr_len, |
70 | aport); |
71 | } |
72 | |
73 | return err_port; |
74 | } |
75 | |
76 | err = HURD_DPORT_USE_CANCEL (fd, |
77 | ({ |
78 | if (addr != NULL) |
79 | err = create_address_port (port, addr, addr_len, |
80 | &aport); |
81 | else |
82 | err = 0; |
83 | if (! err) |
84 | { |
85 | /* Send the data. */ |
86 | int cancel_oldtype = LIBC_CANCEL_ASYNC(); |
87 | err = __socket_send (port, aport, |
88 | flags, buf, n, |
89 | NULL, |
90 | MACH_MSG_TYPE_COPY_SEND, 0, |
91 | NULL, 0, &wrote); |
92 | LIBC_CANCEL_RESET (cancel_oldtype); |
93 | } |
94 | err; |
95 | })); |
96 | |
97 | if (aport != MACH_PORT_NULL) |
98 | __mach_port_deallocate (__mach_task_self (), aport); |
99 | |
100 | return err ? __hurd_sockfail (fd, flags, err) : wrote; |
101 | } |
102 | |
103 | weak_alias (__sendto, sendto) |
104 | |