Remove building with NOCRYPTO option
[minix.git] / minix / lib / libc / sys / sendto.c
blobc194c8182382b1af51b468de7e24e18579fd99e0
1 #include <sys/cdefs.h>
2 #include "namespace.h"
3 #include <lib.h>
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>
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>
24 #define DEBUG 0
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);
37 * Send a message on a socket.
39 static ssize_t
40 __sendto(int fd, const void * buffer, size_t length, int flags,
41 const struct sockaddr * dest_addr, socklen_t dest_len)
43 message m;
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;
53 return _syscall(VFS_PROC_NR, VFS_SENDTO, &m);
56 ssize_t sendto(int sock, const void *message, size_t length, int flags,
57 const struct sockaddr *dest_addr, socklen_t dest_len)
59 int r;
60 nwio_tcpopt_t tcpopt;
61 nwio_udpopt_t udpopt;
62 nwio_ipopt_t ipopt;
63 int uds_sotype = -1;
65 r = __sendto(sock, message, length, flags, dest_addr, dest_len);
66 if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
67 return r;
69 /* For old socket driver implementations, this flag is the default. */
70 flags &= ~MSG_NOSIGNAL;
72 r= ioctl(sock, NWIOGTCPOPT, &tcpopt);
73 if (r != -1 || errno != ENOTTY)
75 if (r == -1)
76 return r;
77 return _tcp_sendto(sock, message, length, flags,
78 dest_addr, dest_len);
81 r= ioctl(sock, NWIOGUDPOPT, &udpopt);
82 if (r != -1 || errno != ENOTTY)
84 if (r == -1)
85 return r;
86 return _udp_sendto(sock, message, length, flags,
87 dest_addr, dest_len, &udpopt);
90 r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype);
91 if (r != -1 || errno != ENOTTY)
93 if (r == -1) {
94 return r;
97 if (uds_sotype == SOCK_DGRAM) {
99 return _uds_sendto_dgram(sock, message,
100 length, flags,dest_addr, dest_len);
101 } else {
103 return _uds_sendto_conn(sock, message,
104 length, flags, dest_addr, dest_len);
108 r= ioctl(sock, NWIOGIPOPT, &ipopt);
109 if (r != -1 || errno != ENOTTY)
111 ip_hdr_t *ip_hdr;
112 const struct sockaddr_in *sinp;
113 ssize_t retval;
114 int saved_errno;
116 if (r == -1) {
117 return r;
120 sinp = (const struct sockaddr_in *)dest_addr;
121 if (sinp->sin_family != AF_INET)
123 errno= EAFNOSUPPORT;
124 return -1;
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..
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;
137 retval = write(sock, ip_hdr, length);
139 saved_errno = errno;
140 free(ip_hdr);
141 errno = saved_errno;
142 return retval;
145 errno = ENOTSOCK;
146 return -1;
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)
153 if (flags != 0) {
154 #if DEBUG
155 fprintf(stderr, "sendto(tcp): flags not implemented\n");
156 #endif
157 errno= ENOSYS;
158 return -1;
161 /* Silently ignore destination, if given. */
163 return write(sock, message, length);
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)
170 int r, t_errno;
171 size_t buflen;
172 void *buf;
173 struct sockaddr_in *sinp;
174 udp_io_hdr_t *io_hdrp;
176 if (flags)
178 #if DEBUG
179 fprintf(stderr, "sendto(udp): flags not implemented\n");
180 #endif
181 errno= ENOSYS;
182 return -1;
185 if (udpoptp->nwuo_flags & NWUO_RWDATONLY)
186 return write(sock, message, length);
188 if ((udpoptp->nwuo_flags & NWUO_RP_ANY) ||
189 (udpoptp->nwuo_flags & NWUO_RA_ANY))
191 if (!dest_addr)
193 errno= ENOTCONN;
194 return -1;
197 /* Check destination address */
198 if (dest_len < sizeof(*sinp))
200 errno= EINVAL;
201 return -1;
203 sinp= (struct sockaddr_in *) __UNCONST(dest_addr);
204 if (sinp->sin_family != AF_INET)
206 errno= EAFNOSUPPORT;
207 return -1;
211 buflen= sizeof(*io_hdrp) + length;
212 if (buflen < length)
214 /* Overflow */
215 errno= EMSGSIZE;
216 return -1;
218 buf= malloc(buflen);
219 if (buf == NULL)
220 return -1;
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;
236 memcpy(&io_hdrp[1], message, length);
237 r= write(sock, buf, buflen);
238 if (r == -1)
240 t_errno= errno;
241 free(buf);
242 errno= t_errno;
243 return -1;
245 assert((size_t)r == buflen);
246 free(buf);
247 return length;
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)
254 /* for connection oriented unix domain sockets (SOCK_STREAM /
255 * SOCK_SEQPACKET)
258 if (flags != 0) {
259 #if DEBUG
260 fprintf(stderr, "sendto(uds): flags not implemented\n");
261 #endif
262 errno= ENOSYS;
263 return -1;
266 /* Silently ignore destination, if given. */
268 return write(sock, message, length);
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)
274 int r;
276 /* for connectionless unix domain sockets (SOCK_DGRAM) */
278 if (flags != 0) {
279 #if DEBUG
280 fprintf(stderr, "sendto(uds): flags not implemented\n");
281 #endif
282 errno= ENOSYS;
283 return -1;
286 if (dest_addr == NULL) {
287 errno = EFAULT;
288 return -1;
291 /* set the target address */
292 r= ioctl(sock, NWIOSUDSTADDR, (void *) __UNCONST(dest_addr));
293 if (r == -1) {
294 return r;
297 /* do the send */
298 return write(sock, message, length);