1 #include <sys/cdefs.h> 2 #include "namespace.h" 3 4 #include <assert.h> 5 #include <errno.h> 6 #include <stdlib.h> 7 #include <stdio.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/tcp.h> 16 #include <net/gen/tcp_io.h> 17 #include <net/gen/udp.h> 18 #include <net/gen/udp_hdr.h> 19 #include <net/gen/udp_io.h> 20 21 #include <net/gen/ip_hdr.h> 22 #include <net/gen/ip_io.h> 23 24 #define DEBUG 0 25 26 static ssize_t _tcp_recvfrom(int sock, void *__restrict buffer, size_t length, 27 int flags, struct sockaddr *__restrict address, 28 socklen_t *__restrict address_len, nwio_tcpconf_t *tcpconfp); 29 static ssize_t _udp_recvfrom(int sock, void *__restrict buffer, size_t length, 30 int flags, struct sockaddr *__restrict address, 31 socklen_t *__restrict address_len, nwio_udpopt_t *udpoptp); 32 static ssize_t _uds_recvfrom_conn(int sock, void *__restrict buffer, 33 size_t length, int flags, struct sockaddr *__restrict address, 34 socklen_t *__restrict address_len, struct sockaddr_un *uds_addr); 35 static ssize_t _uds_recvfrom_dgram(int sock, void *__restrict buffer, 36 size_t length, int flags, struct sockaddr *__restrict address, 37 socklen_t *__restrict address_len); 38 39 ssize_t recvfrom(int sock, void *__restrict buffer, size_t length, 40 int flags, struct sockaddr *__restrict address, 41 socklen_t *__restrict address_len) 42 { 43 int r; 44 nwio_tcpconf_t tcpconf; 45 nwio_udpopt_t udpopt; 46 nwio_ipopt_t ipopt; 47 struct sockaddr_un uds_addr; 48 int uds_sotype = -1; 49 50 #if DEBUG 51 fprintf(stderr, "recvfrom: for fd %d\n", sock); 52 #endif 53 54 r= ioctl(sock, NWIOGTCPCONF, &tcpconf); 55 if (r != -1 || errno != ENOTTY) 56 { 57 if (r == -1) 58 return r; 59 return _tcp_recvfrom(sock, buffer, length, flags, 60 address, address_len, &tcpconf); 61 } 62 63 r= ioctl(sock, NWIOGUDPOPT, &udpopt); 64 if (r != -1 || errno != ENOTTY) 65 { 66 if (r == -1) 67 return r; 68 return _udp_recvfrom(sock, buffer, length, flags, 69 address, address_len, &udpopt); 70 } 71 72 r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); 73 if (r != -1 || errno != ENOTTY) 74 { 75 76 if (r == -1) { 77 return r; 78 } 79 80 if (uds_sotype == SOCK_DGRAM) { 81 return _uds_recvfrom_dgram(sock, buffer, 82 length, flags, address, address_len); 83 } else { 84 return _uds_recvfrom_conn(sock, buffer, 85 length, flags, address, address_len, 86 &uds_addr); 87 } 88 } 89 90 r= ioctl(sock, NWIOGIPOPT, &ipopt); 91 if (r != -1 || errno != ENOTTY) 92 { 93 ip_hdr_t *ip_hdr; 94 int rd; 95 struct sockaddr_in sin; 96 97 if (r == -1) { 98 return r; 99 } 100 101 rd = read(sock, buffer, length); 102 103 if(rd < 0) return rd; 104 105 assert((size_t)rd >= sizeof(*ip_hdr)); 106 107 ip_hdr= buffer; 108 109 if (address != NULL) 110 { 111 int len; 112 memset(&sin, 0, sizeof(sin)); 113 sin.sin_family= AF_INET; 114 sin.sin_addr.s_addr= ip_hdr->ih_src; 115 sin.sin_len= sizeof(sin); 116 len= *address_len; 117 if ((size_t)len > sizeof(sin)) 118 len= (int)sizeof(sin); 119 memcpy(address, &sin, len); 120 *address_len= sizeof(sin); 121 } 122 123 return rd; 124 } 125 126 #if DEBUG 127 fprintf(stderr, "recvfrom: not implemented for fd %d\n", sock); 128 #endif 129 abort(); 130 } 131 132 static ssize_t _tcp_recvfrom(int sock, void *__restrict buffer, size_t length, 133 int flags, struct sockaddr *__restrict address, 134 socklen_t *__restrict address_len, nwio_tcpconf_t *tcpconfp) 135 { 136 int r; 137 size_t len; 138 struct sockaddr_in sin; 139 140 if (flags != 0) 141 { 142 #if DEBUG 143 fprintf(stderr, "recvfrom(tcp): flags not implemented\n"); 144 #endif 145 errno= ENOSYS; 146 return -1; 147 } 148 149 r = read(sock, buffer, length); 150 151 if (r >= 0 && address != NULL) 152 { 153 sin.sin_family= AF_INET; 154 sin.sin_addr.s_addr= tcpconfp->nwtc_remaddr; 155 sin.sin_port= tcpconfp->nwtc_remport; 156 sin.sin_len= sizeof(sin); 157 len= *address_len; 158 if (len > sizeof(sin)) 159 len= sizeof(sin); 160 memcpy(address, &sin, len); 161 *address_len= sizeof(sin); 162 } 163 164 return r; 165 } 166 167 static ssize_t _udp_recvfrom(int sock, void *__restrict buffer, size_t length, 168 int flags, struct sockaddr *__restrict address, 169 socklen_t *__restrict address_len, nwio_udpopt_t *udpoptp) 170 { 171 int r, t_errno; 172 size_t buflen, len; 173 void *buf; 174 udp_io_hdr_t *io_hdrp; 175 struct sockaddr_in sin; 176 177 if (flags) 178 { 179 #if DEBUG 180 fprintf(stderr, "recvfrom(udp): flags not implemented\n"); 181 #endif 182 errno= ENOSYS; 183 return -1; 184 } 185 186 if (udpoptp->nwuo_flags & NWUO_RWDATONLY) 187 { 188 if (address != NULL && 189 (udpoptp->nwuo_flags & (NWUO_RA_SET | NWUO_RP_SET)) != 190 (NWUO_RA_SET | NWUO_RP_SET)) 191 { 192 193 #if DEBUG 194 fprintf(stderr, 195 "recvfrom(udp): RWDATONLY on unconnected socket\n"); 196 #endif 197 errno= ENOTCONN; 198 return -1; 199 } 200 201 r= read(sock, buffer, length); 202 if (r == -1) 203 return r; 204 205 if (address != NULL) 206 { 207 sin.sin_family= AF_INET; 208 sin.sin_addr.s_addr= udpoptp->nwuo_remaddr; 209 sin.sin_port= udpoptp->nwuo_remport; 210 sin.sin_len= sizeof(sin); 211 len= *address_len; 212 if (len > sizeof(sin)) 213 len= sizeof(sin); 214 memcpy(address, &sin, len); 215 *address_len= sizeof(sin); 216 } 217 218 return r; 219 } 220 221 buflen= sizeof(*io_hdrp) + length; 222 if (buflen < length) 223 { 224 /* Overflow */ 225 errno= EMSGSIZE; 226 return -1; 227 } 228 buf= malloc(buflen); 229 if (buf == NULL) 230 return -1; 231 232 r= read(sock, buf, buflen); 233 if (r == -1) 234 { 235 t_errno= errno; 236 #if DEBUG 237 fprintf(stderr, "recvfrom(udp): read failed: %s\n", 238 strerror(errno)); 239 fprintf(stderr, "udp opt flags = 0x%x\n", udpoptp->nwuo_flags); 240 #endif 241 free(buf); 242 errno= t_errno; 243 return -1; 244 } 245 246 assert((size_t)r >= sizeof(*io_hdrp)); 247 length= r-sizeof(*io_hdrp); 248 249 io_hdrp= buf; 250 memcpy(buffer, &io_hdrp[1], length); 251 252 if (address != NULL) 253 { 254 sin.sin_family= AF_INET; 255 sin.sin_addr.s_addr= io_hdrp->uih_src_addr; 256 sin.sin_port= io_hdrp->uih_src_port; 257 sin.sin_len= sizeof(sin); 258 len= *address_len; 259 if (len > sizeof(sin)) 260 len= sizeof(sin); 261 memcpy(address, &sin, len); 262 *address_len= sizeof(sin); 263 } 264 free(buf); 265 return length; 266 } 267 268 static ssize_t _uds_recvfrom_conn(int sock, void *__restrict buffer, 269 size_t length, int flags, struct sockaddr *__restrict address, 270 socklen_t *__restrict address_len, struct sockaddr_un *uds_addr) 271 { 272 int r; 273 size_t len; 274 275 /* for connection oriented unix domain sockets (SOCK_STREAM / 276 * SOCK_SEQPACKET) 277 */ 278 279 if (flags != 0) 280 { 281 #if DEBUG 282 fprintf(stderr, "recvfrom(uds): flags not implemented\n"); 283 #endif 284 errno= ENOSYS; 285 return -1; 286 } 287 288 r = read(sock, buffer, length); 289 290 if (r >= 0 && address != NULL) 291 { 292 293 len= *address_len; 294 if (len > sizeof(struct sockaddr_un)) 295 len= sizeof(struct sockaddr_un); 296 memcpy(address, uds_addr, len); 297 *address_len= sizeof(struct sockaddr_un); 298 } 299 300 return r; 301 } 302 303 static ssize_t _uds_recvfrom_dgram(int sock, void *__restrict buffer, 304 size_t length, int flags, struct sockaddr *__restrict address, 305 socklen_t *__restrict address_len) 306 { 307 int r; 308 size_t len; 309 310 /* for connectionless unix domain sockets (SOCK_DGRAM) */ 311 312 if (flags != 0) 313 { 314 #if DEBUG 315 fprintf(stderr, "recvfrom(uds): flags not implemented\n"); 316 #endif 317 errno= ENOSYS; 318 return -1; 319 } 320 321 r = read(sock, buffer, length); 322 323 if (r >= 0 && address != NULL) 324 { 325 len= *address_len; 326 if (len > sizeof(struct sockaddr_un)) 327 len= sizeof(struct sockaddr_un); 328 ioctl(sock, NWIOGUDSFADDR, address); 329 *address_len= sizeof(struct sockaddr_un); 330 } 331 332 return r; 333 } 334 335