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

# Content
1 /*
2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 *
4 * 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 *
8 * 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 *
13 * 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 *
18 * 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 *
21 * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 */
23
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 #include <sproto.h>
37 #include <sys/types.h>
38 #include <sys/time.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <netinet/tcp.h>
42 #include <netinet/ip.h>
43 #include <netdb.h>
44
45 #include <unistd.h>
46 #include <arpa/inet.h>
47
48 #include <algorithm>
49
50 // 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 sockvec clients;
57
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 client::client (int fd, const char *peername)
64 : fd (fd), host (strdup (peername)),
65 socket_ev (this, &client::socket_cb),
66 cmd_ev (this, &client::cmd_cb)
67 {
68 refcnt_inc (); // the socket is an external reference
69
70 mss = 1500 - 52; // 1500 typical ethernet frame, 66 typical tcp header overhead
71
72 {
73 struct linger linger_opt;
74
75 linger_opt.l_onoff = 0;
76 linger_opt.l_linger = 0;
77
78 if (setsockopt (fd, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof (struct linger)))
79 LOG (llevError, "SO_LINGER: %s\n", strerror (errno));
80 }
81
82 {
83 int val;
84
85 #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 #ifdef IP_TOS
98 val = IPTOS_LOWDELAY;
99 if (setsockopt (fd, IPPROTO_IP, IP_TOS, &val, sizeof (val)))
100 LOG (llevError, "IP_TOS: %s\n", strerror (errno));
101 #endif
102
103 #ifdef TCP_NODELAY
104 val = 1;
105 if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val)))
106 LOG (llevError, "TCP_NODELAY: %s\n", strerror (errno));
107 #endif
108
109 // set some very aggressive keepalive parameters
110 #ifdef TCP_KEEPIDLE
111 val = 1;
112 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 val = 3;
118 if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof (val)))
119 LOG (llevError, "TCP_KEEPCNT: %s\n", strerror (errno));
120 #endif
121
122 #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
128 // 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 }
135
136 {
137 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
155 state = ST_SETUP;
156 mapmode = Map0Cmd;
157 darkness = 1;
158 mapx = 11;
159 mapy = 11;
160 itemcmd = 1; /* Default is version item1 command */
161 max_rate = 100000 / (1000000 / MAX_TIME); // ~1mbit is assumed per default
162
163 /* 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 faces_sent[0] = true;
168
169 socket_ev.prio (PE_PRIO_NORMAL);
170 socket_ev.fd (fd);
171 socket_ev.poll (PE_R);
172
173 cmd_ev.prio (PE_PRIO_NORMAL);
174
175 // initialisation done, kick it!
176 send_packet_printf ("version %d %d %s\n", VERSION_CS, VERSION_SC, VERSION_INFO);
177 flush ();
178
179 reset_stats ();
180
181 clients.insert (this);
182 }
183
184 client::~client ()
185 {
186 clients.erase (this);
187
188 free (stats.range);
189 free (stats.title);
190 free (host);
191 }
192
193 void
194 client::do_destroy ()
195 {
196 attachable::do_destroy ();
197
198 if (pl)
199 pl->disconnect ();
200
201 if (fd >= 0)
202 {
203 send_packet ("goodbye");
204 flush ();
205
206 close (fd);
207 }
208
209 state = ST_DEAD;
210
211 socket_ev.suspend ();
212 cmd_ev.suspend ();
213
214 refcnt_dec (); // socket no longer open
215 }
216
217 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 last_flags = 0;
243
244 static living zero_living;
245 last_stats = zero_living;
246 }
247
248 /*******************************************************************************
249 *
250 * Start of functions dealing with freeing of the data.
251 *
252 ******************************************************************************/
253
254 /** Free's all the memory that ericserver allocates. */
255 void
256 free_all_newserver (void)
257 {
258 LOG (llevDebug, "Freeing all new client/server information.\n");
259 free_socket_images ();
260 }
261
262 client *
263 client::create (int fd, const char *peername)
264 {
265 client *ns = new client (dup (fd), peername);
266 ns->instantiate (); // effectively a nop right now
267 INVOKE_CLIENT (CONNECT, ns);
268 return ns;
269 }
270