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.5 by root, Sat Sep 9 21:48:29 2006 UTC vs.
Revision 1.14 by root, Thu Dec 14 04:30:33 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines