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