1433d6423SLionel Sambuc #include <sys/cdefs.h> 2433d6423SLionel Sambuc #include "namespace.h" 3*c38dbb97SDavid van Moolenbroek #include <lib.h> 4433d6423SLionel Sambuc 5433d6423SLionel Sambuc #include <assert.h> 6433d6423SLionel Sambuc #include <errno.h> 7433d6423SLionel Sambuc #include <stdlib.h> 8433d6423SLionel Sambuc #include <stdio.h> 9433d6423SLionel Sambuc #include <string.h> 10433d6423SLionel Sambuc #include <unistd.h> 11433d6423SLionel Sambuc #include <sys/ioctl.h> 12433d6423SLionel Sambuc #include <sys/socket.h> 13433d6423SLionel Sambuc #include <netinet/in.h> 14433d6423SLionel Sambuc 15433d6423SLionel Sambuc #include <net/gen/in.h> 16433d6423SLionel Sambuc #include <net/gen/tcp.h> 17433d6423SLionel Sambuc #include <net/gen/tcp_io.h> 18433d6423SLionel Sambuc #include <net/gen/udp.h> 19433d6423SLionel Sambuc #include <net/gen/udp_hdr.h> 20433d6423SLionel Sambuc #include <net/gen/udp_io.h> 21433d6423SLionel Sambuc 227f5f010bSBen Gras #include <net/gen/ip_hdr.h> 2317580212SDavid van Moolenbroek #include <net/gen/ip_io.h> 247f5f010bSBen Gras 25433d6423SLionel Sambuc #define DEBUG 0 26433d6423SLionel Sambuc 27433d6423SLionel Sambuc static ssize_t _tcp_recvfrom(int sock, void *__restrict buffer, size_t length, 28433d6423SLionel Sambuc int flags, struct sockaddr *__restrict address, 29433d6423SLionel Sambuc socklen_t *__restrict address_len, nwio_tcpconf_t *tcpconfp); 30433d6423SLionel Sambuc static ssize_t _udp_recvfrom(int sock, void *__restrict buffer, size_t length, 31433d6423SLionel Sambuc int flags, struct sockaddr *__restrict address, 32433d6423SLionel Sambuc socklen_t *__restrict address_len, nwio_udpopt_t *udpoptp); 33433d6423SLionel Sambuc static ssize_t _uds_recvfrom_conn(int sock, void *__restrict buffer, 34433d6423SLionel Sambuc size_t length, int flags, struct sockaddr *__restrict address, 35433d6423SLionel Sambuc socklen_t *__restrict address_len, struct sockaddr_un *uds_addr); 36433d6423SLionel Sambuc static ssize_t _uds_recvfrom_dgram(int sock, void *__restrict buffer, 37433d6423SLionel Sambuc size_t length, int flags, struct sockaddr *__restrict address, 38433d6423SLionel Sambuc socklen_t *__restrict address_len); 39433d6423SLionel Sambuc 40*c38dbb97SDavid van Moolenbroek /* 41*c38dbb97SDavid van Moolenbroek * Receive a message from a socket. 42*c38dbb97SDavid van Moolenbroek */ 43*c38dbb97SDavid van Moolenbroek static ssize_t 44*c38dbb97SDavid van Moolenbroek __recvfrom(int fd, void * __restrict buffer, size_t length, int flags, 45*c38dbb97SDavid van Moolenbroek struct sockaddr * __restrict address, 46*c38dbb97SDavid van Moolenbroek socklen_t * __restrict address_len) 47*c38dbb97SDavid van Moolenbroek { 48*c38dbb97SDavid van Moolenbroek message m; 49*c38dbb97SDavid van Moolenbroek ssize_t r; 50*c38dbb97SDavid van Moolenbroek 51*c38dbb97SDavid van Moolenbroek if (address != NULL && address_len == NULL) { 52*c38dbb97SDavid van Moolenbroek errno = EFAULT; 53*c38dbb97SDavid van Moolenbroek return -1; 54*c38dbb97SDavid van Moolenbroek } 55*c38dbb97SDavid van Moolenbroek 56*c38dbb97SDavid van Moolenbroek memset(&m, 0, sizeof(m)); 57*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sendrecv.fd = fd; 58*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sendrecv.buf = (vir_bytes)buffer; 59*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sendrecv.len = length; 60*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sendrecv.flags = flags; 61*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sendrecv.addr = (vir_bytes)address; 62*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sendrecv.addr_len = (address != NULL) ? *address_len : 0; 63*c38dbb97SDavid van Moolenbroek 64*c38dbb97SDavid van Moolenbroek if ((r = _syscall(VFS_PROC_NR, VFS_RECVFROM, &m)) < 0) 65*c38dbb97SDavid van Moolenbroek return -1; 66*c38dbb97SDavid van Moolenbroek 67*c38dbb97SDavid van Moolenbroek if (address != NULL) 68*c38dbb97SDavid van Moolenbroek *address_len = m.m_vfs_lc_socklen.len; 69*c38dbb97SDavid van Moolenbroek return r; 70*c38dbb97SDavid van Moolenbroek } 71*c38dbb97SDavid van Moolenbroek 72433d6423SLionel Sambuc ssize_t recvfrom(int sock, void *__restrict buffer, size_t length, 73433d6423SLionel Sambuc int flags, struct sockaddr *__restrict address, 74433d6423SLionel Sambuc socklen_t *__restrict address_len) 75433d6423SLionel Sambuc { 76433d6423SLionel Sambuc int r; 77433d6423SLionel Sambuc nwio_tcpconf_t tcpconf; 78433d6423SLionel Sambuc nwio_udpopt_t udpopt; 7917580212SDavid van Moolenbroek nwio_ipopt_t ipopt; 80433d6423SLionel Sambuc struct sockaddr_un uds_addr; 81433d6423SLionel Sambuc int uds_sotype = -1; 82433d6423SLionel Sambuc 83*c38dbb97SDavid van Moolenbroek r = __recvfrom(sock, buffer, length, flags, address, address_len); 84*c38dbb97SDavid van Moolenbroek if (r != -1 || errno != ENOTSOCK) 85*c38dbb97SDavid van Moolenbroek return r; 86*c38dbb97SDavid van Moolenbroek 87433d6423SLionel Sambuc #if DEBUG 88433d6423SLionel Sambuc fprintf(stderr, "recvfrom: for fd %d\n", sock); 89433d6423SLionel Sambuc #endif 90433d6423SLionel Sambuc 91433d6423SLionel Sambuc r= ioctl(sock, NWIOGTCPCONF, &tcpconf); 92433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 93433d6423SLionel Sambuc { 94433d6423SLionel Sambuc if (r == -1) 95433d6423SLionel Sambuc return r; 96433d6423SLionel Sambuc return _tcp_recvfrom(sock, buffer, length, flags, 97433d6423SLionel Sambuc address, address_len, &tcpconf); 98433d6423SLionel Sambuc } 99433d6423SLionel Sambuc 100433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDPOPT, &udpopt); 101433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 102433d6423SLionel Sambuc { 103433d6423SLionel Sambuc if (r == -1) 104433d6423SLionel Sambuc return r; 105433d6423SLionel Sambuc return _udp_recvfrom(sock, buffer, length, flags, 106433d6423SLionel Sambuc address, address_len, &udpopt); 107433d6423SLionel Sambuc } 108433d6423SLionel Sambuc 109433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); 110433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 111433d6423SLionel Sambuc { 112433d6423SLionel Sambuc 113433d6423SLionel Sambuc if (r == -1) { 114433d6423SLionel Sambuc return r; 115433d6423SLionel Sambuc } 116433d6423SLionel Sambuc 117433d6423SLionel Sambuc if (uds_sotype == SOCK_DGRAM) { 118433d6423SLionel Sambuc return _uds_recvfrom_dgram(sock, buffer, 119433d6423SLionel Sambuc length, flags, address, address_len); 120433d6423SLionel Sambuc } else { 121433d6423SLionel Sambuc return _uds_recvfrom_conn(sock, buffer, 122433d6423SLionel Sambuc length, flags, address, address_len, 123433d6423SLionel Sambuc &uds_addr); 124433d6423SLionel Sambuc } 125433d6423SLionel Sambuc } 126433d6423SLionel Sambuc 12717580212SDavid van Moolenbroek r= ioctl(sock, NWIOGIPOPT, &ipopt); 12817580212SDavid van Moolenbroek if (r != -1 || errno != ENOTTY) 1297f5f010bSBen Gras { 1307f5f010bSBen Gras ip_hdr_t *ip_hdr; 1315dd8da10SDavid van Moolenbroek int rd; 1327f5f010bSBen Gras struct sockaddr_in sin; 1337f5f010bSBen Gras 13417580212SDavid van Moolenbroek if (r == -1) { 13517580212SDavid van Moolenbroek return r; 13617580212SDavid van Moolenbroek } 13717580212SDavid van Moolenbroek 1387f5f010bSBen Gras rd = read(sock, buffer, length); 1397f5f010bSBen Gras 1407f5f010bSBen Gras if(rd < 0) return rd; 1417f5f010bSBen Gras 1425dd8da10SDavid van Moolenbroek assert((size_t)rd >= sizeof(*ip_hdr)); 1437f5f010bSBen Gras 1447f5f010bSBen Gras ip_hdr= buffer; 1457f5f010bSBen Gras 1467f5f010bSBen Gras if (address != NULL) 1477f5f010bSBen Gras { 1487f5f010bSBen Gras int len; 1497f5f010bSBen Gras memset(&sin, 0, sizeof(sin)); 1507f5f010bSBen Gras sin.sin_family= AF_INET; 1517f5f010bSBen Gras sin.sin_addr.s_addr= ip_hdr->ih_src; 1527f5f010bSBen Gras sin.sin_len= sizeof(sin); 1537f5f010bSBen Gras len= *address_len; 1545dd8da10SDavid van Moolenbroek if ((size_t)len > sizeof(sin)) 1555dd8da10SDavid van Moolenbroek len= (int)sizeof(sin); 1567f5f010bSBen Gras memcpy(address, &sin, len); 1577f5f010bSBen Gras *address_len= sizeof(sin); 1587f5f010bSBen Gras } 1597f5f010bSBen Gras 1607f5f010bSBen Gras return rd; 1617f5f010bSBen Gras } 1627f5f010bSBen Gras 163*c38dbb97SDavid van Moolenbroek errno = ENOTSOCK; 164*c38dbb97SDavid van Moolenbroek return -1; 165433d6423SLionel Sambuc } 166433d6423SLionel Sambuc 167433d6423SLionel Sambuc static ssize_t _tcp_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_tcpconf_t *tcpconfp) 170433d6423SLionel Sambuc { 171433d6423SLionel Sambuc int r; 172433d6423SLionel Sambuc size_t len; 173433d6423SLionel Sambuc struct sockaddr_in sin; 174433d6423SLionel Sambuc 175433d6423SLionel Sambuc if (flags != 0) 176433d6423SLionel Sambuc { 177433d6423SLionel Sambuc #if DEBUG 178433d6423SLionel Sambuc fprintf(stderr, "recvfrom(tcp): flags not implemented\n"); 179433d6423SLionel Sambuc #endif 180433d6423SLionel Sambuc errno= ENOSYS; 181433d6423SLionel Sambuc return -1; 182433d6423SLionel Sambuc } 183433d6423SLionel Sambuc 184433d6423SLionel Sambuc r = read(sock, buffer, length); 185433d6423SLionel Sambuc 186433d6423SLionel Sambuc if (r >= 0 && address != NULL) 187433d6423SLionel Sambuc { 188433d6423SLionel Sambuc sin.sin_family= AF_INET; 189433d6423SLionel Sambuc sin.sin_addr.s_addr= tcpconfp->nwtc_remaddr; 190433d6423SLionel Sambuc sin.sin_port= tcpconfp->nwtc_remport; 191433d6423SLionel Sambuc sin.sin_len= sizeof(sin); 192433d6423SLionel Sambuc len= *address_len; 193433d6423SLionel Sambuc if (len > sizeof(sin)) 194433d6423SLionel Sambuc len= sizeof(sin); 195433d6423SLionel Sambuc memcpy(address, &sin, len); 196433d6423SLionel Sambuc *address_len= sizeof(sin); 197433d6423SLionel Sambuc } 198433d6423SLionel Sambuc 199433d6423SLionel Sambuc return r; 200433d6423SLionel Sambuc } 201433d6423SLionel Sambuc 202433d6423SLionel Sambuc static ssize_t _udp_recvfrom(int sock, void *__restrict buffer, size_t length, 203433d6423SLionel Sambuc int flags, struct sockaddr *__restrict address, 204433d6423SLionel Sambuc socklen_t *__restrict address_len, nwio_udpopt_t *udpoptp) 205433d6423SLionel Sambuc { 206433d6423SLionel Sambuc int r, t_errno; 207433d6423SLionel Sambuc size_t buflen, len; 208433d6423SLionel Sambuc void *buf; 209433d6423SLionel Sambuc udp_io_hdr_t *io_hdrp; 210433d6423SLionel Sambuc struct sockaddr_in sin; 211433d6423SLionel Sambuc 212433d6423SLionel Sambuc if (flags) 213433d6423SLionel Sambuc { 214433d6423SLionel Sambuc #if DEBUG 215433d6423SLionel Sambuc fprintf(stderr, "recvfrom(udp): flags not implemented\n"); 216433d6423SLionel Sambuc #endif 217433d6423SLionel Sambuc errno= ENOSYS; 218433d6423SLionel Sambuc return -1; 219433d6423SLionel Sambuc } 220433d6423SLionel Sambuc 221433d6423SLionel Sambuc if (udpoptp->nwuo_flags & NWUO_RWDATONLY) 222433d6423SLionel Sambuc { 223433d6423SLionel Sambuc if (address != NULL && 224433d6423SLionel Sambuc (udpoptp->nwuo_flags & (NWUO_RA_SET | NWUO_RP_SET)) != 225433d6423SLionel Sambuc (NWUO_RA_SET | NWUO_RP_SET)) 226433d6423SLionel Sambuc { 227433d6423SLionel Sambuc 228433d6423SLionel Sambuc #if DEBUG 229433d6423SLionel Sambuc fprintf(stderr, 230433d6423SLionel Sambuc "recvfrom(udp): RWDATONLY on unconnected socket\n"); 231433d6423SLionel Sambuc #endif 232433d6423SLionel Sambuc errno= ENOTCONN; 233433d6423SLionel Sambuc return -1; 234433d6423SLionel Sambuc } 235433d6423SLionel Sambuc 236433d6423SLionel Sambuc r= read(sock, buffer, length); 237433d6423SLionel Sambuc if (r == -1) 238433d6423SLionel Sambuc return r; 239433d6423SLionel Sambuc 240433d6423SLionel Sambuc if (address != NULL) 241433d6423SLionel Sambuc { 242433d6423SLionel Sambuc sin.sin_family= AF_INET; 243433d6423SLionel Sambuc sin.sin_addr.s_addr= udpoptp->nwuo_remaddr; 244433d6423SLionel Sambuc sin.sin_port= udpoptp->nwuo_remport; 245433d6423SLionel Sambuc sin.sin_len= sizeof(sin); 246433d6423SLionel Sambuc len= *address_len; 247433d6423SLionel Sambuc if (len > sizeof(sin)) 248433d6423SLionel Sambuc len= sizeof(sin); 249433d6423SLionel Sambuc memcpy(address, &sin, len); 250433d6423SLionel Sambuc *address_len= sizeof(sin); 251433d6423SLionel Sambuc } 252433d6423SLionel Sambuc 253433d6423SLionel Sambuc return r; 254433d6423SLionel Sambuc } 255433d6423SLionel Sambuc 256433d6423SLionel Sambuc buflen= sizeof(*io_hdrp) + length; 257433d6423SLionel Sambuc if (buflen < length) 258433d6423SLionel Sambuc { 259433d6423SLionel Sambuc /* Overflow */ 260433d6423SLionel Sambuc errno= EMSGSIZE; 261433d6423SLionel Sambuc return -1; 262433d6423SLionel Sambuc } 263433d6423SLionel Sambuc buf= malloc(buflen); 264433d6423SLionel Sambuc if (buf == NULL) 265433d6423SLionel Sambuc return -1; 266433d6423SLionel Sambuc 267433d6423SLionel Sambuc r= read(sock, buf, buflen); 268433d6423SLionel Sambuc if (r == -1) 269433d6423SLionel Sambuc { 270433d6423SLionel Sambuc t_errno= errno; 271433d6423SLionel Sambuc #if DEBUG 272433d6423SLionel Sambuc fprintf(stderr, "recvfrom(udp): read failed: %s\n", 273433d6423SLionel Sambuc strerror(errno)); 274433d6423SLionel Sambuc fprintf(stderr, "udp opt flags = 0x%x\n", udpoptp->nwuo_flags); 275433d6423SLionel Sambuc #endif 276433d6423SLionel Sambuc free(buf); 277433d6423SLionel Sambuc errno= t_errno; 278433d6423SLionel Sambuc return -1; 279433d6423SLionel Sambuc } 280433d6423SLionel Sambuc 2815dd8da10SDavid van Moolenbroek assert((size_t)r >= sizeof(*io_hdrp)); 282433d6423SLionel Sambuc length= r-sizeof(*io_hdrp); 283433d6423SLionel Sambuc 284433d6423SLionel Sambuc io_hdrp= buf; 285433d6423SLionel Sambuc memcpy(buffer, &io_hdrp[1], length); 286433d6423SLionel Sambuc 287433d6423SLionel Sambuc if (address != NULL) 288433d6423SLionel Sambuc { 289433d6423SLionel Sambuc sin.sin_family= AF_INET; 290433d6423SLionel Sambuc sin.sin_addr.s_addr= io_hdrp->uih_src_addr; 291433d6423SLionel Sambuc sin.sin_port= io_hdrp->uih_src_port; 292433d6423SLionel Sambuc sin.sin_len= sizeof(sin); 293433d6423SLionel Sambuc len= *address_len; 294433d6423SLionel Sambuc if (len > sizeof(sin)) 295433d6423SLionel Sambuc len= sizeof(sin); 296433d6423SLionel Sambuc memcpy(address, &sin, len); 297433d6423SLionel Sambuc *address_len= sizeof(sin); 298433d6423SLionel Sambuc } 299433d6423SLionel Sambuc free(buf); 300433d6423SLionel Sambuc return length; 301433d6423SLionel Sambuc } 302433d6423SLionel Sambuc 303433d6423SLionel Sambuc static ssize_t _uds_recvfrom_conn(int sock, void *__restrict buffer, 304433d6423SLionel Sambuc size_t length, int flags, struct sockaddr *__restrict address, 305433d6423SLionel Sambuc socklen_t *__restrict address_len, struct sockaddr_un *uds_addr) 306433d6423SLionel Sambuc { 307433d6423SLionel Sambuc int r; 308433d6423SLionel Sambuc size_t len; 309433d6423SLionel Sambuc 310433d6423SLionel Sambuc /* for connection oriented unix domain sockets (SOCK_STREAM / 311433d6423SLionel Sambuc * SOCK_SEQPACKET) 312433d6423SLionel Sambuc */ 313433d6423SLionel Sambuc 314433d6423SLionel Sambuc if (flags != 0) 315433d6423SLionel Sambuc { 316433d6423SLionel Sambuc #if DEBUG 317433d6423SLionel Sambuc fprintf(stderr, "recvfrom(uds): flags not implemented\n"); 318433d6423SLionel Sambuc #endif 319433d6423SLionel Sambuc errno= ENOSYS; 320433d6423SLionel Sambuc return -1; 321433d6423SLionel Sambuc } 322433d6423SLionel Sambuc 323433d6423SLionel Sambuc r = read(sock, buffer, length); 324433d6423SLionel Sambuc 325433d6423SLionel Sambuc if (r >= 0 && address != NULL) 326433d6423SLionel Sambuc { 327433d6423SLionel Sambuc 328433d6423SLionel Sambuc len= *address_len; 329433d6423SLionel Sambuc if (len > sizeof(struct sockaddr_un)) 330433d6423SLionel Sambuc len= sizeof(struct sockaddr_un); 331433d6423SLionel Sambuc memcpy(address, uds_addr, len); 332433d6423SLionel Sambuc *address_len= sizeof(struct sockaddr_un); 333433d6423SLionel Sambuc } 334433d6423SLionel Sambuc 335433d6423SLionel Sambuc return r; 336433d6423SLionel Sambuc } 337433d6423SLionel Sambuc 338433d6423SLionel Sambuc static ssize_t _uds_recvfrom_dgram(int sock, void *__restrict buffer, 339433d6423SLionel Sambuc size_t length, int flags, struct sockaddr *__restrict address, 340433d6423SLionel Sambuc socklen_t *__restrict address_len) 341433d6423SLionel Sambuc { 342433d6423SLionel Sambuc int r; 343433d6423SLionel Sambuc size_t len; 344433d6423SLionel Sambuc 345433d6423SLionel Sambuc /* for connectionless unix domain sockets (SOCK_DGRAM) */ 346433d6423SLionel Sambuc 347433d6423SLionel Sambuc if (flags != 0) 348433d6423SLionel Sambuc { 349433d6423SLionel Sambuc #if DEBUG 350433d6423SLionel Sambuc fprintf(stderr, "recvfrom(uds): flags not implemented\n"); 351433d6423SLionel Sambuc #endif 352433d6423SLionel Sambuc errno= ENOSYS; 353433d6423SLionel Sambuc return -1; 354433d6423SLionel Sambuc } 355433d6423SLionel Sambuc 356433d6423SLionel Sambuc r = read(sock, buffer, length); 357433d6423SLionel Sambuc 358433d6423SLionel Sambuc if (r >= 0 && address != NULL) 359433d6423SLionel Sambuc { 360433d6423SLionel Sambuc len= *address_len; 361433d6423SLionel Sambuc if (len > sizeof(struct sockaddr_un)) 362433d6423SLionel Sambuc len= sizeof(struct sockaddr_un); 363433d6423SLionel Sambuc ioctl(sock, NWIOGUDSFADDR, address); 364433d6423SLionel Sambuc *address_len= sizeof(struct sockaddr_un); 365433d6423SLionel Sambuc } 366433d6423SLionel Sambuc 367433d6423SLionel Sambuc return r; 368433d6423SLionel Sambuc } 369433d6423SLionel Sambuc 370