1433d6423SLionel Sambuc #include <sys/cdefs.h>
2433d6423SLionel Sambuc #include "namespace.h"
3c38dbb97SDavid van Moolenbroek #include <lib.h>
4c38dbb97SDavid 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
36c38dbb97SDavid van Moolenbroek /*
37c38dbb97SDavid van Moolenbroek * Connect a socket to a remote address.
38c38dbb97SDavid van Moolenbroek */
39c38dbb97SDavid van Moolenbroek static int
__connect(int fd,const struct sockaddr * address,socklen_t address_len)40c38dbb97SDavid van Moolenbroek __connect(int fd, const struct sockaddr * address, socklen_t address_len)
41c38dbb97SDavid van Moolenbroek {
42c38dbb97SDavid van Moolenbroek message m;
43c38dbb97SDavid van Moolenbroek
44c38dbb97SDavid van Moolenbroek memset(&m, 0, sizeof(m));
45c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.fd = fd;
46c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr = (vir_bytes)address;
47c38dbb97SDavid van Moolenbroek m.m_lc_vfs_sockaddr.addr_len = address_len;
48c38dbb97SDavid van Moolenbroek
49c38dbb97SDavid van Moolenbroek return _syscall(VFS_PROC_NR, VFS_CONNECT, &m);
50c38dbb97SDavid van Moolenbroek }
51c38dbb97SDavid van Moolenbroek
connect(int sock,const struct sockaddr * address,socklen_t address_len)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
59c38dbb97SDavid van Moolenbroek r = __connect(sock, address, address_len);
60*84ed480eSDavid van Moolenbroek if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
61c38dbb97SDavid van Moolenbroek return r;
62c38dbb97SDavid 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
97c38dbb97SDavid van Moolenbroek errno = ENOTSOCK;
98433d6423SLionel Sambuc return -1;
99433d6423SLionel Sambuc }
100433d6423SLionel Sambuc
_tcp_connect(int sock,const struct sockaddr * address,socklen_t address_len,nwio_tcpconf_t * tcpconfp)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
_udp_connect(int sock,const struct sockaddr * address,socklen_t address_len,nwio_udpopt_t * udpoptp)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
_uds_connect(int sock,const struct sockaddr * address,socklen_t address_len)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