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
__connect(int fd,const struct sockaddr * address,socklen_t address_len)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
connect(int sock,const struct sockaddr * address,socklen_t address_len)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
_tcp_connect(int sock,const struct sockaddr * address,socklen_t address_len,nwio_tcpconf_t * tcpconfp)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
_udp_connect(int sock,const struct sockaddr * address,socklen_t address_len,nwio_udpopt_t * udpoptp)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
_uds_connect(int sock,const struct sockaddr * address,socklen_t address_len)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