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