src/client/host.c

Go to the documentation of this file.
00001 /*
00002  *  Empire - A multi-player, client/server Internet based war game.
00003  *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
00004  *                           Ken Stevens, Steve McClure
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  *  ---
00021  *
00022  *  See files README, COPYING and CREDITS in the root of the source
00023  *  tree for related information and legal notices.  It is expected
00024  *  that future projects/authors will amend these files as needed.
00025  *
00026  *  ---
00027  *
00028  *  host.c: make stream connection to empire
00029  * 
00030  *  Known contributors to this file:
00031  *     Dave Pare, 1989
00032  *     Steve McClure, 1998
00033  *     Markus Armbruster, 2005
00034  */
00035 
00036 #include <config.h>
00037 
00038 #include <ctype.h>
00039 #include <errno.h>
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #ifndef _WIN32
00044 #include <sys/types.h>
00045 #include <sys/socket.h>
00046 #include <netinet/in.h>
00047 #include <arpa/inet.h>
00048 #include <netdb.h>
00049 #include <unistd.h>
00050 #else
00051 #define close(fd) w32_close_socket((fd))
00052 #endif
00053 #include "misc.h"
00054 
00055 #ifdef HAVE_GETADDRINFO
00056 /*
00057  * Inspired by example code from W. Richard Stevens: UNIX Network
00058  * Programming, Vol. 1
00059  */
00060 
00061 int
00062 tcp_connect(char *host, char *serv)
00063 {
00064     int sockfd, n;
00065     struct addrinfo hints, *res, *ressave;
00066 
00067     memset(&hints, 0, sizeof(struct addrinfo));
00068     hints.ai_family = AF_UNSPEC;
00069     hints.ai_socktype = SOCK_STREAM;
00070 
00071     if ((n = getaddrinfo(host, serv, &hints, &res)) != 0) {
00072         fprintf(stderr, "Can't connect to %s:%s: %s\n",
00073                 host, serv, gai_strerror(n));
00074         exit(1);
00075     }
00076     ressave = res;
00077 
00078     do {
00079         sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
00080         if (sockfd < 0)
00081             continue;           /* ignore this one */
00082 
00083         if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
00084             break;              /* success */
00085         close(sockfd);          /* ignore this one */
00086     } while ((res = res->ai_next) != NULL);
00087 
00088     if (res == NULL) {          /* errno set from final connect() */
00089         fprintf(stderr, "Can't connect to %s:%s: %s\n",
00090                 host, serv, strerror(errno));
00091         exit(1);
00092     }
00093 
00094     freeaddrinfo(ressave);
00095 
00096     return sockfd;
00097 }
00098 
00099 #else  /* !HAVE_GETADDRINFO */
00100 
00101 static int
00102 hostaddr(char *name, struct sockaddr_in *addr)
00103 {
00104     struct hostent *hp;
00105 
00106     if (name == NULL || *name == 0)
00107         return 0;
00108     if (isdigit(*name)) {
00109         addr->sin_addr.s_addr = inet_addr(name);
00110     } else {
00111         hp = gethostbyname(name);
00112         if (hp == NULL)
00113             return 0;
00114         memcpy(&addr->sin_addr, hp->h_addr, sizeof(addr->sin_addr));
00115     }
00116     return 1;
00117 }
00118 
00119 static int
00120 hostport(char *name, struct sockaddr_in *addr)
00121 {
00122     struct servent *sp;
00123 
00124     if (name == NULL || *name == 0)
00125         return 0;
00126     if (isdigit(*name)) {
00127         addr->sin_port = htons(atoi(name));
00128     } else {
00129         sp = getservbyname(name, "tcp");
00130         if (sp == NULL)
00131             return 0;
00132         addr->sin_port = sp->s_port;
00133     }
00134     return 1;
00135 }
00136 
00137 static int
00138 hostconnect(struct sockaddr_in *addr)
00139 {
00140     /* FIXME should attempt connect to all addresses of multi-homed host, not just 1st */
00141     int s;
00142 
00143     s = socket(AF_INET, SOCK_STREAM, 0);
00144     if (s < 0) {
00145         return -1;
00146     }
00147     addr->sin_family = AF_INET;
00148     if (connect(s, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
00149         (void)close(s);
00150         return -1;
00151     }
00152     return s;
00153 }
00154 
00155 int
00156 tcp_connect(char *host, char *serv)
00157 {
00158     struct sockaddr_in sin;
00159     int sock;
00160 
00161     if (!hostport(serv, &sin)) {
00162         fprintf(stderr, "Can't resolve Empire port %s\n", serv);
00163         exit(1);
00164     }
00165     if (!hostaddr(host, &sin)) {
00166         fprintf(stderr, "Can't resolve Empire host %s\n", host);
00167         exit(1);
00168     }
00169     if ((sock = hostconnect(&sin)) < 0) {
00170         fprintf(stderr, "Can't connect to %s:%s: %s\n",
00171                 serv, host, strerror(errno));
00172         exit(1);
00173     }
00174     return sock;
00175 }
00176 #endif

Generated on Fri Mar 28 11:01:11 2008 for empserver by  doxygen 1.5.2