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