1433d6423SLionel Sambuc #include <sys/cdefs.h> 2433d6423SLionel Sambuc #include "namespace.h" 3433d6423SLionel Sambuc 4433d6423SLionel Sambuc #include <assert.h> 5433d6423SLionel Sambuc #include <errno.h> 6433d6423SLionel Sambuc #include <stdlib.h> 7433d6423SLionel Sambuc #include <stdio.h> 8433d6423SLionel Sambuc #include <string.h> 9433d6423SLionel Sambuc #include <unistd.h> 10433d6423SLionel Sambuc #include <sys/ioctl.h> 11433d6423SLionel Sambuc #include <sys/socket.h> 12433d6423SLionel Sambuc #include <netinet/in.h> 13433d6423SLionel Sambuc 14433d6423SLionel Sambuc #include <net/gen/in.h> 15433d6423SLionel Sambuc #include <net/gen/tcp.h> 16433d6423SLionel Sambuc #include <net/gen/tcp_io.h> 17433d6423SLionel Sambuc #include <net/gen/udp.h> 18433d6423SLionel Sambuc #include <net/gen/udp_hdr.h> 19433d6423SLionel Sambuc #include <net/gen/udp_io.h> 20433d6423SLionel Sambuc 217f5f010bSBen Gras #include <net/gen/ip_hdr.h> 22*17580212SDavid van Moolenbroek #include <net/gen/ip_io.h> 237f5f010bSBen Gras 24433d6423SLionel Sambuc #define DEBUG 0 25433d6423SLionel Sambuc 26433d6423SLionel Sambuc static ssize_t _tcp_recvfrom(int sock, void *__restrict buffer, size_t length, 27433d6423SLionel Sambuc int flags, struct sockaddr *__restrict address, 28433d6423SLionel Sambuc socklen_t *__restrict address_len, nwio_tcpconf_t *tcpconfp); 29433d6423SLionel Sambuc static ssize_t _udp_recvfrom(int sock, void *__restrict buffer, size_t length, 30433d6423SLionel Sambuc int flags, struct sockaddr *__restrict address, 31433d6423SLionel Sambuc socklen_t *__restrict address_len, nwio_udpopt_t *udpoptp); 32433d6423SLionel Sambuc static ssize_t _uds_recvfrom_conn(int sock, void *__restrict buffer, 33433d6423SLionel Sambuc size_t length, int flags, struct sockaddr *__restrict address, 34433d6423SLionel Sambuc socklen_t *__restrict address_len, struct sockaddr_un *uds_addr); 35433d6423SLionel Sambuc static ssize_t _uds_recvfrom_dgram(int sock, void *__restrict buffer, 36433d6423SLionel Sambuc size_t length, int flags, struct sockaddr *__restrict address, 37433d6423SLionel Sambuc socklen_t *__restrict address_len); 38433d6423SLionel Sambuc 39433d6423SLionel Sambuc ssize_t recvfrom(int sock, void *__restrict buffer, size_t length, 40433d6423SLionel Sambuc int flags, struct sockaddr *__restrict address, 41433d6423SLionel Sambuc socklen_t *__restrict address_len) 42433d6423SLionel Sambuc { 43433d6423SLionel Sambuc int r; 44433d6423SLionel Sambuc nwio_tcpconf_t tcpconf; 45433d6423SLionel Sambuc nwio_udpopt_t udpopt; 46*17580212SDavid van Moolenbroek nwio_ipopt_t ipopt; 47433d6423SLionel Sambuc struct sockaddr_un uds_addr; 48433d6423SLionel Sambuc int uds_sotype = -1; 49433d6423SLionel Sambuc 50433d6423SLionel Sambuc #if DEBUG 51433d6423SLionel Sambuc fprintf(stderr, "recvfrom: for fd %d\n", sock); 52433d6423SLionel Sambuc #endif 53433d6423SLionel Sambuc 54433d6423SLionel Sambuc r= ioctl(sock, NWIOGTCPCONF, &tcpconf); 55433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 56433d6423SLionel Sambuc { 57433d6423SLionel Sambuc if (r == -1) 58433d6423SLionel Sambuc return r; 59433d6423SLionel Sambuc return _tcp_recvfrom(sock, buffer, length, flags, 60433d6423SLionel Sambuc address, address_len, &tcpconf); 61433d6423SLionel Sambuc } 62433d6423SLionel Sambuc 63433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDPOPT, &udpopt); 64433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 65433d6423SLionel Sambuc { 66433d6423SLionel Sambuc if (r == -1) 67433d6423SLionel Sambuc return r; 68433d6423SLionel Sambuc return _udp_recvfrom(sock, buffer, length, flags, 69433d6423SLionel Sambuc address, address_len, &udpopt); 70433d6423SLionel Sambuc } 71433d6423SLionel Sambuc 72433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); 73433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 74433d6423SLionel Sambuc { 75433d6423SLionel Sambuc 76433d6423SLionel Sambuc if (r == -1) { 77433d6423SLionel Sambuc return r; 78433d6423SLionel Sambuc } 79433d6423SLionel Sambuc 80433d6423SLionel Sambuc if (uds_sotype == SOCK_DGRAM) { 81433d6423SLionel Sambuc return _uds_recvfrom_dgram(sock, buffer, 82433d6423SLionel Sambuc length, flags, address, address_len); 83433d6423SLionel Sambuc } else { 84433d6423SLionel Sambuc return _uds_recvfrom_conn(sock, buffer, 85433d6423SLionel Sambuc length, flags, address, address_len, 86433d6423SLionel Sambuc &uds_addr); 87433d6423SLionel Sambuc } 88433d6423SLionel Sambuc } 89433d6423SLionel Sambuc 90*17580212SDavid van Moolenbroek r= ioctl(sock, NWIOGIPOPT, &ipopt); 91*17580212SDavid van Moolenbroek if (r != -1 || errno != ENOTTY) 927f5f010bSBen Gras { 937f5f010bSBen Gras ip_hdr_t *ip_hdr; 945dd8da10SDavid van Moolenbroek int rd; 957f5f010bSBen Gras struct sockaddr_in sin; 967f5f010bSBen Gras 97*17580212SDavid van Moolenbroek if (r == -1) { 98*17580212SDavid van Moolenbroek return r; 99*17580212SDavid van Moolenbroek } 100*17580212SDavid van Moolenbroek 1017f5f010bSBen Gras rd = read(sock, buffer, length); 1027f5f010bSBen Gras 1037f5f010bSBen Gras if(rd < 0) return rd; 1047f5f010bSBen Gras 1055dd8da10SDavid van Moolenbroek assert((size_t)rd >= sizeof(*ip_hdr)); 1067f5f010bSBen Gras 1077f5f010bSBen Gras ip_hdr= buffer; 1087f5f010bSBen Gras 1097f5f010bSBen Gras if (address != NULL) 1107f5f010bSBen Gras { 1117f5f010bSBen Gras int len; 1127f5f010bSBen Gras memset(&sin, 0, sizeof(sin)); 1137f5f010bSBen Gras sin.sin_family= AF_INET; 1147f5f010bSBen Gras sin.sin_addr.s_addr= ip_hdr->ih_src; 1157f5f010bSBen Gras sin.sin_len= sizeof(sin); 1167f5f010bSBen Gras len= *address_len; 1175dd8da10SDavid van Moolenbroek if ((size_t)len > sizeof(sin)) 1185dd8da10SDavid van Moolenbroek len= (int)sizeof(sin); 1197f5f010bSBen Gras memcpy(address, &sin, len); 1207f5f010bSBen Gras *address_len= sizeof(sin); 1217f5f010bSBen Gras } 1227f5f010bSBen Gras 1237f5f010bSBen Gras return rd; 1247f5f010bSBen Gras } 1257f5f010bSBen Gras 126433d6423SLionel Sambuc #if DEBUG 127433d6423SLionel Sambuc fprintf(stderr, "recvfrom: not implemented for fd %d\n", sock); 128433d6423SLionel Sambuc #endif 1299d3fcac4SLionel Sambuc abort(); 130433d6423SLionel Sambuc } 131433d6423SLionel Sambuc 132433d6423SLionel Sambuc static ssize_t _tcp_recvfrom(int sock, void *__restrict buffer, size_t length, 133433d6423SLionel Sambuc int flags, struct sockaddr *__restrict address, 134433d6423SLionel Sambuc socklen_t *__restrict address_len, nwio_tcpconf_t *tcpconfp) 135433d6423SLionel Sambuc { 136433d6423SLionel Sambuc int r; 137433d6423SLionel Sambuc size_t len; 138433d6423SLionel Sambuc struct sockaddr_in sin; 139433d6423SLionel Sambuc 140433d6423SLionel Sambuc if (flags != 0) 141433d6423SLionel Sambuc { 142433d6423SLionel Sambuc #if DEBUG 143433d6423SLionel Sambuc fprintf(stderr, "recvfrom(tcp): flags not implemented\n"); 144433d6423SLionel Sambuc #endif 145433d6423SLionel Sambuc errno= ENOSYS; 146433d6423SLionel Sambuc return -1; 147433d6423SLionel Sambuc } 148433d6423SLionel Sambuc 149433d6423SLionel Sambuc r = read(sock, buffer, length); 150433d6423SLionel Sambuc 151433d6423SLionel Sambuc if (r >= 0 && address != NULL) 152433d6423SLionel Sambuc { 153433d6423SLionel Sambuc sin.sin_family= AF_INET; 154433d6423SLionel Sambuc sin.sin_addr.s_addr= tcpconfp->nwtc_remaddr; 155433d6423SLionel Sambuc sin.sin_port= tcpconfp->nwtc_remport; 156433d6423SLionel Sambuc sin.sin_len= sizeof(sin); 157433d6423SLionel Sambuc len= *address_len; 158433d6423SLionel Sambuc if (len > sizeof(sin)) 159433d6423SLionel Sambuc len= sizeof(sin); 160433d6423SLionel Sambuc memcpy(address, &sin, len); 161433d6423SLionel Sambuc *address_len= sizeof(sin); 162433d6423SLionel Sambuc } 163433d6423SLionel Sambuc 164433d6423SLionel Sambuc return r; 165433d6423SLionel Sambuc } 166433d6423SLionel Sambuc 167433d6423SLionel Sambuc static ssize_t _udp_recvfrom(int sock, void *__restrict buffer, size_t length, 168433d6423SLionel Sambuc int flags, struct sockaddr *__restrict address, 169433d6423SLionel Sambuc socklen_t *__restrict address_len, nwio_udpopt_t *udpoptp) 170433d6423SLionel Sambuc { 171433d6423SLionel Sambuc int r, t_errno; 172433d6423SLionel Sambuc size_t buflen, len; 173433d6423SLionel Sambuc void *buf; 174433d6423SLionel Sambuc udp_io_hdr_t *io_hdrp; 175433d6423SLionel Sambuc struct sockaddr_in sin; 176433d6423SLionel Sambuc 177433d6423SLionel Sambuc if (flags) 178433d6423SLionel Sambuc { 179433d6423SLionel Sambuc #if DEBUG 180433d6423SLionel Sambuc fprintf(stderr, "recvfrom(udp): flags not implemented\n"); 181433d6423SLionel Sambuc #endif 182433d6423SLionel Sambuc errno= ENOSYS; 183433d6423SLionel Sambuc return -1; 184433d6423SLionel Sambuc } 185433d6423SLionel Sambuc 186433d6423SLionel Sambuc if (udpoptp->nwuo_flags & NWUO_RWDATONLY) 187433d6423SLionel Sambuc { 188433d6423SLionel Sambuc if (address != NULL && 189433d6423SLionel Sambuc (udpoptp->nwuo_flags & (NWUO_RA_SET | NWUO_RP_SET)) != 190433d6423SLionel Sambuc (NWUO_RA_SET | NWUO_RP_SET)) 191433d6423SLionel Sambuc { 192433d6423SLionel Sambuc 193433d6423SLionel Sambuc #if DEBUG 194433d6423SLionel Sambuc fprintf(stderr, 195433d6423SLionel Sambuc "recvfrom(udp): RWDATONLY on unconnected socket\n"); 196433d6423SLionel Sambuc #endif 197433d6423SLionel Sambuc errno= ENOTCONN; 198433d6423SLionel Sambuc return -1; 199433d6423SLionel Sambuc } 200433d6423SLionel Sambuc 201433d6423SLionel Sambuc r= read(sock, buffer, length); 202433d6423SLionel Sambuc if (r == -1) 203433d6423SLionel Sambuc return r; 204433d6423SLionel Sambuc 205433d6423SLionel Sambuc if (address != NULL) 206433d6423SLionel Sambuc { 207433d6423SLionel Sambuc sin.sin_family= AF_INET; 208433d6423SLionel Sambuc sin.sin_addr.s_addr= udpoptp->nwuo_remaddr; 209433d6423SLionel Sambuc sin.sin_port= udpoptp->nwuo_remport; 210433d6423SLionel Sambuc sin.sin_len= sizeof(sin); 211433d6423SLionel Sambuc len= *address_len; 212433d6423SLionel Sambuc if (len > sizeof(sin)) 213433d6423SLionel Sambuc len= sizeof(sin); 214433d6423SLionel Sambuc memcpy(address, &sin, len); 215433d6423SLionel Sambuc *address_len= sizeof(sin); 216433d6423SLionel Sambuc } 217433d6423SLionel Sambuc 218433d6423SLionel Sambuc return r; 219433d6423SLionel Sambuc } 220433d6423SLionel Sambuc 221433d6423SLionel Sambuc buflen= sizeof(*io_hdrp) + length; 222433d6423SLionel Sambuc if (buflen < length) 223433d6423SLionel Sambuc { 224433d6423SLionel Sambuc /* Overflow */ 225433d6423SLionel Sambuc errno= EMSGSIZE; 226433d6423SLionel Sambuc return -1; 227433d6423SLionel Sambuc } 228433d6423SLionel Sambuc buf= malloc(buflen); 229433d6423SLionel Sambuc if (buf == NULL) 230433d6423SLionel Sambuc return -1; 231433d6423SLionel Sambuc 232433d6423SLionel Sambuc r= read(sock, buf, buflen); 233433d6423SLionel Sambuc if (r == -1) 234433d6423SLionel Sambuc { 235433d6423SLionel Sambuc t_errno= errno; 236433d6423SLionel Sambuc #if DEBUG 237433d6423SLionel Sambuc fprintf(stderr, "recvfrom(udp): read failed: %s\n", 238433d6423SLionel Sambuc strerror(errno)); 239433d6423SLionel Sambuc fprintf(stderr, "udp opt flags = 0x%x\n", udpoptp->nwuo_flags); 240433d6423SLionel Sambuc #endif 241433d6423SLionel Sambuc free(buf); 242433d6423SLionel Sambuc errno= t_errno; 243433d6423SLionel Sambuc return -1; 244433d6423SLionel Sambuc } 245433d6423SLionel Sambuc 2465dd8da10SDavid van Moolenbroek assert((size_t)r >= sizeof(*io_hdrp)); 247433d6423SLionel Sambuc length= r-sizeof(*io_hdrp); 248433d6423SLionel Sambuc 249433d6423SLionel Sambuc io_hdrp= buf; 250433d6423SLionel Sambuc memcpy(buffer, &io_hdrp[1], length); 251433d6423SLionel Sambuc 252433d6423SLionel Sambuc if (address != NULL) 253433d6423SLionel Sambuc { 254433d6423SLionel Sambuc sin.sin_family= AF_INET; 255433d6423SLionel Sambuc sin.sin_addr.s_addr= io_hdrp->uih_src_addr; 256433d6423SLionel Sambuc sin.sin_port= io_hdrp->uih_src_port; 257433d6423SLionel Sambuc sin.sin_len= sizeof(sin); 258433d6423SLionel Sambuc len= *address_len; 259433d6423SLionel Sambuc if (len > sizeof(sin)) 260433d6423SLionel Sambuc len= sizeof(sin); 261433d6423SLionel Sambuc memcpy(address, &sin, len); 262433d6423SLionel Sambuc *address_len= sizeof(sin); 263433d6423SLionel Sambuc } 264433d6423SLionel Sambuc free(buf); 265433d6423SLionel Sambuc return length; 266433d6423SLionel Sambuc } 267433d6423SLionel Sambuc 268433d6423SLionel Sambuc static ssize_t _uds_recvfrom_conn(int sock, void *__restrict buffer, 269433d6423SLionel Sambuc size_t length, int flags, struct sockaddr *__restrict address, 270433d6423SLionel Sambuc socklen_t *__restrict address_len, struct sockaddr_un *uds_addr) 271433d6423SLionel Sambuc { 272433d6423SLionel Sambuc int r; 273433d6423SLionel Sambuc size_t len; 274433d6423SLionel Sambuc 275433d6423SLionel Sambuc /* for connection oriented unix domain sockets (SOCK_STREAM / 276433d6423SLionel Sambuc * SOCK_SEQPACKET) 277433d6423SLionel Sambuc */ 278433d6423SLionel Sambuc 279433d6423SLionel Sambuc if (flags != 0) 280433d6423SLionel Sambuc { 281433d6423SLionel Sambuc #if DEBUG 282433d6423SLionel Sambuc fprintf(stderr, "recvfrom(uds): flags not implemented\n"); 283433d6423SLionel Sambuc #endif 284433d6423SLionel Sambuc errno= ENOSYS; 285433d6423SLionel Sambuc return -1; 286433d6423SLionel Sambuc } 287433d6423SLionel Sambuc 288433d6423SLionel Sambuc r = read(sock, buffer, length); 289433d6423SLionel Sambuc 290433d6423SLionel Sambuc if (r >= 0 && address != NULL) 291433d6423SLionel Sambuc { 292433d6423SLionel Sambuc 293433d6423SLionel Sambuc len= *address_len; 294433d6423SLionel Sambuc if (len > sizeof(struct sockaddr_un)) 295433d6423SLionel Sambuc len= sizeof(struct sockaddr_un); 296433d6423SLionel Sambuc memcpy(address, uds_addr, len); 297433d6423SLionel Sambuc *address_len= sizeof(struct sockaddr_un); 298433d6423SLionel Sambuc } 299433d6423SLionel Sambuc 300433d6423SLionel Sambuc return r; 301433d6423SLionel Sambuc } 302433d6423SLionel Sambuc 303433d6423SLionel Sambuc static ssize_t _uds_recvfrom_dgram(int sock, void *__restrict buffer, 304433d6423SLionel Sambuc size_t length, int flags, struct sockaddr *__restrict address, 305433d6423SLionel Sambuc socklen_t *__restrict address_len) 306433d6423SLionel Sambuc { 307433d6423SLionel Sambuc int r; 308433d6423SLionel Sambuc size_t len; 309433d6423SLionel Sambuc 310433d6423SLionel Sambuc /* for connectionless unix domain sockets (SOCK_DGRAM) */ 311433d6423SLionel Sambuc 312433d6423SLionel Sambuc if (flags != 0) 313433d6423SLionel Sambuc { 314433d6423SLionel Sambuc #if DEBUG 315433d6423SLionel Sambuc fprintf(stderr, "recvfrom(uds): flags not implemented\n"); 316433d6423SLionel Sambuc #endif 317433d6423SLionel Sambuc errno= ENOSYS; 318433d6423SLionel Sambuc return -1; 319433d6423SLionel Sambuc } 320433d6423SLionel Sambuc 321433d6423SLionel Sambuc r = read(sock, buffer, length); 322433d6423SLionel Sambuc 323433d6423SLionel Sambuc if (r >= 0 && address != NULL) 324433d6423SLionel Sambuc { 325433d6423SLionel Sambuc len= *address_len; 326433d6423SLionel Sambuc if (len > sizeof(struct sockaddr_un)) 327433d6423SLionel Sambuc len= sizeof(struct sockaddr_un); 328433d6423SLionel Sambuc ioctl(sock, NWIOGUDSFADDR, address); 329433d6423SLionel Sambuc *address_len= sizeof(struct sockaddr_un); 330433d6423SLionel Sambuc } 331433d6423SLionel Sambuc 332433d6423SLionel Sambuc return r; 333433d6423SLionel Sambuc } 334433d6423SLionel Sambuc 335