src/lib/gen/tcp_listen.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  *  tcp_listen.c: Create a socket and listen on it
00029  * 
00030  *  Known contributors to this file:
00031  *     Markus Armbruster, 2005
00032  */
00033 
00034 #include <config.h>
00035 
00036 #include <ctype.h>
00037 #include <errno.h>
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include <sys/types.h>
00042 #include <sys/socket.h>
00043 #include <netinet/in.h>
00044 #include <arpa/inet.h>
00045 #include <netdb.h>
00046 #include <unistd.h>
00047 #include "prototypes.h"
00048 
00049 static void cant_listen(char *, char *, const char *);
00050 
00051 int
00052 tcp_listen(char *host, char *serv, size_t *addrlenp)
00053 {
00054     int fd;
00055     int on = 1;
00056 #ifdef HAVE_GETADDRINFO
00057     /*
00058      * Inspired by example code from W. Richard Stevens: UNIX Network
00059      * Programming, Vol. 1
00060      */
00061     int n;
00062     struct addrinfo hints, *res, *ressave;
00063 
00064     memset(&hints, 0, sizeof(struct addrinfo));
00065     hints.ai_flags = AI_PASSIVE;
00066     hints.ai_family = AF_UNSPEC;
00067     hints.ai_socktype = SOCK_STREAM;
00068 
00069     if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
00070         cant_listen(host, serv, gai_strerror(n));
00071     ressave = res;
00072 
00073     do {
00074         fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
00075         if (fd < 0)
00076             continue;           /* error, try next one */
00077 
00078         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
00079             cant_listen(host, serv, strerror(errno));
00080         if (bind(fd, res->ai_addr, res->ai_addrlen) == 0)
00081             break;              /* success */
00082 
00083         close(fd);              /* error, close and try next one */
00084     } while ((res = res->ai_next) != NULL);
00085 
00086     if (res == NULL)         /* errno from final socket() or bind() */
00087         cant_listen(host, serv, strerror(errno));
00088 
00089     if (listen(fd, SOMAXCONN) < 0)
00090         cant_listen(host, serv, strerror(errno));
00091 
00092     if (addrlenp)
00093         *addrlenp = res->ai_addrlen;
00094 
00095     freeaddrinfo(ressave);
00096 
00097 #else  /* !HAVE_GETADDRINFO */
00098     struct sockaddr_in sin;
00099     struct hostent *hp;
00100     struct servent *sp;
00101 
00102     memset(&sin, 0, sizeof(sin));
00103     sin.sin_family = AF_INET;
00104     if (!host)
00105         sin.sin_addr.s_addr = htonl(INADDR_ANY);
00106     else if (isdigit(*host))
00107         sin.sin_addr.s_addr = inet_addr(host);
00108     else {
00109         hp = gethostbyname(host);
00110         if (!hp)
00111             cant_listen(host, serv, strerror(errno));
00112         memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
00113     }
00114     if (isdigit(*serv))
00115         sin.sin_port = htons(atoi(serv));
00116     else {
00117         sp = getservbyname(serv, "tcp");
00118         if (!sp)
00119             cant_listen(host, serv, strerror(errno));
00120         sin.sin_port = sp->s_port;
00121     }
00122     if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
00123         cant_listen(host, serv, strerror(errno));
00124     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
00125         cant_listen(host, serv, strerror(errno));
00126     if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
00127         cant_listen(host, serv, strerror(errno));
00128     if (listen(fd, SOMAXCONN) < 0)
00129         cant_listen(host, serv, strerror(errno));
00130 
00131     if (addrlenp)
00132         *addrlenp = sizeof(struct sockaddr_in);
00133 
00134 #endif /* !HAVE_GETADDRINFO */
00135 
00136     return fd;
00137 }
00138 
00139 static void
00140 cant_listen(char *host, char *serv, const char *err)
00141 {
00142     fprintf(stderr, "Can't listen on %s%s%s: %s\n",
00143             host ? host : "", host ? ":" : "", serv, err);
00144     exit(1);
00145 }

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