ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/init.C
Revision: 1.61
Committed: Wed Sep 2 16:54:20 2009 UTC (14 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_80
Changes since 1.60: +2 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2001,2007 Mark Wedel
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Deliantra 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 <support@deliantra.net>
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 {
67 refcnt_inc (); // the socket is an external reference
68
69 mss = 1500 - 52; // 1500 typical ethernet frame, 66 typical tcp header overhead
70
71 socket_timeout = 16.;
72
73 {
74 struct linger linger_opt;
75
76 linger_opt.l_onoff = 0;
77 linger_opt.l_linger = 0;
78
79 if (setsockopt (fd, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof (struct linger)))
80 LOG (llevError, "SO_LINGER: %s\n", strerror (errno));
81 }
82
83 {
84 int val;
85
86 #ifdef SO_RCVBUF
87 val = SOCKET_RCVBUF;
88 if (setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)))
89 LOG (llevError, "SO_RCVBUF: %s\n", strerror (errno));
90 #endif
91
92 #ifdef SO_SNDBUF
93 val = SOCKET_SNDBUF;
94 if (setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)))
95 LOG (llevError, "SO_SNDBUF: %s\n", strerror (errno));
96 #endif
97
98 #ifdef IP_TOS
99 val = IPTOS_LOWDELAY;
100 if (setsockopt (fd, IPPROTO_IP, IP_TOS, &val, sizeof (val)))
101 LOG (llevError, "IP_TOS: %s\n", strerror (errno));
102 #endif
103
104 #ifdef TCP_NODELAY
105 val = 1;
106 if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val)))
107 LOG (llevError, "TCP_NODELAY: %s\n", strerror (errno));
108 #endif
109
110 // set some very aggressive keepalive parameters
111 #ifdef TCP_KEEPIDLE
112 val = 1;
113 if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof (val)))
114 LOG (llevError, "TCP_KEEPIDLE: %s\n", strerror (errno));
115 #endif
116
117 #ifdef TCP_KEEPCNT
118 val = 3;
119 if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof (val)))
120 LOG (llevError, "TCP_KEEPCNT: %s\n", strerror (errno));
121 #endif
122
123 #ifdef TCP_KEEPINTVL
124 val = 1;
125 if (setsockopt (fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof (val)))
126 LOG (llevError, "TCP_KEEPINTVL: %s\n", strerror (errno));
127 #endif
128
129 // try to find the mss value in use
130 #ifdef TCP_MAXSEG
131 socklen_t sl = sizeof (val);
132 if (!getsockopt (fd, IPPROTO_TCP, TCP_MAXSEG, &val, &sl) && sl == sizeof (val))
133 mss = val;
134 #endif
135 }
136
137 if (fcntl (fd, F_SETFL, O_NONBLOCK) == -1)
138 LOG (llevError, "InitConnection: Error on fcntl.\n");
139
140 state = ST_SETUP;
141 mapmode = Map1aCmd;
142 mapx = 11;
143 mapy = 11;
144 itemcmd = 1; /* Default is version item1 command */
145 max_rate = 100000 / (1000000 / MAX_TIME); // ~1mbit is assumed per default
146
147 /* Do this so we don't send a face command for the client for
148 * this face. Face 0 is sent to the client to say clear
149 * face information.
150 */
151 faces_sent[0] = true;
152 fx_want [FT_FACE] = true; // all clients must support image faces
153
154 socket_ev.set (fd, EV_READ);
155 socket_ev.prio (2); // one higher than the ticker priority
156 socket_ev.start ();
157
158 // initialisation done, kick it!
159 send_packet_printf ("version %d %d %s\n", VERSION_CS, VERSION_SC, VERSION_INFO);
160 flush ();
161
162 reset_stats ();
163
164 clients.insert (this);
165 }
166
167 client::~client ()
168 {
169 clients.erase (this);
170
171 mapinfo_queue_clear ();
172 free (stats.range);
173 free (stats.title);
174 free (host);
175 }
176
177 void
178 client::do_destroy ()
179 {
180 attachable::do_destroy ();
181
182 if (pl)
183 pl->disconnect ();
184
185 if (fd >= 0)
186 {
187 send_packet ("goodbye");
188 flush ();
189
190 close (fd);
191 }
192
193 state = ST_DEAD;
194
195 socket_ev.stop ();
196
197 refcnt_dec (); // socket no longer open
198 }
199
200 void
201 client::reset_stats ()
202 {
203 /* we need to clear these to -1 and not zero - otherwise,
204 * if a player quits and starts a new character, we wont
205 * send new values to the client, as things like exp start
206 * at zero.
207 */
208 for (int i = 0; i < NUM_SKILLS; i++)
209 last_skill_exp[i] = -1;
210
211 for (int i = 0; i < NROFATTACKS; i++)
212 last_resist[i] = -1;
213
214 last_weapon_sp = -1;
215 last_level = -1;
216 last_stats.exp = -1;
217 last_flags = 0;
218 last_weight = -1;
219 last_weight_limit = 0;
220 last_path_attuned = 0;
221 last_path_repelled = 0;
222 last_path_denied = 0;
223 last_speed = 0;
224 last_flags = 0;
225
226 static living zero_living;
227 last_stats = zero_living;
228 }
229
230 client *
231 client::create (int fd, const char *peername)
232 {
233 client *ns = new client (dup (fd), peername);
234 ns->instantiate (); // effectively a nop right now
235 INVOKE_CLIENT (CONNECT, ns);
236 return ns;
237 }
238