1 #include <sys/cdefs.h>
2 #include "namespace.h"
3 #include <lib.h>
4
5 #include <assert.h>
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <sys/ioctl.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14
15 #include <net/gen/in.h>
16 #include <net/gen/ip_hdr.h>
17 #include <net/gen/ip_io.h>
18 #include <net/gen/tcp.h>
19 #include <net/gen/tcp_io.h>
20 #include <net/gen/udp.h>
21 #include <net/gen/udp_hdr.h>
22 #include <net/gen/udp_io.h>
23
24 #define DEBUG 0
25
26 static ssize_t _tcp_sendto(int sock, const void *message, size_t length,
27 int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
28 static ssize_t _udp_sendto(int sock, const void *message, size_t length,
29 int flags, const struct sockaddr *dest_addr, socklen_t dest_len,
30 nwio_udpopt_t *udpoptp);
31 static ssize_t _uds_sendto_conn(int sock, const void *message, size_t length,
32 int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
33 static ssize_t _uds_sendto_dgram(int sock, const void *message, size_t length,
34 int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
35
36 /*
37 * Send a message on a socket.
38 */
39 static ssize_t
__sendto(int fd,const void * buffer,size_t length,int flags,const struct sockaddr * dest_addr,socklen_t dest_len)40 __sendto(int fd, const void * buffer, size_t length, int flags,
41 const struct sockaddr * dest_addr, socklen_t dest_len)
42 {
43 message m;
44
45 memset(&m, 0, sizeof(m));
46 m.m_lc_vfs_sendrecv.fd = fd;
47 m.m_lc_vfs_sendrecv.buf = (vir_bytes)buffer;
48 m.m_lc_vfs_sendrecv.len = length;
49 m.m_lc_vfs_sendrecv.flags = flags;
50 m.m_lc_vfs_sendrecv.addr = (vir_bytes)dest_addr;
51 m.m_lc_vfs_sendrecv.addr_len = dest_len;
52
53 return _syscall(VFS_PROC_NR, VFS_SENDTO, &m);
54 }
55
sendto(int sock,const void * message,size_t length,int flags,const struct sockaddr * dest_addr,socklen_t dest_len)56 ssize_t sendto(int sock, const void *message, size_t length, int flags,
57 const struct sockaddr *dest_addr, socklen_t dest_len)
58 {
59 int r;
60 nwio_tcpopt_t tcpopt;
61 nwio_udpopt_t udpopt;
62 nwio_ipopt_t ipopt;
63 int uds_sotype = -1;
64
65 r = __sendto(sock, message, length, flags, dest_addr, dest_len);
66 if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
67 return r;
68
69 /* For old socket driver implementations, this flag is the default. */
70 flags &= ~MSG_NOSIGNAL;
71
72 r= ioctl(sock, NWIOGTCPOPT, &tcpopt);
73 if (r != -1 || errno != ENOTTY)
74 {
75 if (r == -1)
76 return r;
77 return _tcp_sendto(sock, message, length, flags,
78 dest_addr, dest_len);
79 }
80
81 r= ioctl(sock, NWIOGUDPOPT, &udpopt);
82 if (r != -1 || errno != ENOTTY)
83 {
84 if (r == -1)
85 return r;
86 return _udp_sendto(sock, message, length, flags,
87 dest_addr, dest_len, &udpopt);
88 }
89
90 r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype);
91 if (r != -1 || errno != ENOTTY)
92 {
93 if (r == -1) {
94 return r;
95 }
96
97 if (uds_sotype == SOCK_DGRAM) {
98
99 return _uds_sendto_dgram(sock, message,
100 length, flags,dest_addr, dest_len);
101 } else {
102
103 return _uds_sendto_conn(sock, message,
104 length, flags, dest_addr, dest_len);
105 }
106 }
107
108 r= ioctl(sock, NWIOGIPOPT, &ipopt);
109 if (r != -1 || errno != ENOTTY)
110 {
111 ip_hdr_t *ip_hdr;
112 const struct sockaddr_in *sinp;
113 ssize_t retval;
114 int saved_errno;
115
116 if (r == -1) {
117 return r;
118 }
119
120 sinp = (const struct sockaddr_in *)dest_addr;
121 if (sinp->sin_family != AF_INET)
122 {
123 errno= EAFNOSUPPORT;
124 return -1;
125 }
126
127 /* raw */
128 /* XXX this is horrible: we have to copy the entire buffer
129 * because we have to change one header field. Obviously we
130 * can't modify the user buffer directly..
131 */
132 if ((ip_hdr = malloc(length)) == NULL)
133 return -1; /* errno is ENOMEM */
134 memcpy(ip_hdr, message, length);
135 ip_hdr->ih_dst= sinp->sin_addr.s_addr;
136
137 retval = write(sock, ip_hdr, length);
138
139 saved_errno = errno;
140 free(ip_hdr);
141 errno = saved_errno;
142 return retval;
143 }
144
145 errno = ENOTSOCK;
146 return -1;
147 }
148
_tcp_sendto(int sock,const void * message,size_t length,int flags,const struct sockaddr * dest_addr,socklen_t dest_len)149 static ssize_t _tcp_sendto(int sock, const void *message, size_t length,
150 int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
151 {
152
153 if (flags != 0) {
154 #if DEBUG
155 fprintf(stderr, "sendto(tcp): flags not implemented\n");
156 #endif
157 errno= ENOSYS;
158 return -1;
159 }
160
161 /* Silently ignore destination, if given. */
162
163 return write(sock, message, length);
164 }
165
_udp_sendto(int sock,const void * message,size_t length,int flags,const struct sockaddr * dest_addr,socklen_t dest_len,nwio_udpopt_t * udpoptp)166 static ssize_t _udp_sendto(int sock, const void *message, size_t length,
167 int flags, const struct sockaddr *dest_addr, socklen_t dest_len,
168 nwio_udpopt_t *udpoptp)
169 {
170 int r, t_errno;
171 size_t buflen;
172 void *buf;
173 struct sockaddr_in *sinp;
174 udp_io_hdr_t *io_hdrp;
175
176 if (flags)
177 {
178 #if DEBUG
179 fprintf(stderr, "sendto(udp): flags not implemented\n");
180 #endif
181 errno= ENOSYS;
182 return -1;
183 }
184
185 if (udpoptp->nwuo_flags & NWUO_RWDATONLY)
186 return write(sock, message, length);
187
188 if ((udpoptp->nwuo_flags & NWUO_RP_ANY) ||
189 (udpoptp->nwuo_flags & NWUO_RA_ANY))
190 {
191 if (!dest_addr)
192 {
193 errno= ENOTCONN;
194 return -1;
195 }
196
197 /* Check destination address */
198 if (dest_len < sizeof(*sinp))
199 {
200 errno= EINVAL;
201 return -1;
202 }
203 sinp= (struct sockaddr_in *) __UNCONST(dest_addr);
204 if (sinp->sin_family != AF_INET)
205 {
206 errno= EAFNOSUPPORT;
207 return -1;
208 }
209 }
210
211 buflen= sizeof(*io_hdrp) + length;
212 if (buflen < length)
213 {
214 /* Overflow */
215 errno= EMSGSIZE;
216 return -1;
217 }
218 buf= malloc(buflen);
219 if (buf == NULL)
220 return -1;
221
222 io_hdrp= buf;
223 io_hdrp->uih_src_addr= 0; /* Unused */
224 io_hdrp->uih_src_port= 0; /* Will cause error if NWUO_LP_ANY */
225 if (udpoptp->nwuo_flags & NWUO_RA_ANY)
226 io_hdrp->uih_dst_addr= sinp->sin_addr.s_addr;
227 else
228 io_hdrp->uih_dst_addr= 0;
229 if (udpoptp->nwuo_flags & NWUO_RP_ANY)
230 io_hdrp->uih_dst_port= sinp->sin_port;
231 else
232 io_hdrp->uih_dst_port= 0;
233 io_hdrp->uih_ip_opt_len= 0;
234 io_hdrp->uih_data_len= 0;
235
236 memcpy(&io_hdrp[1], message, length);
237 r= write(sock, buf, buflen);
238 if (r == -1)
239 {
240 t_errno= errno;
241 free(buf);
242 errno= t_errno;
243 return -1;
244 }
245 assert((size_t)r == buflen);
246 free(buf);
247 return length;
248 }
249
_uds_sendto_conn(int sock,const void * message,size_t length,int flags,const struct sockaddr * dest_addr,socklen_t dest_len)250 static ssize_t _uds_sendto_conn(int sock, const void *message, size_t length,
251 int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
252 {
253
254 /* for connection oriented unix domain sockets (SOCK_STREAM /
255 * SOCK_SEQPACKET)
256 */
257
258 if (flags != 0) {
259 #if DEBUG
260 fprintf(stderr, "sendto(uds): flags not implemented\n");
261 #endif
262 errno= ENOSYS;
263 return -1;
264 }
265
266 /* Silently ignore destination, if given. */
267
268 return write(sock, message, length);
269 }
270
_uds_sendto_dgram(int sock,const void * message,size_t length,int flags,const struct sockaddr * dest_addr,socklen_t dest_len)271 static ssize_t _uds_sendto_dgram(int sock, const void *message, size_t length,
272 int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
273 {
274 int r;
275
276 /* for connectionless unix domain sockets (SOCK_DGRAM) */
277
278 if (flags != 0) {
279 #if DEBUG
280 fprintf(stderr, "sendto(uds): flags not implemented\n");
281 #endif
282 errno= ENOSYS;
283 return -1;
284 }
285
286 if (dest_addr == NULL) {
287 errno = EFAULT;
288 return -1;
289 }
290
291 /* set the target address */
292 r= ioctl(sock, NWIOSUDSTADDR, (void *) __UNCONST(dest_addr));
293 if (r == -1) {
294 return r;
295 }
296
297 /* do the send */
298 return write(sock, message, length);
299 }
300