--- deliantra/server/socket/init.C 2006/12/21 06:12:37 1.27 +++ deliantra/server/socket/init.C 2007/04/27 02:43:04 1.44 @@ -1,25 +1,26 @@ /* - CrossFire, A Multiplayer game for X-windows - - Copyright (C) 2001 Mark Wedel - Copyright (C) 1992 Frank Tore Johansen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - The author can be reached via e-mail to -*/ + * CrossFire, A Multiplayer game for X-windows + * + * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team + * Copyright (C) 2001 Mark Wedel + * Copyright (C) 1992 Frank Tore Johansen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * The author can be reached via e-mail to + */ /** * \file @@ -45,6 +46,8 @@ #include #include +#include + sockvec clients; /** @@ -55,13 +58,16 @@ client::client (int fd, const char *peername) : fd (fd), host (strdup (peername)), socket_ev (this, &client::socket_cb), - cmd_ev (this, &client::cmd_cb), - cc_inv (this), cc_other (this) + cmd_ev (this, &client::cmd_cb) { + refcnt_inc (); // the socket is an external reference + + mss = 1500 - 52; // 1500 typical ethernet frame, 66 typical tcp header overhead + { struct linger linger_opt; - linger_opt.l_onoff = 0; + linger_opt.l_onoff = 0; linger_opt.l_linger = 0; if (setsockopt (fd, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof (struct linger))) @@ -69,38 +75,47 @@ } { - int val = IPTOS_LOWDELAY; + int val; +#ifdef IP_TOS + val = IPTOS_LOWDELAY; if (setsockopt (fd, IPPROTO_IP, IP_TOS, &val, sizeof (val))) LOG (llevError, "IP_TOS: %s\n", strerror (errno)); - } - - { - int val = 1; +#endif +#ifdef TCP_NODELAY + val = 1; if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val))) LOG (llevError, "TCP_NODELAY: %s\n", strerror (errno)); - } +#endif -#ifdef __linux__ - { - int val; + // set some very aggressive keepalive parameters +#ifdef TCP_KEEPIDLE + val = 1; + if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof (val))) + LOG (llevError, "TCP_KEEPIDLE: %s\n", strerror (errno)); +#endif - // set some very aggressive keepalive parameters - val = 10; - if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof (val))) - LOG (llevError, "TCP_KEEPIDLE: %s\n", strerror (errno)); - - val = 5; - if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof (val))) - LOG (llevError, "TCP_KEEPCNT: %s\n", strerror (errno)); - - val = 1; - if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof (val))) - LOG (llevError, "TCP_KEEPINTVL: %s\n", strerror (errno)); - } +#ifdef TCP_KEEPCNT + val = 3; + if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof (val))) + LOG (llevError, "TCP_KEEPCNT: %s\n", strerror (errno)); +#endif + +#ifdef TCP_KEEPINTVL + val = 1; + if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof (val))) + LOG (llevError, "TCP_KEEPINTVL: %s\n", strerror (errno)); #endif + // try to find the mss value in use +#ifdef TCP_MAXSEG + socklen_t sl = sizeof (val); + if (!getsockopt (fd, IPPROTO_TCP, TCP_MAXSEG, &val, &sl) && sl == sizeof (val)) + mss = val; +#endif + } + { int bufsize = 65535; /*Supposed absolute upper limit */ int oldbufsize; @@ -120,62 +135,97 @@ getsockopt (fd, SOL_SOCKET, SO_SNDBUF, (char *) &oldbufsize, (socklen_t *) & buflen); } + state = ST_SETUP; mapmode = Map0Cmd; darkness = 1; mapx = 11; mapy = 11; itemcmd = 1; /* Default is version item1 command */ - - faces_sent = salloc0 (nrofpixmaps); + max_rate = 100000 / (1000000 / MAX_TIME); // ~1mbit is assumed per default /* Do this so we don't send a face command for the client for * this face. Face 0 is sent to the client to say clear * face information. */ - faces_sent[0] = NS_FACESENT_FACE; + faces_sent[0] = true; - // socket I/O is low priority - // we prefer to have the server run instead of handling client requests - socket_ev.prio (PE_PRIO_NORMAL + 1); + socket_ev.prio (PE_PRIO_NORMAL); socket_ev.fd (fd); socket_ev.poll (PE_R); - // command handling is even lower priority - // that way no client can monopolise the server - cmd_ev.prio (PE_PRIO_NORMAL + 2); + cmd_ev.prio (PE_PRIO_NORMAL); // initialisation done, kick it! send_packet_printf ("version %d %d %s\n", VERSION_CS, VERSION_SC, VERSION_INFO); flush (); -#if 0//TODO - socket_info.nconns++; - if (socket_info.nconns > cst_tot.max_conn) cst_tot.max_conn = socket_info.nconns; - if (socket_info.nconns > cst_lst.max_conn) cst_lst.max_conn = socket_info.nconns; -#endif + reset_stats (); + + clients.insert (this); } client::~client () { - if (pl) - pl->socket = 0; + clients.erase (this); - if (fd >= 0) - close (fd); - - sfree (faces_sent, nrofpixmaps); free (stats.range); free (stats.title); free (host); } void -client::destroy () +client::do_destroy () { - destroyed = true; + attachable::do_destroy (); + + if (pl) + pl->disconnect (); + + if (fd >= 0) + { + send_packet ("goodbye"); + flush (); + + close (fd); + } + + state = ST_DEAD; socket_ev.suspend (); cmd_ev.suspend (); + + refcnt_dec (); // socket no longer open +} + +void +client::reset_stats () +{ + /* we need to clear these to -1 and not zero - otherwise, + * if a player quits and starts a new character, we wont + * send new values to the client, as things like exp start + * at zero. + */ + for (int i = 0; i < NUM_SKILLS; i++) + last_skill_exp[i] = -1; + + for (int i = 0; i < NROFATTACKS; i++) + last_resist[i] = -1; + + last_weapon_sp = -1; + last_level = -1; + last_stats.exp = -1; + last_weight = (uint32) - 1; + last_flags = 0; + last_weight = 0; + last_weight_limit = 0; + last_path_attuned = 0; + last_path_repelled = 0; + last_path_denied = 0; + last_speed = 0; + flags = 0; + + static living zero_living; + last_stats = zero_living; } /** This sets up the socket and reads all the image information into memory. */ @@ -186,8 +236,6 @@ cst_lst.time_start = time (NULL); LOG (llevDebug, "Initialize new client/server data\n"); - - read_client_images (); } @@ -205,31 +253,12 @@ free_socket_images (); } -/** Sends the 'goodbye' command to the player, and closes connection. */ -void -final_free_player (player *pl) -{ - free_player (pl); -} - client * client::create (int fd, const char *peername) { - if (checkbanned (NULL, peername)) - { - LOG (llevInfo, "Banned host tried to connect: [%s]\n", peername); - return 0; - } - else - { - client *ns = new client (dup (fd), peername); - clients.push_back (ns); - - ns->instantiate (); // effectively a nop right now - - INVOKE_CLIENT (CONNECT, ns); - - return ns; - } + client *ns = new client (dup (fd), peername); + ns->instantiate (); // effectively a nop right now + INVOKE_CLIENT (CONNECT, ns); + return ns; }