xref: /minix3/minix/lib/libc/sys/connect.c (revision 84ed480ef770e26a28565a26c8ef94ba01312a41)
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