ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/loop.C
(Generate patch)

Comparing deliantra/server/socket/loop.C (file contents):
Revision 1.6 by root, Sun Sep 10 13:43:33 2006 UTC vs.
Revision 1.17 by root, Fri Dec 15 03:53:44 2006 UTC

1
2/*
3 * static char *rcsid_loop_c =
4 * "$Id: loop.C,v 1.6 2006/09/10 13:43:33 root Exp $";
5 */
6
7/* 1/*
8 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
9 3
10 Copyright (C) 2002-2003 Mark Wedel & The Crossfire Development Team 4 Copyright (C) 2002-2003 Mark Wedel & The Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen 5 Copyright (C) 1992 Frank Tore Johansen
22 16
23 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software 18 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 20
27 The author can be reached via e-mail to crossfire-devel@real-time.com 21 The author can be reached via e-mail to <crossfire@schmorp.de>
28*/ 22*/
29 23
30/** 24/**
31 * \file 25 * \file
32 * Main client/server loops. 26 * Main client/server loops.
38 * The reading of data is handled in ericserver.c 32 * The reading of data is handled in ericserver.c
39 */ 33 */
40 34
41 35
42#include <global.h> 36#include <global.h>
43#ifndef __CEXTRACT__
44# include <sproto.h> 37#include <sproto.h>
45# include <sockproto.h> 38#include <sockproto.h>
46#endif
47 39
48#ifndef WIN32 /* ---win32 exclude unix headers */
49# include <sys/types.h> 40#include <sys/types.h>
50# include <sys/time.h> 41#include <sys/time.h>
51# include <sys/socket.h> 42#include <sys/socket.h>
52# include <netinet/in.h> 43#include <netinet/in.h>
53# include <netdb.h> 44#include <netdb.h>
54#endif /* end win32 */
55 45
56#ifdef HAVE_UNISTD_H
57# include <unistd.h> 46#include <unistd.h>
58#endif
59
60#ifdef HAVE_ARPA_INET_H
61# include <arpa/inet.h> 47#include <arpa/inet.h>
62#endif
63 48
64#include <loader.h> 49#include <loader.h>
65#include <newserver.h> 50#include <newserver.h>
66 51
67/***************************************************************************** 52/*****************************************************************************
75 * before player joins, and those happen after the player has joined. 60 * before player joins, and those happen after the player has joined.
76 * As such, we have function types that might be called, so 61 * As such, we have function types that might be called, so
77 * we end up having 2 tables. 62 * we end up having 2 tables.
78 */ 63 */
79 64
80typedef void (*func_uint8_int_ns) (char *, int, NewSocket *); 65enum {
81 66 PF_PLAYER = 0x01, // must have valid player
82struct NsCmdMapping 67 PF_IMMEDIATE = 0x02, // TODO: hack, can be executed immediately
83{ 68 PF_PLAYING = 0x04, // must be in playing state
84 const char *cmdname;
85 func_uint8_int_ns cmdproc;
86}; 69};
87 70
88typedef void (*func_uint8_int_pl) (char *, int, player *); 71struct pkt_type
89struct PlCmdMapping
90{ 72{
91 const char *cmdname; 73 const char *name;
92 func_uint8_int_pl cmdproc; 74 void *cb;
93 uint8 flag; 75 int flags;
76
77 bool may_execute (client_socket *ns)
78 {
79 return (!(flags & PF_PLAYER) || ns->pl)
80 && (!(flags & PF_PLAYING) || (ns->pl && ns->pl->state == ST_PLAYING));
81 }
82
83 void execute (client_socket *ns, char *data, int datalen)
84 {
85 //TODO: only one format
86 if (flags & PF_PLAYER)
87 ((void (*)(char *, int, player * ))cb)((char *)data, datalen, ns->pl);
88 else
89 ((void (*)(char *, int, client_socket *))cb)((char *)data, datalen, ns);
90 }
94}; 91};
95 92
93// SocketCommand, PlayingCommand, should not exist with those ugly casts
94#define SC(cb) (void *)static_cast<void (*)(char *, int, client_socket *)>(cb),
95#define PC(cb) (void *)static_cast<void (*)(char *, int, player *)>(cb), PF_PLAYER |
96
96/** 97/**
97 * Dispatch table for the server. 98 * Dispatch table for the server.
98 * 99 */
99 * CmdMapping is the dispatch table for the server, used in HandleClient, 100static struct pkt_type packets[] = {
100 * which gets called when the client has input. All commands called here 101 {"ncom", PC(NewPlayerCmd) PF_PLAYING },
101 * use the same parameter form (char* data, int len, int clientnum. 102 {"command", PC(PlayerCmd) PF_PLAYING },
102 * We do implicit casts, because the data that is being passed is 103
103 * unsigned (pretty much needs to be for binary data), however, most 104 {"examine", PC(ExamineCmd) PF_PLAYING | PF_IMMEDIATE },
104 * of these treat it only as strings, so it makes things easier 105 {"apply", PC(ApplyCmd) PF_PLAYING | PF_IMMEDIATE },
105 * to cast it here instead of a bunch of times in the function itself. 106 {"reply", PC(ReplyCmd) PF_IMMEDIATE },
106 * flag is 1 if the player must be in the playing state to issue the 107 {"lookat", PC(LookAt) PF_PLAYING | PF_IMMEDIATE },
107 * command, 0 if they can issue it at any time. 108 {"lock", PC(LockItem) PF_PLAYING | PF_IMMEDIATE },
108 */ 109 {"mark", PC(MarkItem) PF_PLAYING | PF_IMMEDIATE },
109static struct PlCmdMapping plcommands[] = { 110 {"move", PC(MoveCmd) PF_PLAYING | PF_IMMEDIATE },
110 {"examine", ExamineCmd, 1}, 111 {"ext", PC(ExtCmd) PF_IMMEDIATE }, /* CF+ */
111 {"apply", ApplyCmd, 1},
112 {"move", MoveCmd, 1},
113 {"reply", ReplyCmd, 0},
114 {"command", PlayerCmd, 1},
115 {"ncom", (func_uint8_int_pl) NewPlayerCmd, 1},
116 {"lookat", LookAt, 1},
117 {"lock", (func_uint8_int_pl) LockItem, 1},
118 {"mark", (func_uint8_int_pl) MarkItem, 1},
119 {"mapredraw", MapRedrawCmd, 0}, /* Added: phil */ 112 {"mapredraw", PC(MapRedrawCmd) PF_IMMEDIATE }, /* Added: phil */
120 {"mapinfo", MapInfoCmd, 2}, /* CF+ */ 113 {"mapinfo", PC(MapInfoCmd) PF_IMMEDIATE }, /* CF+ */
121 {"ext", ExtCmd, 2}, /* CF+ */
122 {NULL, NULL, 0} /* terminator */
123};
124 114
125/** Face-related commands */ 115 {"addme", SC(AddMeCmd) PF_IMMEDIATE },
126static struct NsCmdMapping nscommands[] = {
127 {"addme", AddMeCmd},
128 {"askface", SendFaceCmd}, /* Added: phil */ 116 {"askface", SC(SendFaceCmd) 0 }, /* Added: phil */
129 {"requestinfo", RequestInfo}, 117 {"requestinfo", SC(RequestInfo) 0 },
130 {"setfacemode", SetFaceMode}, 118 {"setfacemode", SC(SetFaceMode) PF_IMMEDIATE },
131 {"setsound", SetSound}, 119 {"setsound", SC(SetSound) PF_IMMEDIATE },
132 {"setup", SetUp}, 120 {"setup", SC(SetUp) PF_IMMEDIATE },
133 {"version", VersionCmd}, 121 {"version", SC(VersionCmd) PF_IMMEDIATE },
134 {"toggleextendedinfos", ToggleExtendedInfos}, /*Added: tchize */ 122 {"toggleextendedinfos", SC(ToggleExtendedInfos) PF_IMMEDIATE }, /*Added: tchize */
135 {"toggleextendedtext", ToggleExtendedText}, /*Added: tchize */ 123 {"toggleextendedtext", SC(ToggleExtendedText) PF_IMMEDIATE }, /*Added: tchize */
136 {"asksmooth", AskSmooth}, /*Added: tchize (smoothing technologies) */ 124 {"asksmooth", SC(AskSmooth) 0 }, /*Added: tchize (smoothing technologies) */
137 {NULL, NULL} /* terminator (I, II & III) */
138}; 125};
139 126
140/** 127/**
141 * RequestInfo is sort of a meta command. There is some specific 128 * RequestInfo is sort of a meta command. There is some specific
142 * request of information, but we call other functions to provide 129 * request of information, but we call other functions to provide
143 * that information. 130 * that information.
144 */ 131 */
145void 132void
146RequestInfo (char *buf, int len, NewSocket * ns) 133RequestInfo (char *buf, int len, client_socket * ns)
147{ 134{
148 char *params = NULL, *cp; 135 char *params = NULL, *cp;
149 136
150 /* No match */ 137 /* No match */
151 char bigbuf[MAX_BUF]; 138 char bigbuf[MAX_BUF];
166 { 153 {
167 *cp = '\0'; 154 *cp = '\0';
168 params = cp + 1; 155 params = cp + 1;
169 break; 156 break;
170 } 157 }
158
171 if (!strcmp (buf, "image_info")) 159 if (!strcmp (buf, "image_info"))
172 send_image_info (ns, params); 160 send_image_info (ns, params);
173 else if (!strcmp (buf, "image_sums")) 161 else if (!strcmp (buf, "image_sums"))
174 send_image_sums (ns, params); 162 send_image_sums (ns, params);
175 else if (!strcmp (buf, "skill_info")) 163 else if (!strcmp (buf, "skill_info"))
176 send_skill_info (ns, params); 164 send_skill_info (ns, params);
177 else if (!strcmp (buf, "spell_paths")) 165 else if (!strcmp (buf, "spell_paths"))
178 send_spell_paths (ns, params); 166 send_spell_paths (ns, params);
179 else 167 else
180 Write_String_To_Socket (ns, bigbuf, len); 168 ns->send_packet (bigbuf, len);
181} 169}
182 170
183/** 171/**
184 * Handle client input. 172 * Handle client input.
185 * 173 *
189 * with this socket, null if no player (one of the init_sockets for just 177 * with this socket, null if no player (one of the init_sockets for just
190 * starting a connection) 178 * starting a connection)
191 */ 179 */
192 180
193void 181void
194HandleClient (NewSocket * ns, player *pl) 182HandleClient (client_socket *ns, player *pl)
195{ 183{
196 int len = 0, i, cnt;
197 char *data;
198
199 /* Loop through this - maybe we have several complete packets here. */ 184 /* Loop through this - maybe we have several complete packets here. */
200 // limit to a few commands only, though, as to not monopolise the server 185 // limit to a few commands only, though, as to not monopolise the server
201 for (cnt = 16; cnt--;) 186 for (int repeat = 16; repeat--;)
202 { 187 {
203 /* If it is a player, and they don't have any speed left, we 188 /* If it is a player, and they don't have any speed left, we
204 * return, and will read in the data when they do have time. 189 * return, and will read in the data when they do have time.
205 */ 190 */
206 if (pl && pl->state == ST_PLAYING && pl->ob != NULL && pl->ob->speed_left < 0) 191 if (pl && pl->state == ST_PLAYING && pl->ob && pl->ob->speed_left < 0)
207 {
208 return; 192 return;
193
194 int pkt_len = ns->read_packet ();
195
196 if (pkt_len < 0)
209 } 197 {
210 198 LOG (llevError, "read error on player %s\n", &pl->ob->name);
211 i = SockList_ReadPacket (ns->fd, &ns->inbuf, MAXSOCKBUF - 1);
212
213 if (i < 0)
214 {
215#ifdef ESRV_DEBUG
216 LOG (llevDebug, "HandleClient: Read error on connection player %s\n", (pl ? pl->ob->name : "None"));
217#endif
218 /* Caller will take care of cleaning this up */ 199 /* Caller will take care of cleaning this up */
219 ns->status = Ns_Dead; 200 ns->status = Ns_Dead;
220 return; 201 return;
221 } 202 }
203 else if (pkt_len == 0)
222 /* Still dont have a full packet */ 204 /* Still dont have a full packet */
223 if (i == 0)
224 return; 205 return;
225
226// //D//TODO//temporarily log long commands
227// if (ns->inbuf.len >= 40 && pl && pl->ob)
228// LOG (llevDebug, "HandleClient: long comamnd from <%s,%s> %d<%s>\n", pl->ob->name, ns->host, ns->inbuf.len, ns->inbuf.buf + 2);
229 206
230 /* First, break out beginning word. There are at least 207 /* First, break out beginning word. There are at least
231 * a few commands that do not have any paremeters. If 208 * a few commands that do not have any paremeters. If
232 * we get such a command, don't worry about trying 209 * we get such a command, don't worry about trying
233 * to break it up. 210 * to break it up.
234 */ 211 */
212 int datalen;
235 data = (char *) strchr ((char *) ns->inbuf.buf + 2, ' '); 213 char *data = strchr ((char *)ns->inbuf + 2, ' ');
214
236 if (data) 215 if (data)
237 { 216 {
238 *data = '\0'; 217 *data++ = 0;
239 data++; 218 datalen = pkt_len - (data - (char *)ns->inbuf);
240 len = ns->inbuf.len - (data - (char *) ns->inbuf.buf);
241 } 219 }
242 else 220 else
243 len = 0;
244
245 ns->inbuf.buf[ns->inbuf.len] = '\0'; /* Terminate buffer - useful for string data */
246 for (i = 0; nscommands[i].cmdname != NULL; i++)
247 {
248 if (strcmp ((char *) ns->inbuf.buf + 2, nscommands[i].cmdname) == 0)
249 {
250 nscommands[i].cmdproc ((char *) data, len, ns);
251 ns->inbuf.len = 0;
252 return; //D// not doing this causes random memory corruption
253 goto next_packet;
254 }
255 } 221 {
256 /* Player must be in the playing state or the flag on the 222 data = (char *)ns->inbuf + 2; // better read garbage than segfault
257 * the command must be zero for the user to use the command - 223 datalen = 0;
258 * otherwise, a player cam save, be in the play_again state, and
259 * the map they were on gets swapped out, yet things that try to look
260 * at the map causes a crash. If the command is valid, but
261 * one they can't use, we still swallow it up.
262 */ 224 }
263 if (pl) 225
264 for (i = 0; plcommands[i].cmdname != NULL; i++) 226 ns->inbuf [pkt_len] = 0; /* Terminate buffer - useful for string data */
227
228 for (pkt_type *pkt = packets; pkt < packets + (sizeof (packets) / sizeof (packets[0])); ++pkt)
229 if (!strcmp ((char *)ns->inbuf + 2, pkt->name))
265 { 230 {
266 if (strcmp ((char *) ns->inbuf.buf + 2, plcommands[i].cmdname) == 0) 231 if (pkt->may_execute (ns))
267 { 232 {
268 if (pl->state == ST_PLAYING || !(plcommands[i].flag & 1)) 233 pkt->execute (ns, data, datalen);
269 plcommands[i].cmdproc ((char *) data, len, pl); 234 ns->skip_packet (pkt_len);
270 ns->inbuf.len = 0;
271 //D// not doing this causes random memory corruption 235 //D//TODO not doing this causes random memory corruption
272 if (plcommands[i].flag & 2) 236 if (pkt->flags & PF_IMMEDIATE)
273 goto next_packet; 237 goto next_packet;
274 return; 238 return;
275 } 239 }
276 } 240 }
241
277 /* If we get here, we didn't find a valid command. Logging 242 /* If we get here, we didn't find a valid command. Logging
278 * this might be questionable, because a broken client/malicious 243 * this might be questionable, because a broken client/malicious
279 * user could certainly send a whole bunch of invalid commands. 244 * user could certainly send a whole bunch of invalid commands.
280 */ 245 */
281 LOG (llevDebug, "Bad command from client (%s)\n", ns->inbuf.buf + 2); 246 LOG (llevDebug, "Bad command from client (%s)\n", ns->inbuf + 2);
247 ns->skip_packet (pkt_len);
282 next_packet: 248 next_packet:
283 ; 249 ;
284 } 250 }
285} 251}
286 252
287
288/*****************************************************************************
289 *
290 * Low level socket looping - select calls and watchdog udp packet
291 * sending.
292 *
293 ******************************************************************************/
294
295#ifdef WATCHDOG
296
297/**
298 * Tell watchdog that we are still alive
299 *
300 * I put the function here since we should hopefully already be getting
301 * all the needed include files for socket support
302 */
303
304void
305watchdog (void)
306{
307 static int fd = -1;
308 static struct sockaddr_in insock;
309
310 if (fd == -1)
311 {
312 struct protoent *protoent;
313
314 if ((protoent = getprotobyname ("udp")) == NULL || (fd = socket (PF_INET, SOCK_DGRAM, protoent->p_proto)) == -1)
315 {
316 return;
317 }
318 insock.sin_family = AF_INET;
319 insock.sin_port = htons ((unsigned short) 13325);
320 insock.sin_addr.s_addr = inet_addr ("127.0.0.1");
321 }
322 sendto (fd, (void *) &fd, 1, 0, (struct sockaddr *) &insock, sizeof (insock));
323}
324#endif
325
326void 253void
327flush_sockets (void) 254flush_sockets (void)
328{ 255{
329 player *pl; 256 for (sockvec::iterator i = client_sockets.begin (); i != client_sockets.end (); ++i)
330
331 for (pl = first_player; pl != NULL; pl = pl->next)
332 if (pl->socket.status != Ns_Dead) 257 if ((*i)->status != Ns_Dead)
333 Socket_Flush (&pl->socket); 258 (*i)->flush ();
334} 259}
335 260
336/** 261/**
337 * This checks the sockets for input and exceptions, does the right thing. 262 * This checks the sockets for input, does the right thing.
338 * 263 *
339 * A bit of this code is grabbed out of socket.c 264 * A bit of this code is grabbed out of socket.c
340 * There are 2 lists we need to look through - init_sockets is a list 265 * There are 2 lists we need to look through - init_sockets is a list
341 * 266 *
342 */ 267 */
343void 268void
344doeric_server (void) 269doeric_server (void)
345{ 270{
346 int i, pollret; 271 int i, pollret;
347 fd_set tmp_read, tmp_exceptions, tmp_write; 272 fd_set tmp_read;
348 struct sockaddr_in addr; 273 struct sockaddr_in addr;
349 socklen_t addrlen = sizeof (struct sockaddr); 274 socklen_t addrlen = sizeof (struct sockaddr);
350 player *pl, *next; 275 player *pl, *next;
276 int maxfd = 0;
351 277
352#ifdef CS_LOGSTATS 278#ifdef CS_LOGSTATS
353 if ((time (NULL) - cst_lst.time_start) >= CS_LOGTIME) 279 if ((time (NULL) - cst_lst.time_start) >= CS_LOGTIME)
354 write_cs_stats (); 280 write_cs_stats ();
355#endif 281#endif
356 282
357 FD_ZERO (&tmp_read);
358 FD_ZERO (&tmp_write);
359 FD_ZERO (&tmp_exceptions);
360
361 for (i = 0; i < socket_info.allocated_sockets; i++)
362 {
363 if (init_sockets[i].status == Ns_Dead)
364 {
365 free_newsocket (&init_sockets[i]);
366 init_sockets[i].status = Ns_Avail;
367 socket_info.nconns--;
368 }
369 else if (init_sockets[i].status != Ns_Avail)
370 {
371 FD_SET ((uint32) init_sockets[i].fd, &tmp_read);
372 FD_SET ((uint32) init_sockets[i].fd, &tmp_write);
373 FD_SET ((uint32) init_sockets[i].fd, &tmp_exceptions);
374 }
375 }
376
377 /* Go through the players. Let the loop set the next pl value, 283 /* Go through the players. Let the loop set the next pl value,
378 * since we may remove some 284 * since we may remove some
379 */ 285 */
286 //TODO: must be handled cleanly elsewhere
380 for (pl = first_player; pl != NULL;) 287 for (pl = first_player; pl; )
381 { 288 {
289 player *npl = pl->next;
290
291 //TODO: must be handled cleanly elsewhere
382 if (pl->socket.status == Ns_Dead) 292 if (pl->socket->status == Ns_Dead)
383 { 293 {
384 player *npl = pl->next;
385
386 save_player (pl->ob, 0); 294 save_player (pl->ob, 0);
295
387 if (!QUERY_FLAG (pl->ob, FLAG_REMOVED)) 296 if (!QUERY_FLAG (pl->ob, FLAG_REMOVED))
388 { 297 {
389 terminate_all_pets (pl->ob); 298 terminate_all_pets (pl->ob);
390 remove_ob (pl->ob); 299 pl->ob->remove ();
391 } 300 }
301
392 leave (pl, 1); 302 leave (pl, 1);
393 final_free_player (pl); 303 final_free_player (pl);
304 }
305
394 pl = npl; 306 pl = npl;
307 }
308
309 FD_ZERO (&tmp_read);
310
311 for (sockvec::iterator i = client_sockets.begin (); i != client_sockets.end (); )
312 {
313 client_socket *s = *i;
314
315 if (s->status == Ns_Dead)
316 {
317 client_sockets.erase (i);
318 delete s;
395 } 319 }
396 else 320 else
397 { 321 {
322 if (s->fd > maxfd) maxfd = s->fd;
323
398 FD_SET ((uint32) pl->socket.fd, &tmp_read); 324 FD_SET (s->fd, &tmp_read);
399 FD_SET ((uint32) pl->socket.fd, &tmp_write);
400 FD_SET ((uint32) pl->socket.fd, &tmp_exceptions);
401 pl = pl->next;
402 }
403 }
404 325
405 /* Reset timeout each time, since some OS's will change the values on 326 ++i;
406 * the return from select. 327 }
407 */ 328 }
329
330 struct timeval timeout;
331
408 socket_info.timeout.tv_sec = 0; 332 timeout.tv_sec = 0;
409 socket_info.timeout.tv_usec = 0; 333 timeout.tv_usec = 0;
410 334
411 pollret = select (socket_info.max_filedescriptor, &tmp_read, &tmp_write, &tmp_exceptions, &socket_info.timeout); 335 pollret = select (maxfd + 1,
336 &tmp_read, 0, 0,
337 &timeout);
412 338
413 if (pollret == -1) 339 if (pollret == -1)
414 { 340 {
415 LOG (llevError, "select failed: %s\n", strerror (errno)); 341 LOG (llevError, "select failed: %s\n", strerror (errno));
416 return; 342 return;
417 } 343 }
418 344
419 /* We need to do some of the processing below regardless */ 345 /* We need to do some of the processing below regardless */
420 346
421/* if (!pollret) return;*/ 347 /* Check for any input on the sockets */
422 348 for (sockvec::iterator i = client_sockets.begin (); i != client_sockets.end (); ++i)
423 /* Following adds a new connection */
424 if (pollret && FD_ISSET (init_sockets[0].fd, &tmp_read))
425 { 349 {
426 int newsocknum = 0; 350 client_socket *s = *i;
351 player *pl = s->pl;
427 352
428#ifdef ESRV_DEBUG 353 //TODO: disassociate handleclient from socket readin
429 LOG (llevDebug, "doeric_server: New Connection\n"); 354 if (s->inbuf_len || FD_ISSET (s->fd, &tmp_read))
430#endif 355 HandleClient (s, pl);
431 /* If this is the case, all sockets currently in used */ 356
432 if (socket_info.allocated_sockets <= socket_info.nconns) 357 //TODO: should not be done here, either
433 { 358 if (s->status != Ns_Dead && pl)
434 init_sockets = (NewSocket *) realloc (init_sockets, sizeof (NewSocket) * (socket_info.nconns + 1));
435 if (!init_sockets)
436 fatal (OUT_OF_MEMORY);
437 newsocknum = socket_info.allocated_sockets;
438 socket_info.allocated_sockets++;
439 init_sockets[newsocknum].faces_sent_len = nrofpixmaps;
440 init_sockets[newsocknum].faces_sent = (uint8 *) malloc (nrofpixmaps * sizeof (*init_sockets[newsocknum].faces_sent));
441 if (!init_sockets[newsocknum].faces_sent)
442 fatal (OUT_OF_MEMORY);
443 init_sockets[newsocknum].status = Ns_Avail;
444 } 359 {
445 else 360 /* Update the players stats once per tick. More efficient than
446 { 361 * sending them whenever they change, and probably just as useful
447 int j;
448
449 for (j = 1; j < socket_info.allocated_sockets; j++)
450 if (init_sockets[j].status == Ns_Avail)
451 { 362 */
452 newsocknum = j; 363 esrv_update_stats (pl);
453 break; 364 if (pl->last_weight != -1 && pl->last_weight != WEIGHT (pl->ob))
454 }
455 }
456 init_sockets[newsocknum].fd = accept (init_sockets[0].fd, (struct sockaddr *) &addr, &addrlen);
457 if (init_sockets[newsocknum].fd == -1)
458 {
459 LOG (llevError, "accept failed: %s\n", strerror (errno));
460 }
461 else
462 {
463 char buf[MAX_BUF];
464 long ip;
465 NewSocket *ns;
466
467 ns = &init_sockets[newsocknum];
468
469 ip = ntohl (addr.sin_addr.s_addr);
470 sprintf (buf, "%ld.%ld.%ld.%ld", (ip >> 24) & 255, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
471
472 if (checkbanned (NULL, buf))
473 { 365 {
474 LOG (llevInfo, "Banned host tried to connect: [%s]\n", buf); 366 esrv_update_item (UPD_WEIGHT, pl->ob, pl->ob);
475 close (init_sockets[newsocknum].fd); 367 if (pl->last_weight != WEIGHT (pl->ob))
476 init_sockets[newsocknum].fd = -1; 368 LOG (llevError, "esrv_update_item(UPD_WEIGHT) did not set player weight: is %lu, should be %lu\n",
369 (unsigned long) pl->last_weight, WEIGHT (pl->ob));
477 } 370 }
478 else
479 {
480 InitConnection (ns, buf);
481 socket_info.nconns++;
482 }
483 }
484 }
485 371
486 /* Check for any exceptions/input on the sockets */ 372 /* draw_client_map does sanity checking that map is
487 if (pollret) 373 * valid, so don't do it here.
488 for (i = 1; i < socket_info.allocated_sockets; i++)
489 {
490 if (init_sockets[i].status == Ns_Avail)
491 continue;
492 if (FD_ISSET (init_sockets[i].fd, &tmp_exceptions))
493 {
494 free_newsocket (&init_sockets[i]);
495 init_sockets[i].status = Ns_Avail;
496 socket_info.nconns--;
497 continue;
498 }
499 if (FD_ISSET (init_sockets[i].fd, &tmp_read))
500 {
501 HandleClient (&init_sockets[i], NULL);
502 }
503 if (FD_ISSET (init_sockets[i].fd, &tmp_write))
504 {
505 init_sockets[i].can_write = 1;
506 }
507 }
508
509 /* This does roughly the same thing, but for the players now */
510 for (pl = first_player; pl != NULL; pl = next)
511 {
512
513 next = pl->next;
514 if (pl->socket.status == Ns_Dead)
515 continue;
516
517 if (FD_ISSET (pl->socket.fd, &tmp_write))
518 {
519 if (!pl->socket.can_write)
520 {
521#if 0
522 LOG (llevDebug, "Player %s socket now write enabled\n", pl->ob->name);
523#endif
524 pl->socket.can_write = 1;
525 write_socket_buffer (&pl->socket);
526 }
527 /* if we get an error on the write_socket buffer, no reason to
528 * continue on this socket.
529 */ 374 */
530 if (pl->socket.status == Ns_Dead)
531 continue;
532 }
533 else
534 pl->socket.can_write = 0;
535
536 if (FD_ISSET (pl->socket.fd, &tmp_exceptions))
537 {
538 save_player (pl->ob, 0);
539 if (!QUERY_FLAG (pl->ob, FLAG_REMOVED))
540 {
541 terminate_all_pets (pl->ob);
542 remove_ob (pl->ob);
543 }
544 leave (pl, 1);
545 final_free_player (pl);
546 }
547 else
548 {
549 HandleClient (&pl->socket, pl);
550 /* If the player has left the game, then the socket status
551 * will be set to this be the leave function. We don't
552 * need to call leave again, as it has already been called
553 * once.
554 */
555 if (pl->socket.status == Ns_Dead)
556 {
557 save_player (pl->ob, 0);
558 if (!QUERY_FLAG (pl->ob, FLAG_REMOVED))
559 {
560 terminate_all_pets (pl->ob);
561 remove_ob (pl->ob);
562 }
563 leave (pl, 1);
564 final_free_player (pl);
565 }
566 else
567 {
568
569 /* Update the players stats once per tick. More efficient than
570 * sending them whenever they change, and probably just as useful
571 */
572 esrv_update_stats (pl);
573 if (pl->last_weight != -1 && pl->last_weight != WEIGHT (pl->ob))
574 {
575 esrv_update_item (UPD_WEIGHT, pl->ob, pl->ob);
576 if (pl->last_weight != WEIGHT (pl->ob))
577 LOG (llevError, "esrv_update_item(UPD_WEIGHT) did not set player weight: is %lu, should be %lu\n",
578 (unsigned long) pl->last_weight, WEIGHT (pl->ob));
579 }
580 /* draw_client_map does sanity checking that map is
581 * valid, so don't do it here.
582 */
583 draw_client_map (pl->ob); 375 draw_client_map (pl->ob);
584 if (pl->socket.update_look) 376 if (s->update_look)
585 esrv_draw_look (pl->ob); 377 esrv_draw_look (pl->ob);
586 }
587 } 378 }
588 } 379 }
589} 380}
381

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines