1433d6423SLionel Sambuc #include <sys/cdefs.h> 2433d6423SLionel Sambuc #include "namespace.h" 3*c38dbb97SDavid van Moolenbroek #include <lib.h> 4*c38dbb97SDavid van Moolenbroek 5433d6423SLionel Sambuc #include <minix/config.h> 6433d6423SLionel Sambuc 7433d6423SLionel Sambuc #include <errno.h> 8433d6423SLionel Sambuc #include <fcntl.h> 9433d6423SLionel Sambuc #include <stdio.h> 10433d6423SLionel Sambuc #include <stdlib.h> 11433d6423SLionel Sambuc #include <unistd.h> 12433d6423SLionel Sambuc #include <string.h> 13433d6423SLionel Sambuc #include <sys/ioctl.h> 14433d6423SLionel Sambuc #include <sys/socket.h> 15433d6423SLionel Sambuc #include <sys/types.h> 16433d6423SLionel Sambuc #include <sys/stat.h> 17433d6423SLionel Sambuc #include <netinet/in.h> 18433d6423SLionel Sambuc 19433d6423SLionel Sambuc #include <net/gen/in.h> 20433d6423SLionel Sambuc #include <net/gen/tcp.h> 21433d6423SLionel Sambuc #include <net/gen/tcp_io.h> 22433d6423SLionel Sambuc #include <net/gen/udp.h> 23433d6423SLionel Sambuc #include <net/gen/udp_io.h> 24433d6423SLionel Sambuc 25433d6423SLionel Sambuc #include <minix/const.h> 26433d6423SLionel Sambuc 27433d6423SLionel Sambuc #define DEBUG 0 28433d6423SLionel Sambuc 29433d6423SLionel Sambuc static int _tcp_connect(int sock, const struct sockaddr *address, 30433d6423SLionel Sambuc socklen_t address_len, nwio_tcpconf_t *tcpconfp); 31433d6423SLionel Sambuc static int _udp_connect(int sock, const struct sockaddr *address, 32433d6423SLionel Sambuc socklen_t address_len, nwio_udpopt_t *udpoptp); 33433d6423SLionel Sambuc static int _uds_connect(int sock, const struct sockaddr *address, 34433d6423SLionel Sambuc socklen_t address_len); 35433d6423SLionel Sambuc 36*c38dbb97SDavid van Moolenbroek /* 37*c38dbb97SDavid van Moolenbroek * Connect a socket to a remote address. 38*c38dbb97SDavid van Moolenbroek */ 39*c38dbb97SDavid van Moolenbroek static int 40*c38dbb97SDavid van Moolenbroek __connect(int fd, const struct sockaddr * address, socklen_t address_len) 41*c38dbb97SDavid van Moolenbroek { 42*c38dbb97SDavid van Moolenbroek message m; 43*c38dbb97SDavid van Moolenbroek 44*c38dbb97SDavid van Moolenbroek memset(&m, 0, sizeof(m)); 45*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.fd = fd; 46*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr = (vir_bytes)address; 47*c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr_len = address_len; 48*c38dbb97SDavid van Moolenbroek 49*c38dbb97SDavid van Moolenbroek return _syscall(VFS_PROC_NR, VFS_CONNECT, &m); 50*c38dbb97SDavid van Moolenbroek } 51*c38dbb97SDavid van Moolenbroek 52433d6423SLionel Sambuc int connect(int sock, const struct sockaddr *address, 53433d6423SLionel Sambuc socklen_t address_len) 54433d6423SLionel Sambuc { 55433d6423SLionel Sambuc int r; 56433d6423SLionel Sambuc nwio_tcpconf_t tcpconf; 57433d6423SLionel Sambuc nwio_udpopt_t udpopt; 58433d6423SLionel Sambuc 59*c38dbb97SDavid van Moolenbroek r = __connect(sock, address, address_len); 60*c38dbb97SDavid van Moolenbroek if (r != -1 || errno != ENOTSOCK) 61*c38dbb97SDavid van Moolenbroek return r; 62*c38dbb97SDavid van Moolenbroek 63433d6423SLionel Sambuc r= ioctl(sock, NWIOGTCPCONF, &tcpconf); 64433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 65433d6423SLionel Sambuc { 66433d6423SLionel Sambuc if (r == -1) 67433d6423SLionel Sambuc { 68433d6423SLionel Sambuc /* Bad file descriptor */ 69433d6423SLionel Sambuc return -1; 70433d6423SLionel Sambuc } 71433d6423SLionel Sambuc return _tcp_connect(sock, address, address_len, &tcpconf); 72433d6423SLionel Sambuc } 73433d6423SLionel Sambuc 74433d6423SLionel Sambuc r= ioctl(sock, NWIOGUDPOPT, &udpopt); 75433d6423SLionel Sambuc if (r != -1 || errno != ENOTTY) 76433d6423SLionel Sambuc { 77433d6423SLionel Sambuc if (r == -1) 78433d6423SLionel Sambuc { 79433d6423SLionel Sambuc /* Bad file descriptor */ 80433d6423SLionel Sambuc return -1; 81433d6423SLionel Sambuc } 82433d6423SLionel Sambuc return _udp_connect(sock, address, address_len, &udpopt); 83433d6423SLionel Sambuc } 84433d6423SLionel Sambuc 85433d6423SLionel Sambuc r= _uds_connect(sock, address, address_len); 86433d6423SLionel Sambuc if (r != -1 || (errno != ENOTTY && errno != EAFNOSUPPORT)) 87433d6423SLionel Sambuc { 88433d6423SLionel Sambuc if (r == -1) 89433d6423SLionel Sambuc { 90433d6423SLionel Sambuc /* Bad file descriptor */ 91433d6423SLionel Sambuc return -1; 92433d6423SLionel Sambuc } 93433d6423SLionel Sambuc 94433d6423SLionel Sambuc return r; 95433d6423SLionel Sambuc } 96433d6423SLionel Sambuc 97*c38dbb97SDavid van Moolenbroek errno = ENOTSOCK; 98433d6423SLionel Sambuc return -1; 99433d6423SLionel Sambuc } 100433d6423SLionel Sambuc 101433d6423SLionel Sambuc static int _tcp_connect(int sock, const struct sockaddr *address, 102433d6423SLionel Sambuc socklen_t address_len, nwio_tcpconf_t *tcpconfp) 103433d6423SLionel Sambuc { 104433d6423SLionel Sambuc int r; 105433d6423SLionel Sambuc struct sockaddr_in *sinp; 106433d6423SLionel Sambuc nwio_tcpconf_t tcpconf; 107433d6423SLionel Sambuc nwio_tcpcl_t tcpcl; 108433d6423SLionel Sambuc 109433d6423SLionel Sambuc if (address_len != sizeof(*sinp)) 110433d6423SLionel Sambuc { 111433d6423SLionel Sambuc errno= EINVAL; 112433d6423SLionel Sambuc return -1; 113433d6423SLionel Sambuc } 114433d6423SLionel Sambuc sinp= (struct sockaddr_in *) __UNCONST(address); 115433d6423SLionel Sambuc if (sinp->sin_family != AF_INET) 116433d6423SLionel Sambuc { 117433d6423SLionel Sambuc errno= EINVAL; 118433d6423SLionel Sambuc return -1; 119433d6423SLionel Sambuc } 120433d6423SLionel Sambuc tcpconf.nwtc_flags= NWTC_SET_RA | NWTC_SET_RP; 121433d6423SLionel Sambuc if ((tcpconfp->nwtc_flags & NWTC_LOCPORT_MASK) == NWTC_LP_UNSET) 122433d6423SLionel Sambuc tcpconf.nwtc_flags |= NWTC_LP_SEL; 123433d6423SLionel Sambuc tcpconf.nwtc_remaddr= sinp->sin_addr.s_addr; 124433d6423SLionel Sambuc tcpconf.nwtc_remport= sinp->sin_port; 125433d6423SLionel Sambuc 126433d6423SLionel Sambuc if (ioctl(sock, NWIOSTCPCONF, &tcpconf) == -1) 127433d6423SLionel Sambuc { 128433d6423SLionel Sambuc /* Ignore EISCONN error. The NWIOTCPCONN ioctl will get the 129433d6423SLionel Sambuc * right error. 130433d6423SLionel Sambuc */ 131433d6423SLionel Sambuc if (errno != EISCONN) 132433d6423SLionel Sambuc return -1; 133433d6423SLionel Sambuc } 134433d6423SLionel Sambuc 135433d6423SLionel Sambuc tcpcl.nwtcl_flags= TCF_DEFAULT; 136433d6423SLionel Sambuc 137433d6423SLionel Sambuc r= fcntl(sock, F_GETFL); 138433d6423SLionel Sambuc if (r == 1) 139433d6423SLionel Sambuc return -1; 140433d6423SLionel Sambuc if (r & O_NONBLOCK) 141433d6423SLionel Sambuc tcpcl.nwtcl_flags |= TCF_ASYNCH; 142433d6423SLionel Sambuc 143433d6423SLionel Sambuc r= ioctl(sock, NWIOTCPCONN, &tcpcl); 144433d6423SLionel Sambuc return r; 145433d6423SLionel Sambuc } 146433d6423SLionel Sambuc 147433d6423SLionel Sambuc static int _udp_connect(int sock, const struct sockaddr *address, 148433d6423SLionel Sambuc socklen_t address_len, nwio_udpopt_t *udpoptp) 149433d6423SLionel Sambuc { 150433d6423SLionel Sambuc int r; 151433d6423SLionel Sambuc struct sockaddr_in *sinp; 152433d6423SLionel Sambuc nwio_udpopt_t udpopt; 153433d6423SLionel Sambuc 154433d6423SLionel Sambuc if (address == NULL) 155433d6423SLionel Sambuc { 156433d6423SLionel Sambuc /* Unset remote address */ 157433d6423SLionel Sambuc udpopt.nwuo_flags= NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL; 158433d6423SLionel Sambuc 159433d6423SLionel Sambuc r= ioctl(sock, NWIOSUDPOPT, &udpopt); 160433d6423SLionel Sambuc return r; 161433d6423SLionel Sambuc } 162433d6423SLionel Sambuc 163433d6423SLionel Sambuc if (address_len != sizeof(*sinp)) 164433d6423SLionel Sambuc { 165433d6423SLionel Sambuc errno= EINVAL; 166433d6423SLionel Sambuc return -1; 167433d6423SLionel Sambuc } 168433d6423SLionel Sambuc sinp= (struct sockaddr_in *) __UNCONST(address); 169433d6423SLionel Sambuc if (sinp->sin_family != AF_INET) 170433d6423SLionel Sambuc { 171433d6423SLionel Sambuc errno= EINVAL; 172433d6423SLionel Sambuc return -1; 173433d6423SLionel Sambuc } 174433d6423SLionel Sambuc udpopt.nwuo_flags= NWUO_RP_SET | NWUO_RA_SET | NWUO_RWDATONLY; 175433d6423SLionel Sambuc if ((udpoptp->nwuo_flags & NWUO_LOCPORT_MASK) == NWUO_LP_ANY) 176433d6423SLionel Sambuc udpopt.nwuo_flags |= NWUO_LP_SEL; 177433d6423SLionel Sambuc udpopt.nwuo_remaddr= sinp->sin_addr.s_addr; 178433d6423SLionel Sambuc udpopt.nwuo_remport= sinp->sin_port; 179433d6423SLionel Sambuc 180433d6423SLionel Sambuc r= ioctl(sock, NWIOSUDPOPT, &udpopt); 181433d6423SLionel Sambuc return r; 182433d6423SLionel Sambuc } 183433d6423SLionel Sambuc 184433d6423SLionel Sambuc static int _uds_connect(int sock, const struct sockaddr *address, 185433d6423SLionel Sambuc socklen_t address_len) 186433d6423SLionel Sambuc { 187433d6423SLionel Sambuc 188433d6423SLionel Sambuc if (address == NULL) { 189433d6423SLionel Sambuc errno = EFAULT; 190433d6423SLionel Sambuc return -1; 191433d6423SLionel Sambuc } 192433d6423SLionel Sambuc 193433d6423SLionel Sambuc /* perform the connect */ 194433d6423SLionel Sambuc return ioctl(sock, NWIOSUDSCONN, (void *) __UNCONST(address)); 195433d6423SLionel Sambuc } 196