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