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