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