netbsd ping & traceroute
[minix3.git] / minix / lib / libc / sys / sendto.c
blobf0d6a2811fa6b62446ae695123022cbca2687cbf
1 #include <sys/cdefs.h>
2 #include "namespace.h"
4 #undef NDEBUG
6 #include <assert.h>
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
16 #include <net/gen/in.h>
17 #include <net/gen/ip_hdr.h>
18 #include <net/gen/icmp_hdr.h>
19 #include <net/gen/tcp.h>
20 #include <net/gen/tcp_io.h>
21 #include <net/gen/udp.h>
22 #include <net/gen/udp_hdr.h>
23 #include <net/gen/udp_io.h>
25 #define DEBUG 0
27 static ssize_t _tcp_sendto(int sock, const void *message, size_t length,
28 int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
29 static ssize_t _udp_sendto(int sock, const void *message, size_t length,
30 int flags, const struct sockaddr *dest_addr, socklen_t dest_len,
31 nwio_udpopt_t *udpoptp);
32 static ssize_t _uds_sendto_conn(int sock, const void *message, size_t length,
33 int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
34 static ssize_t _uds_sendto_dgram(int sock, const void *message, size_t length,
35 int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
37 ssize_t sendto(int sock, const void *message, size_t length, int flags,
38 const struct sockaddr *dest_addr, socklen_t dest_len)
40 int r;
41 nwio_tcpopt_t tcpopt;
42 nwio_udpopt_t udpopt;
43 int uds_sotype = -1;
45 r= ioctl(sock, NWIOGTCPOPT, &tcpopt);
46 if (r != -1 || errno != ENOTTY)
48 if (r == -1)
49 return r;
50 return _tcp_sendto(sock, message, length, flags,
51 dest_addr, dest_len);
54 r= ioctl(sock, NWIOGUDPOPT, &udpopt);
55 if (r != -1 || errno != ENOTTY)
57 if (r == -1)
58 return r;
59 return _udp_sendto(sock, message, length, flags,
60 dest_addr, dest_len, &udpopt);
63 r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype);
64 if (r != -1 || errno != ENOTTY)
66 if (r == -1) {
67 return r;
70 if (uds_sotype == SOCK_DGRAM) {
72 return _uds_sendto_dgram(sock, message,
73 length, flags,dest_addr, dest_len);
74 } else {
76 return _uds_sendto_conn(sock, message,
77 length, flags, dest_addr, dest_len);
82 ip_hdr_t *ip_hdr;
83 int ihl;
84 icmp_hdr_t *icmp_hdr;
85 struct sockaddr_in *sinp;
87 sinp = (struct sockaddr_in *) __UNCONST(dest_addr);
88 if (sinp->sin_family != AF_INET)
90 errno= EAFNOSUPPORT;
91 return -1;
94 /* raw */
95 ip_hdr= (ip_hdr_t *)message;
96 ip_hdr->ih_dst= sinp->sin_addr.s_addr;
98 return write(sock, message, length);
101 #if DEBUG
102 fprintf(stderr, "sendto: not implemented for fd %d\n", sock);
103 #endif
104 errno= ENOSYS;
105 return -1;
108 static ssize_t _tcp_sendto(int sock, const void *message, size_t length,
109 int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
112 if (flags != 0) {
113 #if DEBUG
114 fprintf(stderr, "sendto(tcp): flags not implemented\n");
115 #endif
116 errno= ENOSYS;
117 return -1;
120 /* Silently ignore destination, if given. */
122 return write(sock, message, length);
125 static ssize_t _udp_sendto(int sock, const void *message, size_t length,
126 int flags, const struct sockaddr *dest_addr, socklen_t dest_len,
127 nwio_udpopt_t *udpoptp)
129 int r, t_errno;
130 size_t buflen;
131 void *buf;
132 struct sockaddr_in *sinp;
133 udp_io_hdr_t *io_hdrp;
135 if (flags)
137 #if DEBUG
138 fprintf(stderr, "sendto(udp): flags not implemented\n");
139 #endif
140 errno= ENOSYS;
141 return -1;
144 if (udpoptp->nwuo_flags & NWUO_RWDATONLY)
145 return write(sock, message, length);
147 if ((udpoptp->nwuo_flags & NWUO_RP_ANY) ||
148 (udpoptp->nwuo_flags & NWUO_RA_ANY))
150 if (!dest_addr)
152 errno= ENOTCONN;
153 return -1;
156 /* Check destination address */
157 if (dest_len < sizeof(*sinp))
159 errno= EINVAL;
160 return -1;
162 sinp= (struct sockaddr_in *) __UNCONST(dest_addr);
163 if (sinp->sin_family != AF_INET)
165 errno= EAFNOSUPPORT;
166 return -1;
170 buflen= sizeof(*io_hdrp) + length;
171 if (buflen < length)
173 /* Overflow */
174 errno= EMSGSIZE;
175 return -1;
177 buf= malloc(buflen);
178 if (buf == NULL)
179 return -1;
181 io_hdrp= buf;
182 io_hdrp->uih_src_addr= 0; /* Unused */
183 io_hdrp->uih_src_port= 0; /* Will cause error if NWUO_LP_ANY */
184 if (udpoptp->nwuo_flags & NWUO_RA_ANY)
185 io_hdrp->uih_dst_addr= sinp->sin_addr.s_addr;
186 else
187 io_hdrp->uih_dst_addr= 0;
188 if (udpoptp->nwuo_flags & NWUO_RP_ANY)
189 io_hdrp->uih_dst_port= sinp->sin_port;
190 else
191 io_hdrp->uih_dst_port= 0;
192 io_hdrp->uih_ip_opt_len= 0;
193 io_hdrp->uih_data_len= 0;
195 memcpy(&io_hdrp[1], message, length);
196 r= write(sock, buf, buflen);
197 if (r == -1)
199 t_errno= errno;
200 free(buf);
201 errno= t_errno;
202 return -1;
204 assert(r == buflen);
205 free(buf);
206 return length;
209 static ssize_t _uds_sendto_conn(int sock, const void *message, size_t length,
210 int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
213 /* for connection oriented unix domain sockets (SOCK_STREAM /
214 * SOCK_SEQPACKET)
217 if (flags != 0) {
218 #if DEBUG
219 fprintf(stderr, "sendto(uds): flags not implemented\n");
220 #endif
221 errno= ENOSYS;
222 return -1;
225 /* Silently ignore destination, if given. */
227 return write(sock, message, length);
230 static ssize_t _uds_sendto_dgram(int sock, const void *message, size_t length,
231 int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
233 int r;
235 /* for connectionless unix domain sockets (SOCK_DGRAM) */
237 if (flags != 0) {
238 #if DEBUG
239 fprintf(stderr, "sendto(uds): flags not implemented\n");
240 #endif
241 errno= ENOSYS;
242 return -1;
245 if (dest_addr == NULL) {
246 errno = EFAULT;
247 return -1;
250 /* set the target address */
251 r= ioctl(sock, NWIOSUDSTADDR, (void *) __UNCONST(dest_addr));
252 if (r == -1) {
253 return r;
256 /* do the send */
257 return write(sock, message, length);