1 #include <sys/cdefs.h> 2 #include "namespace.h" 3 #include <lib.h> 4 5 #include <minix/config.h> 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <unistd.h> 12 #include <string.h> 13 #include <sys/ioctl.h> 14 #include <sys/socket.h> 15 #include <sys/types.h> 16 #include <sys/stat.h> 17 #include <netinet/in.h> 18 19 #include <net/gen/in.h> 20 #include <net/gen/tcp.h> 21 #include <net/gen/tcp_io.h> 22 #include <net/gen/udp.h> 23 #include <net/gen/udp_io.h> 24 25 #include <minix/const.h> 26 27 #define DEBUG 0 28 29 static int _tcp_connect(int sock, const struct sockaddr *address, 30 socklen_t address_len, nwio_tcpconf_t *tcpconfp); 31 static int _udp_connect(int sock, const struct sockaddr *address, 32 socklen_t address_len, nwio_udpopt_t *udpoptp); 33 static int _uds_connect(int sock, const struct sockaddr *address, 34 socklen_t address_len); 35 36 /* 37 * Connect a socket to a remote address. 38 */ 39 static int 40 __connect(int fd, const struct sockaddr * address, socklen_t address_len) 41 { 42 message m; 43 44 memset(&m, 0, sizeof(m)); 45 m.m_lc_vfs_sockaddr.fd = fd; 46 m.m_lc_vfs_sockaddr.addr = (vir_bytes)address; 47 m.m_lc_vfs_sockaddr.addr_len = address_len; 48 49 return _syscall(VFS_PROC_NR, VFS_CONNECT, &m); 50 } 51 52 int connect(int sock, const struct sockaddr *address, 53 socklen_t address_len) 54 { 55 int r; 56 nwio_tcpconf_t tcpconf; 57 nwio_udpopt_t udpopt; 58 59 r = __connect(sock, address, address_len); 60 if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS)) 61 return r; 62 63 r= ioctl(sock, NWIOGTCPCONF, &tcpconf); 64 if (r != -1 || errno != ENOTTY) 65 { 66 if (r == -1) 67 { 68 /* Bad file descriptor */ 69 return -1; 70 } 71 return _tcp_connect(sock, address, address_len, &tcpconf); 72 } 73 74 r= ioctl(sock, NWIOGUDPOPT, &udpopt); 75 if (r != -1 || errno != ENOTTY) 76 { 77 if (r == -1) 78 { 79 /* Bad file descriptor */ 80 return -1; 81 } 82 return _udp_connect(sock, address, address_len, &udpopt); 83 } 84 85 r= _uds_connect(sock, address, address_len); 86 if (r != -1 || (errno != ENOTTY && errno != EAFNOSUPPORT)) 87 { 88 if (r == -1) 89 { 90 /* Bad file descriptor */ 91 return -1; 92 } 93 94 return r; 95 } 96 97 errno = ENOTSOCK; 98 return -1; 99 } 100 101 static int _tcp_connect(int sock, const struct sockaddr *address, 102 socklen_t address_len, nwio_tcpconf_t *tcpconfp) 103 { 104 int r; 105 struct sockaddr_in *sinp; 106 nwio_tcpconf_t tcpconf; 107 nwio_tcpcl_t tcpcl; 108 109 if (address_len != sizeof(*sinp)) 110 { 111 errno= EINVAL; 112 return -1; 113 } 114 sinp= (struct sockaddr_in *) __UNCONST(address); 115 if (sinp->sin_family != AF_INET) 116 { 117 errno= EINVAL; 118 return -1; 119 } 120 tcpconf.nwtc_flags= NWTC_SET_RA | NWTC_SET_RP; 121 if ((tcpconfp->nwtc_flags & NWTC_LOCPORT_MASK) == NWTC_LP_UNSET) 122 tcpconf.nwtc_flags |= NWTC_LP_SEL; 123 tcpconf.nwtc_remaddr= sinp->sin_addr.s_addr; 124 tcpconf.nwtc_remport= sinp->sin_port; 125 126 if (ioctl(sock, NWIOSTCPCONF, &tcpconf) == -1) 127 { 128 /* Ignore EISCONN error. The NWIOTCPCONN ioctl will get the 129 * right error. 130 */ 131 if (errno != EISCONN) 132 return -1; 133 } 134 135 tcpcl.nwtcl_flags= TCF_DEFAULT; 136 137 r= fcntl(sock, F_GETFL); 138 if (r == 1) 139 return -1; 140 if (r & O_NONBLOCK) 141 tcpcl.nwtcl_flags |= TCF_ASYNCH; 142 143 r= ioctl(sock, NWIOTCPCONN, &tcpcl); 144 return r; 145 } 146 147 static int _udp_connect(int sock, const struct sockaddr *address, 148 socklen_t address_len, nwio_udpopt_t *udpoptp) 149 { 150 int r; 151 struct sockaddr_in *sinp; 152 nwio_udpopt_t udpopt; 153 154 if (address == NULL) 155 { 156 /* Unset remote address */ 157 udpopt.nwuo_flags= NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL; 158 159 r= ioctl(sock, NWIOSUDPOPT, &udpopt); 160 return r; 161 } 162 163 if (address_len != sizeof(*sinp)) 164 { 165 errno= EINVAL; 166 return -1; 167 } 168 sinp= (struct sockaddr_in *) __UNCONST(address); 169 if (sinp->sin_family != AF_INET) 170 { 171 errno= EINVAL; 172 return -1; 173 } 174 udpopt.nwuo_flags= NWUO_RP_SET | NWUO_RA_SET | NWUO_RWDATONLY; 175 if ((udpoptp->nwuo_flags & NWUO_LOCPORT_MASK) == NWUO_LP_ANY) 176 udpopt.nwuo_flags |= NWUO_LP_SEL; 177 udpopt.nwuo_remaddr= sinp->sin_addr.s_addr; 178 udpopt.nwuo_remport= sinp->sin_port; 179 180 r= ioctl(sock, NWIOSUDPOPT, &udpopt); 181 return r; 182 } 183 184 static int _uds_connect(int sock, const struct sockaddr *address, 185 socklen_t address_len) 186 { 187 188 if (address == NULL) { 189 errno = EFAULT; 190 return -1; 191 } 192 193 /* perform the connect */ 194 return ioctl(sock, NWIOSUDSCONN, (void *) __UNCONST(address)); 195 } 196