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