1 /*************************************************************
2  *  $Id: connect.c,v 1.4 2003/09/25 15:54:27 marcolz Exp $
3  *
4  *  connect.c
5  *
6  *  Much of this shamelessly cloned from elsewhere.
7  *
8  */
9 /*******************************************************
10  *  Copyright (C) Doug Hay, 1991.
11  *  Permission to use and abuse this code, as long
12  *  as this copyright notice stays intact and with the
13  *  code.  No warranty implied.  This code supplied as is.
14  *******************************************************/
15 #include	"config.h"
16 
17 #include	<ctype.h>
18 #include	<errno.h>
19 #include	<netdb.h>
20 #include	<sys/types.h>
21 #include	<sys/socket.h>
22 #include	<netinet/in.h>
23 #include	<arpa/inet.h>
24 #include	<netinet/tcp.h>
25 #include	<stdio.h>
26 #ifdef	HAVE_STDLIB_H
27 #include	<stdlib.h>
28 #endif				/* HAVE_STDLIB_H */
29 #ifdef	HAVE_STRING_H
30 #include	<string.h>
31 #endif				/* HAVE_STRING_H */
32 #ifdef	HAVE_STRINGS_H
33 #include	<strings.h>
34 #endif				/* HAVE_STRINGS_H */
35 #ifdef	HAVE_UNISTD_H
36 #include	<unistd.h>
37 #endif				/* HAVE_UNISTD_H */
38 
39 #include	"connect.h"
40 #include	"login.h"
41 
42 #include	"../print.h"
43 
44 #ifndef USE_IPv6
45 static int	get_hostaddr(char *host, struct sockaddr_in * addr);
46 static int	get_hostport(char *port, struct sockaddr_in * addr);
47 static int	hostconnect(struct sockaddr_in * addr);
48 #else
49 static int	hostconnect(struct addrinfo * addr);
50 #endif
51 
52 int
empire_connect(host,port,country,rep,kill_it)53 empire_connect(host, port, country, rep, kill_it)
54 	char		*host, *port, *country, *rep;
55 	int		kill_it;
56 {
57 	int		sock;
58 	const char	*user;
59 #ifndef USE_IPv6
60 	struct sockaddr_in addr;
61 
62 	if (!get_hostaddr(host, &addr)) {
63 		eprt("Unable to get address of %s\n", host);
64 		return (-1);
65 	}
66 	if (!get_hostport(port, &addr)) {
67 		eprt("Unable to convert port %s\n", port);
68 		return (-1);
69 	}
70 	sock = hostconnect(&addr);
71 #else
72 	struct addrinfo *ainfo, hints;
73 	int		i;
74 
75 	memset(&hints, 0, sizeof(hints));
76 	hints.ai_family = PF_UNSPEC;
77 	hints.ai_socktype = SOCK_STREAM;
78 
79 	if ((i = getaddrinfo(host, port, &hints, &ainfo))) {
80 		eprt("%s\n", gai_strerror(i));
81 		return (-1);
82 	}
83 	sock = hostconnect(ainfo);
84 	freeaddrinfo(ainfo);
85 #endif
86 	if (-1 == sock) {
87 		eprt("Connection failed.\n");
88 		return (-1);
89 	}
90 	if (!(user = getenv("USER")))
91 		user = "unknown";
92 
93 	if (!login(sock, user, country, rep, kill_it)) {
94 		eprt("Login failed.\n");
95 		(void) close(sock);
96 		return (-1);
97 	}
98 	if (kill_it) {
99 		(void) close(sock);
100 		return (-1);
101 	}
102 	return (sock);
103 }
104 #ifndef USE_IPv6
105 /******************************************
106  * get_hostaddr
107  *
108  * Find the actual net address from the host name.
109  * The host name can be an internet id, or a name.
110  *
111  * Returns 1 if ok, 0 if it failed.
112  */
113 static int
get_hostaddr(host,addr)114 get_hostaddr(host, addr)
115 	char		*host;
116 	struct sockaddr_in *addr;
117 {
118 	struct hostent *hptr;
119 
120 	if (!host || !*host)
121 		return (0);
122 
123 	if (isdigit(*host)) {
124 		/* Well, it could be an internet address. */
125 		/* Could also be a name starting with a numeric.  sick. */
126 		addr->sin_addr.s_addr = inet_addr(host);
127 		if ((unsigned)-1 != addr->sin_addr.s_addr) {
128 			/* Yeah, worked. */
129 			return (1);
130 		}
131 	}
132 	hptr = gethostbyname(host);
133 	if (!hptr)
134 		return (0);
135 
136 	bcopy(hptr->h_addr, (char *)&addr->sin_addr, sizeof(addr->sin_addr));
137 	return (1);
138 }
139 
140 /******************************************
141  * get_hostport
142  *
143  * Convert the port string into the proper port id
144  * in the socket address.
145  * If "port" is a numeric string, add it in directly.
146  * Otherwise, look it up in the services.
147  *
148  * Returns 1 if ok, 0 if it fails.
149  */
150 static int
get_hostport(port,addr)151 get_hostport(port, addr)
152 	char			*port;
153 	struct sockaddr_in	*addr;
154 {
155 	struct servent *serv;
156 
157 	if (!port || !*port)
158 		return (0);
159 
160 	if (isdigit(*port)) {
161 		addr->sin_port = htons((unsigned short)atol(port));
162 	} else {
163 		serv = getservbyname(port, "tcp");
164 		if (!serv)
165 			return (0);
166 		addr->sin_port = serv->s_port;
167 	}
168 	return (1);
169 }
170 #endif
171 /******************************************
172  * hostconnect
173  *
174  * Returns -1 if terrible error occurs.
175  * Returns socket number if succeeds.
176  */
177 static int
hostconnect(addr)178 hostconnect(addr)
179 #ifndef USE_IPv6
180 	struct sockaddr_in *addr;
181 #else
182 	struct addrinfo *addr;
183 #endif
184 {
185 	int		sock;
186 
187 #ifndef USE_IPv6
188 	sock = socket(AF_INET, SOCK_STREAM, 0);
189 #else
190 	sock = socket(addr->ai_family, addr->ai_socktype, 0);
191 	/*
192 	 * XXX should work as long as AF_INET=PF_INET and AF_INET6=PF_INET6
193 	 * ai_family is PF_INET or PF_INET6 fix this
194 	 */
195 #endif
196 	if (-1 == sock) {
197 		perror("socket:");
198 		return (-1);
199 	}
200 #if 0
201 	/* This just prints some crap about the connection buffering */
202 	{
203 		int		t, dat, len;
204 		t = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&dat, &len);
205 		if (-1 == t) {
206 			eprt("getsockopt failed, %d\n", errno);
207 		} else {
208 			eprt("getsockopt, sndbuf, %d, %d\n", dat, len);
209 		}
210 		t = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&dat, &len);
211 		if (-1 == t) {
212 			eprt("getsockopt failed, %d\n", errno);
213 		} else {
214 			eprt("getsockopt, rcvbuf, %d, %d\n", dat, len);
215 		}
216 	}
217 #endif
218 
219 #ifndef USE_IPv6
220 	addr->sin_family = AF_INET;
221 	if (connect(sock, (struct sockaddr *) addr, sizeof(*addr)) == -1) {
222 #else
223 	if (connect(sock, addr->ai_addr, (addr->ai_addrlen)) == -1) {
224 #endif
225 		switch (errno) {
226 		case ECONNREFUSED:	/* Connection refused */
227 			eprt("Connection refused.\n");
228 			eprt("Game is probably not up.\n");
229 			break;
230 
231 		case ETIMEDOUT:/* Connection timed out. */
232 			eprt("Connection timed out.\n");
233 			eprt("Network problems?\n");
234 			break;
235 
236 		case ENETUNREACH:	/* Network unreachable. */
237 			eprt("Network unreachable.\n");
238 			eprt("Good luck.\n");
239 			break;
240 
241 		case EISCONN:	/* Already connected??!? */
242 			eprt("Already connected.\n");
243 			return (sock);
244 
245 		default:
246 			perror("hostconnect:");
247 			break;
248 		}
249 		(void) close(sock);
250 		return (-1);
251 	}
252 #if 0
253 	/* This just prints some crap about the connection buffering */
254 	{
255 		int		t, dat, len;
256 		/* 6 is tcp's ip protocol number from /etc/protocols.. */
257 		t = getsockopt(sock, 6, TCP_NODELAY, (char *)&dat, &len);
258 		if (-1 == t) {
259 			eprt("getsockopt tcp failed, %d\n", errno);
260 		} else {
261 			eprt("getsockopt, nodelay, %d, %d\n", dat, len);
262 		}
263 		t = getsockopt(sock, 6, TCP_MAXSEG, (char *)&dat, &len);
264 		if (-1 == t) {
265 			eprt("getsockopt tcp failed, %d\n", errno);
266 		} else {
267 			eprt("getsockopt, maxseg, %d, %d\n", dat, len);
268 		}
269 	}
270 #endif
271 	return (sock);
272 }
273 
274 /* vim:ts=8:ai:sw=8:syntax=c
275  */
276