ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/init.C
Revision: 1.49
Committed: Sun Jul 1 05:00:20 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.48: +11 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.49 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 pippijn 1.36 *
4 root 1.46 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2001,2007 Mark Wedel
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.36 *
8 root 1.49 * Crossfire TRT is free software: you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation, either version 3 of the License, or
11     * (at your option) any later version.
12 pippijn 1.36 *
13 root 1.49 * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17 pippijn 1.36 *
18 root 1.49 * You should have received a copy of the GNU General Public License
19     * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 root 1.46 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 pippijn 1.36 */
23 elmex 1.1
24     /**
25     * \file
26     * Socket general functions
27     *
28     * \date 2003-12-02
29     *
30     * Mainly deals with initialization and higher level socket
31     * maintenance (checking for lost connections and if data has arrived.)
32     * The reading of data is handled in ericserver.c
33     */
34    
35     #include <global.h>
36 root 1.11 #include <sproto.h>
37 pippijn 1.10 #include <sys/types.h>
38     #include <sys/time.h>
39     #include <sys/socket.h>
40     #include <netinet/in.h>
41 root 1.23 #include <netinet/tcp.h>
42     #include <netinet/ip.h>
43 pippijn 1.10 #include <netdb.h>
44 elmex 1.1
45 root 1.19 #include <unistd.h>
46     #include <arpa/inet.h>
47 elmex 1.1
48 root 1.31 #include <algorithm>
49    
50 root 1.48 // use relatively small values, as we do not expect to receive much,
51     // and we do userspace write buffering
52     // 8kb limits throughput to roughly 66kb/s
53     #define SOCKET_RCVBUF 8192
54     #define SOCKET_SNDBUF 16384
55    
56 root 1.20 sockvec clients;
57 elmex 1.1
58     /**
59     * Initializes a connection. Really, it just sets up the data structure,
60     * socket setup is handled elsewhere. We do send a version to the
61     * client.
62     */
63 root 1.20 client::client (int fd, const char *peername)
64 root 1.17 : fd (fd), host (strdup (peername)),
65 root 1.21 socket_ev (this, &client::socket_cb),
66 root 1.44 cmd_ev (this, &client::cmd_cb)
67 elmex 1.1 {
68 root 1.34 refcnt_inc (); // the socket is an external reference
69    
70 root 1.43 mss = 1500 - 52; // 1500 typical ethernet frame, 66 typical tcp header overhead
71 root 1.42
72 root 1.16 {
73     struct linger linger_opt;
74    
75 root 1.44 linger_opt.l_onoff = 0;
76 root 1.16 linger_opt.l_linger = 0;
77    
78     if (setsockopt (fd, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof (struct linger)))
79 root 1.23 LOG (llevError, "SO_LINGER: %s\n", strerror (errno));
80 root 1.16 }
81    
82     {
83 root 1.42 int val;
84 root 1.23
85 root 1.48 #ifdef SO_RCVBUF
86     val = SOCKET_RCVBUF;
87     if (setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)))
88     LOG (llevError, "SO_RCVBUF: %s\n", strerror (errno));
89     #endif
90    
91     #ifdef SO_SNDBUF
92     val = SOCKET_SNDBUF;
93     if (setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)))
94     LOG (llevError, "SO_SNDBUF: %s\n", strerror (errno));
95     #endif
96    
97 root 1.42 #ifdef IP_TOS
98     val = IPTOS_LOWDELAY;
99 root 1.23 if (setsockopt (fd, IPPROTO_IP, IP_TOS, &val, sizeof (val)))
100     LOG (llevError, "IP_TOS: %s\n", strerror (errno));
101 root 1.42 #endif
102 root 1.23
103 root 1.42 #ifdef TCP_NODELAY
104     val = 1;
105 root 1.23 if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val)))
106     LOG (llevError, "TCP_NODELAY: %s\n", strerror (errno));
107 root 1.42 #endif
108    
109     // set some very aggressive keepalive parameters
110     #ifdef TCP_KEEPIDLE
111 root 1.44 val = 1;
112 root 1.42 if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof (val)))
113     LOG (llevError, "TCP_KEEPIDLE: %s\n", strerror (errno));
114     #endif
115    
116     #ifdef TCP_KEEPCNT
117 root 1.44 val = 3;
118 root 1.42 if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof (val)))
119     LOG (llevError, "TCP_KEEPCNT: %s\n", strerror (errno));
120     #endif
121 root 1.23
122 root 1.42 #ifdef TCP_KEEPINTVL
123     val = 1;
124     if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof (val)))
125     LOG (llevError, "TCP_KEEPINTVL: %s\n", strerror (errno));
126     #endif
127 root 1.23
128 root 1.42 // try to find the mss value in use
129     #ifdef TCP_MAXSEG
130     socklen_t sl = sizeof (val);
131     if (!getsockopt (fd, IPPROTO_TCP, TCP_MAXSEG, &val, &sl) && sl == sizeof (val))
132     mss = val;
133     #endif
134 root 1.23 }
135    
136     {
137 root 1.16 int bufsize = 65535; /*Supposed absolute upper limit */
138     int oldbufsize;
139     int buflen = sizeof (int);
140    
141     if (fcntl (fd, F_SETFL, O_NONBLOCK) == -1)
142     LOG (llevError, "InitConnection: Error on fcntl.\n");
143    
144     if (getsockopt (fd, SOL_SOCKET, SO_SNDBUF, (char *) &oldbufsize, (socklen_t *) & buflen) == -1)
145     oldbufsize = 0;
146    
147     if (oldbufsize < bufsize)
148     if (setsockopt (fd, SOL_SOCKET, SO_SNDBUF, (char *) &bufsize, sizeof (&bufsize)))
149     LOG (llevError, "InitConnection: setsockopt unable to set output buf size to %d\n", bufsize);
150    
151     buflen = sizeof (oldbufsize);
152     getsockopt (fd, SOL_SOCKET, SO_SNDBUF, (char *) &oldbufsize, (socklen_t *) & buflen);
153     }
154 elmex 1.1
155 root 1.28 state = ST_SETUP;
156 root 1.15 mapmode = Map0Cmd;
157     darkness = 1;
158     mapx = 11;
159     mapy = 11;
160     itemcmd = 1; /* Default is version item1 command */
161 root 1.41 max_rate = 100000 / (1000000 / MAX_TIME); // ~1mbit is assumed per default
162 root 1.12
163 root 1.7 /* Do this so we don't send a face command for the client for
164     * this face. Face 0 is sent to the client to say clear
165     * face information.
166     */
167 root 1.40 faces_sent[0] = true;
168 root 1.7
169 root 1.37 socket_ev.prio (PE_PRIO_NORMAL);
170 root 1.18 socket_ev.fd (fd);
171 root 1.21 socket_ev.poll (PE_R);
172    
173 root 1.37 cmd_ev.prio (PE_PRIO_NORMAL);
174 root 1.15
175 root 1.16 // initialisation done, kick it!
176 root 1.21 send_packet_printf ("version %d %d %s\n", VERSION_CS, VERSION_SC, VERSION_INFO);
177     flush ();
178 root 1.13
179 root 1.35 reset_stats ();
180    
181 root 1.34 clients.insert (this);
182 elmex 1.1 }
183    
184 root 1.20 client::~client ()
185 root 1.16 {
186 root 1.34 clients.erase (this);
187 root 1.32
188 root 1.22 free (stats.range);
189     free (stats.title);
190     free (host);
191 root 1.21 }
192    
193     void
194 root 1.31 client::do_destroy ()
195 root 1.21 {
196 root 1.31 attachable::do_destroy ();
197    
198     if (pl)
199     pl->disconnect ();
200    
201     if (fd >= 0)
202 root 1.34 {
203     send_packet ("goodbye");
204     flush ();
205    
206     close (fd);
207     }
208 root 1.29
209 root 1.28 state = ST_DEAD;
210 root 1.27
211 root 1.21 socket_ev.suspend ();
212     cmd_ev.suspend ();
213 root 1.31
214 root 1.34 refcnt_dec (); // socket no longer open
215 root 1.16 }
216 elmex 1.1
217 root 1.35 void
218     client::reset_stats ()
219     {
220     /* we need to clear these to -1 and not zero - otherwise,
221     * if a player quits and starts a new character, we wont
222     * send new values to the client, as things like exp start
223     * at zero.
224     */
225     for (int i = 0; i < NUM_SKILLS; i++)
226     last_skill_exp[i] = -1;
227    
228     for (int i = 0; i < NROFATTACKS; i++)
229     last_resist[i] = -1;
230    
231     last_weapon_sp = -1;
232     last_level = -1;
233     last_stats.exp = -1;
234     last_weight = (uint32) - 1;
235     last_flags = 0;
236     last_weight = 0;
237     last_weight_limit = 0;
238     last_path_attuned = 0;
239     last_path_repelled = 0;
240     last_path_denied = 0;
241     last_speed = 0;
242 root 1.45 last_flags = 0;
243 root 1.35
244     static living zero_living;
245     last_stats = zero_living;
246     }
247    
248 elmex 1.1 /*******************************************************************************
249     *
250     * Start of functions dealing with freeing of the data.
251     *
252     ******************************************************************************/
253    
254     /** Free's all the memory that ericserver allocates. */
255 root 1.7 void
256     free_all_newserver (void)
257     {
258     LOG (llevDebug, "Freeing all new client/server information.\n");
259     free_socket_images ();
260 elmex 1.1 }
261    
262 root 1.27 client *
263     client::create (int fd, const char *peername)
264 root 1.16 {
265 root 1.38 client *ns = new client (dup (fd), peername);
266     ns->instantiate (); // effectively a nop right now
267     INVOKE_CLIENT (CONNECT, ns);
268     return ns;
269 root 1.16 }
270