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