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