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