Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_init_c = 00003 * "$Id: init.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2006 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The author can be reached via e-mail to crossfire-devel@real-time.com 00027 */ 00028 00040 #include <global.h> 00041 #ifndef __CEXTRACT__ 00042 #include <sproto.h> 00043 #endif 00044 #ifndef WIN32 /* ---win32 exclude include files */ 00045 #include <sys/types.h> 00046 #include <sys/time.h> 00047 #include <sys/socket.h> 00048 #include <netinet/in.h> 00049 #include <netdb.h> 00050 #endif /* win32 */ 00051 00052 #ifdef HAVE_UNISTD_H 00053 #include <unistd.h> 00054 #endif 00055 00056 #ifdef HAVE_ARPA_INET_H 00057 #include <arpa/inet.h> 00058 #endif 00059 #include <newserver.h> 00060 #include <loader.h> 00061 00063 Socket_Info socket_info; 00068 socket_struct *init_sockets; 00069 00075 void init_connection(socket_struct *ns, const char *from_ip) { 00076 SockList sl; 00077 int bufsize = 65535; /*Supposed absolute upper limit */ 00078 int oldbufsize; 00079 socklen_t buflen = sizeof(int); 00080 00081 #ifdef WIN32 /* ***WIN32 SOCKET: init win32 non blocking socket */ 00082 int temp = 1; 00083 00084 if (ioctlsocket(ns->fd, FIONBIO , &temp) == -1) 00085 LOG(llevError, "init_connection: Error on ioctlsocket.\n"); 00086 #else 00087 if (fcntl(ns->fd, F_SETFL, O_NONBLOCK) == -1) { 00088 LOG(llevError, "init_connection: Error on fcntl.\n"); 00089 } 00090 #endif /* end win32 */ 00091 00092 if (getsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&oldbufsize, &buflen) == -1) 00093 oldbufsize = 0; 00094 if (oldbufsize < bufsize) { 00095 #ifdef ESRV_DEBUG 00096 LOG(llevDebug, "Default buffer size was %d bytes, will reset it to %d\n", oldbufsize, bufsize); 00097 #endif 00098 if (setsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize))) { 00099 LOG(llevError, "init_connection: setsockopt unable to set output buf size to %d\n", bufsize); 00100 } 00101 } 00102 buflen = sizeof(oldbufsize); 00103 getsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&oldbufsize, &buflen); 00104 #ifdef ESRV_DEBUG 00105 LOG(llevDebug, "Socket buffer size now %d bytes\n", oldbufsize); 00106 #endif 00107 00108 ns->faceset = 0; 00109 ns->facecache = 0; 00110 ns->sound = 0; 00111 ns->monitor_spells = 0; 00112 ns->darkness = 1; 00113 ns->status = Ns_Add; 00114 ns->mapx = 11; 00115 ns->mapy = 11; 00116 ns->newmapcmd = 0; 00117 ns->look_position = 0; 00118 ns->update_look = 0; 00119 ns->has_readable_type = 0; 00120 ns->supported_readables = 0; 00121 ns->monitor_spells = 0; 00122 ns->tick = 0; 00123 ns->is_bot = 0; 00124 ns->num_look_objects = DEFAULT_NUM_LOOK_OBJECTS; 00125 ns->want_pickup = 0; 00126 00127 /* we should really do some checking here - if total clients overflows 00128 * we need to do something more intelligent, because client id's will start 00129 * duplicating (not likely in normal cases, but malicous attacks that 00130 * just open and close connections could get this total up. 00131 */ 00132 SockList_Init(&ns->inbuf); 00133 SockList_ResetRead(&ns->inbuf); 00134 /* Basic initialization. Needed because we do a check in 00135 * handle_client for oldsocketmode without checking the 00136 * length of data. 00137 */ 00138 memset(ns->inbuf.buf, 0, sizeof(ns->inbuf.buf)); 00139 memset(&ns->lastmap, 0, sizeof(struct Map)); 00140 if (!ns->faces_sent) 00141 ns->faces_sent = calloc(sizeof(*ns->faces_sent), nrofpixmaps); 00142 ns->faces_sent_len = nrofpixmaps; 00143 00144 memset(&ns->anims_sent, 0, sizeof(ns->anims_sent)); 00145 memset(&ns->stats, 0, sizeof(struct statsinfo)); 00146 ns->map_scroll_x = 0; 00147 ns->map_scroll_y = 0; 00148 /* Do this so we don't send a face command for the client for 00149 * this face. Face 0 is sent to the client to say clear 00150 * face information. 00151 */ 00152 ns->faces_sent[0] = NS_FACESENT_FACE; 00153 00154 ns->outputbuffer.start = 0; 00155 ns->outputbuffer.len = 0; 00156 ns->can_write = 1; 00157 ns->password_fails = 0; 00158 00159 ns->host = strdup_local(from_ip); 00160 SockList_Init(&sl); 00161 SockList_AddPrintf(&sl, "version %d %d %s\n", VERSION_CS, VERSION_SC, VERSION_INFO); 00162 Send_With_Handling(ns, &sl); 00163 SockList_Term(&sl); 00164 #ifdef CS_LOGSTATS 00165 if (socket_info.nconns > cst_tot.max_conn) 00166 cst_tot.max_conn = socket_info.nconns; 00167 if (socket_info.nconns > cst_lst.max_conn) 00168 cst_lst.max_conn = socket_info.nconns; 00169 #endif 00170 } 00171 00173 void init_server(void) { 00174 struct sockaddr_in insock; 00175 struct protoent *protox; 00176 struct linger linger_opt; 00177 char err[MAX_BUF]; 00178 00179 #ifdef WIN32 /* ***win32 - we init a windows socket */ 00180 WSADATA w; 00181 00182 socket_info.max_filedescriptor = 1; /* used in select, ignored in winsockets */ 00183 WSAStartup(0x0101, &w); /* this setup all socket stuff */ 00184 /* ill include no error tests here, winsocket 1.1 should always work */ 00185 /* except some old win95 versions without tcp/ip stack */ 00186 #else /* non windows */ 00187 00188 #ifdef HAVE_SYSCONF 00189 socket_info.max_filedescriptor = sysconf(_SC_OPEN_MAX); 00190 #else 00191 # ifdef HAVE_GETDTABLESIZE 00192 socket_info.max_filedescriptor = getdtablesize(); 00193 # else 00194 "Unable to find usable function to get max filedescriptors"; 00195 # endif 00196 #endif 00197 #endif /* win32 */ 00198 00199 socket_info.timeout.tv_sec = 0; 00200 socket_info.timeout.tv_usec = 0; 00201 socket_info.nconns = 0; 00202 00203 #ifdef CS_LOGSTATS 00204 memset(&cst_tot, 0, sizeof(CS_Stats)); 00205 memset(&cst_lst, 0, sizeof(CS_Stats)); 00206 cst_tot.time_start = time(NULL); 00207 cst_lst.time_start = time(NULL); 00208 #endif 00209 00210 LOG(llevDebug, "Initialize new client/server data\n"); 00211 socket_info.nconns = 1; 00212 init_sockets = malloc(sizeof(socket_struct)); 00213 init_sockets[0].faces_sent = NULL; /* unused */ 00214 socket_info.allocated_sockets = 1; 00215 00216 protox = getprotobyname("tcp"); 00217 if (protox == NULL) { 00218 LOG(llevError, "init_server: Error getting protox\n"); 00219 return; 00220 } 00221 init_sockets[0].fd = socket(PF_INET, SOCK_STREAM, protox->p_proto); 00222 if (init_sockets[0].fd == -1) { 00223 LOG(llevError, "Cannot create socket: %s\n", strerror_local(errno, err, sizeof(err))); 00224 exit(-1); 00225 } 00226 insock.sin_family = AF_INET; 00227 insock.sin_port = htons(settings.csport); 00228 insock.sin_addr.s_addr = htonl(INADDR_ANY); 00229 00230 linger_opt.l_onoff = 0; 00231 linger_opt.l_linger = 0; 00232 if (setsockopt(init_sockets[0].fd, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, sizeof(struct linger))) { 00233 LOG(llevError, "Cannot setsockopt(SO_LINGER): %s\n", strerror_local(errno, err, sizeof(err))); 00234 } 00235 /* Would be nice to have an autoconf check for this. It appears that 00236 * these functions are both using the same calling syntax, just one 00237 * of them needs extra valus passed. 00238 */ 00239 #if defined(__osf__) || defined(hpux) || defined(sgi) || defined(NeXT) || \ 00240 defined(__sun__) || defined(__linux__) || defined(SVR4) || \ 00241 defined(__FreeBSD__) || defined(__OpenBSD__) || \ 00242 defined(WIN32) /* ---win32 add this here */ || \ 00243 defined(__GNU__) /* HURD */ 00244 { 00245 #ifdef WIN32 00246 char tmp = 1; 00247 #else 00248 int tmp = 1; 00249 #endif 00250 00251 if (setsockopt(init_sockets[0].fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp))) { 00252 LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror_local(errno, err, sizeof(err))); 00253 } 00254 } 00255 #else 00256 if (setsockopt(init_sockets[0].fd, SOL_SOCKET, SO_REUSEADDR, (char *)NULL, 0)) { 00257 LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror_local(errno, err, sizeof(err))); 00258 } 00259 #endif 00260 00261 if (bind(init_sockets[0].fd, (struct sockaddr *)&insock, sizeof(insock)) == (-1)) { 00262 LOG(llevError, "Cannot bind socket to port %d: %s\n", ntohs(insock.sin_port), strerror_local(errno, err, sizeof(err))); 00263 #ifdef WIN32 /* ***win32: close() -> closesocket() */ 00264 shutdown(init_sockets[0].fd, SD_BOTH); 00265 closesocket(init_sockets[0].fd); 00266 #else 00267 close(init_sockets[0].fd); 00268 #endif /* win32 */ 00269 exit(-1); 00270 } 00271 if (listen(init_sockets[0].fd, 5) == (-1)) { 00272 LOG(llevError, "Cannot listen on socket: %s\n", strerror_local(errno, err, sizeof(err))); 00273 #ifdef WIN32 /* ***win32: close() -> closesocket() */ 00274 shutdown(init_sockets[0].fd, SD_BOTH); 00275 closesocket(init_sockets[0].fd); 00276 #else 00277 close(init_sockets[0].fd); 00278 #endif /* win32 */ 00279 exit(-1); 00280 } 00281 init_sockets[0].status = Ns_Add; 00282 read_client_images(); 00283 } 00284 00285 /******************************************************************************* 00286 * 00287 * Start of functions dealing with freeing of the data. 00288 * 00289 ******************************************************************************/ 00290 00292 void free_all_newserver(void) { 00293 LOG(llevDebug, "Freeing all new client/server information.\n"); 00294 free_socket_images(); 00295 free(init_sockets); 00296 } 00297 00305 void free_newsocket(socket_struct *ns) { 00306 #ifdef WIN32 /* ***win32: closesocket in windows style */ 00307 shutdown(ns->fd, SD_BOTH); 00308 if (closesocket(ns->fd)) { 00309 #else 00310 if (close(ns->fd)) { 00311 #endif /* win32 */ 00312 00313 #ifdef ESRV_DEBUG 00314 LOG(llevDebug, "Error closing socket %d\n", ns->fd); 00315 #endif 00316 } 00317 ns->fd = -1; 00318 if (ns->stats.range) 00319 FREE_AND_CLEAR(ns->stats.range); 00320 if (ns->stats.title) 00321 FREE_AND_CLEAR(ns->stats.title); 00322 if (ns->host) 00323 FREE_AND_CLEAR(ns->host); 00324 SockList_Term(&ns->inbuf); 00325 } 00326 00328 void final_free_player(player *pl) { 00329 SockList sl; 00330 00331 SockList_Init(&sl); 00332 SockList_AddString(&sl, "goodbye"); 00333 Send_With_Handling(&pl->socket, &sl); 00334 SockList_Term(&sl); 00335 free_newsocket(&pl->socket); 00336 free_player(pl); 00337 }