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.1 by elmex, Sun Aug 13 17:16:06 2006 UTC vs.
Revision 1.7 by root, Thu Sep 14 22:34:05 2006 UTC

1
2/*
3 * static char *rcsid_loop_c =
4 * "$Id: loop.C,v 1.1 2006/08/13 17:16:06 elmex 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.
39 */ 33 */
40 34
41 35
42#include <global.h> 36#include <global.h>
43#ifndef __CEXTRACT__ 37#ifndef __CEXTRACT__
44#include <sproto.h> 38# include <sproto.h>
45#include <sockproto.h> 39# include <sockproto.h>
46#endif 40#endif
47 41
48#ifndef WIN32 /* ---win32 exclude unix headers */ 42#ifndef WIN32 /* ---win32 exclude unix headers */
49#include <sys/types.h> 43# include <sys/types.h>
50#include <sys/time.h> 44# include <sys/time.h>
51#include <sys/socket.h> 45# include <sys/socket.h>
52#include <netinet/in.h> 46# include <netinet/in.h>
53#include <netdb.h> 47# include <netdb.h>
54#endif /* end win32 */ 48#endif /* end win32 */
55 49
56#ifdef HAVE_UNISTD_H 50#ifdef HAVE_UNISTD_H
57#include <unistd.h> 51# include <unistd.h>
58#endif 52#endif
59 53
60#ifdef HAVE_ARPA_INET_H 54#ifdef HAVE_ARPA_INET_H
61#include <arpa/inet.h> 55# include <arpa/inet.h>
62#endif 56#endif
63 57
64#include <loader.h> 58#include <loader.h>
65#include <newserver.h> 59#include <newserver.h>
66 60
75 * before player joins, and those happen after the player has joined. 69 * before player joins, and those happen after the player has joined.
76 * As such, we have function types that might be called, so 70 * As such, we have function types that might be called, so
77 * we end up having 2 tables. 71 * we end up having 2 tables.
78 */ 72 */
79 73
80typedef void (*func_uint8_int_ns) (char*, int, NewSocket *); 74typedef void (*func_uint8_int_ns) (char *, int, NewSocket *);
81 75
82struct NsCmdMapping { 76struct NsCmdMapping
77{
83 const char *cmdname; 78 const char *cmdname;
84 func_uint8_int_ns cmdproc; 79 func_uint8_int_ns cmdproc;
85}; 80};
86 81
87typedef void (*func_uint8_int_pl)(char*, int, player *); 82typedef void (*func_uint8_int_pl) (char *, int, player *);
88struct PlCmdMapping { 83struct PlCmdMapping
84{
89 const char *cmdname; 85 const char *cmdname;
90 func_uint8_int_pl cmdproc; 86 func_uint8_int_pl cmdproc;
91 uint8 flag; 87 uint8 flag;
92}; 88};
93 89
94/** 90/**
95 * Dispatch table for the server. 91 * Dispatch table for the server.
96 * 92 *
103 * to cast it here instead of a bunch of times in the function itself. 99 * 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 100 * 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. 101 * command, 0 if they can issue it at any time.
106 */ 102 */
107static struct PlCmdMapping plcommands[] = { 103static struct PlCmdMapping plcommands[] = {
108 { "examine", ExamineCmd, 1}, 104 {"examine", ExamineCmd, 1},
109 { "apply", ApplyCmd, 1}, 105 {"apply", ApplyCmd, 1},
110 { "move", MoveCmd, 1}, 106 {"move", MoveCmd, 1},
111 { "reply", ReplyCmd, 0}, 107 {"reply", ReplyCmd, 0},
112 { "command", PlayerCmd, 1}, 108 {"command", PlayerCmd, 1},
113 { "ncom", (func_uint8_int_pl)NewPlayerCmd, 1}, 109 {"ncom", (func_uint8_int_pl) NewPlayerCmd, 1},
114 { "lookat", LookAt, 1}, 110 {"lookat", LookAt, 1},
115 { "lock", (func_uint8_int_pl)LockItem, 1}, 111 {"lock", (func_uint8_int_pl) LockItem, 1},
116 { "mark", (func_uint8_int_pl)MarkItem, 1}, 112 {"mark", (func_uint8_int_pl) MarkItem, 1},
117 { "mapredraw", MapRedrawCmd, 0}, /* Added: phil */ 113 {"mapredraw", MapRedrawCmd, 0}, /* Added: phil */
118 { "mapinfo", MapInfoCmd, 2}, /* CF+ */ 114 {"mapinfo", MapInfoCmd, 2}, /* CF+ */
119 { "ext", ExtCmd, 2}, /* CF+ */ 115 {"ext", ExtCmd, 2}, /* CF+ */
120 { NULL, NULL, 0} /* terminator */ 116 {NULL, NULL, 0} /* terminator */
121}; 117};
122 118
123/** Face-related commands */ 119/** Face-related commands */
124static struct NsCmdMapping nscommands[] = { 120static struct NsCmdMapping nscommands[] = {
125 { "addme", AddMeCmd }, 121 {"addme", AddMeCmd},
126 { "askface", SendFaceCmd}, /* Added: phil */ 122 {"askface", SendFaceCmd}, /* Added: phil */
127 { "requestinfo", RequestInfo}, 123 {"requestinfo", RequestInfo},
128 { "setfacemode", SetFaceMode}, 124 {"setfacemode", SetFaceMode},
129 { "setsound", SetSound}, 125 {"setsound", SetSound},
130 { "setup", SetUp}, 126 {"setup", SetUp},
131 { "version", VersionCmd }, 127 {"version", VersionCmd},
132 { "toggleextendedinfos", ToggleExtendedInfos}, /*Added: tchize*/ 128 {"toggleextendedinfos", ToggleExtendedInfos}, /*Added: tchize */
133 { "toggleextendedtext", ToggleExtendedText}, /*Added: tchize*/ 129 {"toggleextendedtext", ToggleExtendedText}, /*Added: tchize */
134 { "asksmooth", AskSmooth}, /*Added: tchize (smoothing technologies)*/ 130 {"asksmooth", AskSmooth}, /*Added: tchize (smoothing technologies) */
135 { NULL, NULL} /* terminator (I, II & III)*/ 131 {NULL, NULL} /* terminator (I, II & III) */
136}; 132};
137 133
138/** 134/**
139 * RequestInfo is sort of a meta command. There is some specific 135 * RequestInfo is sort of a meta command. There is some specific
140 * request of information, but we call other functions to provide 136 * request of information, but we call other functions to provide
141 * that information. 137 * that information.
142 */ 138 */
139void
143void RequestInfo(char *buf, int len, NewSocket *ns) 140RequestInfo (char *buf, int len, NewSocket * ns)
144{ 141{
145 char *params=NULL, *cp; 142 char *params = NULL, *cp;
143
146 /* No match */ 144 /* No match */
147 char bigbuf[MAX_BUF]; 145 char bigbuf[MAX_BUF];
148 int slen; 146 int slen;
149 147
150 /* Set up replyinfo before we modify any of the buffers - this is used 148 /* Set up replyinfo before we modify any of the buffers - this is used
151 * if we don't find a match. 149 * if we don't find a match.
152 */ 150 */
153 strcpy(bigbuf,"replyinfo "); 151 strcpy (bigbuf, "replyinfo ");
154 slen = strlen(bigbuf); 152 slen = strlen (bigbuf);
155 safe_strcat(bigbuf, buf, &slen, MAX_BUF); 153 safe_strcat (bigbuf, buf, &slen, MAX_BUF);
156 154
157 /* find the first space, make it null, and update the 155 /* find the first space, make it null, and update the
158 * params pointer. 156 * params pointer.
159 */ 157 */
160 for (cp = buf; *cp != '\0'; cp++) 158 for (cp = buf; *cp != '\0'; cp++)
161 if (*cp==' ') { 159 if (*cp == ' ')
160 {
162 *cp = '\0'; 161 *cp = '\0';
163 params = cp + 1; 162 params = cp + 1;
164 break; 163 break;
165 } 164 }
166 if (!strcmp(buf, "image_info")) send_image_info(ns, params); 165 if (!strcmp (buf, "image_info"))
167 else if (!strcmp(buf,"image_sums")) send_image_sums(ns, params); 166 send_image_info (ns, params);
168 else if (!strcmp(buf,"skill_info")) send_skill_info(ns, params); 167 else if (!strcmp (buf, "image_sums"))
169 else if (!strcmp(buf,"spell_paths")) send_spell_paths(ns, params); 168 send_image_sums (ns, params);
169 else if (!strcmp (buf, "skill_info"))
170 send_skill_info (ns, params);
171 else if (!strcmp (buf, "spell_paths"))
172 send_spell_paths (ns, params);
173 else
170 else Write_String_To_Socket(ns, bigbuf, len); 174 Write_String_To_Socket (ns, bigbuf, len);
171} 175}
172
173/**
174 * Handles old socket format.
175 */
176void Handle_Oldsocket(NewSocket *ns)
177{
178 int stat,i;
179 CommFunc command;
180 char buf[MAX_BUF],*cp;
181 object ob;
182 player pl;
183
184 /* This is not the most efficient block, but keeps the code simpler -
185 * we basically read a byte at a time until we get a newline, error,
186 * or no more characters to read.
187 */
188 do {
189 /* hack to disable old socket mode without creating too many conflicts */
190 if (1 || ns->inbuf.len >= MAXSOCKBUF-1) {
191 ns->status = Ns_Dead;
192 LOG(llevDebug, "Old input socket sent too much data without newline\n");
193 return;
194 }
195#ifdef WIN32 /* ***win32: change oldsocket read() to recv() */
196 stat = recv(ns->fd, ns->inbuf.buf + ns->inbuf.len, 1,0);
197
198 if (stat==-1 && WSAGetLastError() !=WSAEWOULDBLOCK) {
199#else
200 do {
201 stat = read(ns->fd, ns->inbuf.buf + ns->inbuf.len, 1);
202 } while ((stat<0) && (errno == EINTR));
203
204 if (stat<0 && errno != EAGAIN && errno !=EWOULDBLOCK) {
205#endif
206 LOG(llevError, "Cannot read from socket: %s\n", strerror_local(errno));
207 ns->status = Ns_Dead;
208 return;
209 }
210 if (stat == 0) return;
211 } while (ns->inbuf.buf[ns->inbuf.len++]!='\n');
212
213 ns->inbuf.buf[ns->inbuf.len]=0;
214
215 cp = strchr((const char*)ns->inbuf.buf, ' ');
216 if (cp) {
217 /* Replace the space with a null, skip any more spaces */
218 *cp++=0;
219 while (isspace(*cp)) cp++;
220 }
221
222 /* Strip off all spaces and control characters from end of line */
223 for (i=ns->inbuf.len-1; i>=0; i--) {
224 if (ns->inbuf.buf[i]<=32) ns->inbuf.buf[i]=0;
225 else break;
226 }
227 ns->inbuf.len=0; /* reset for next read */
228
229 /* If just a return, don't do anything */
230 if (ns->inbuf.buf[0] == 0) return;
231 if (!strcasecmp((const char*)ns->inbuf.buf,"quit")) {
232 ns->status = Ns_Dead;
233 return;
234 }
235 if (!strcasecmp((const char*)ns->inbuf.buf, "listen")) {
236 if (cp) {
237 char *buf="Socket switched to listen mode\n";
238
239 free(ns->comment);
240 ns->comment = strdup_local(cp);
241 ns->old_mode = Old_Listen;
242 cs_write_string(ns, buf, strlen(buf));
243 } else {
244 char *buf="Need to supply a comment/url to listen\n";
245 cs_write_string(ns, buf, strlen(buf));
246 }
247 return;
248 }
249 if (!strcasecmp((const char*)ns->inbuf.buf, "name")) {
250 char *cp1=NULL;
251 if (cp) cp1= strchr(cp, ' ');
252 if (cp1) {
253 *cp1++ = 0;
254 while (isspace(*cp1)) cp1++;
255 }
256 if (!cp || !cp1) {
257 char *buf="Need to provide a name/password to name\n";
258 cs_write_string(ns, buf, strlen(buf));
259 return;
260 }
261
262 if (verify_player(cp, cp1)==0) {
263 char *buf="Welcome back\n";
264 free(ns->comment);
265 ns->comment = strdup_local(cp);
266 ns->old_mode = Old_Player;
267 cs_write_string(ns, buf, strlen(buf));
268 }
269 else if (verify_player(cp, cp1)==2) {
270 ns->password_fails++;
271 if (ns->password_fails >= MAX_PASSWORD_FAILURES) {
272 char *buf="You failed to log in too many times, you will now be kicked.\n";
273 LOG(llevInfo, "A player connecting from %s in oldsocketmode has been dropped for password failure\n",
274 ns->host);
275 cs_write_string(ns, buf, strlen(buf));
276 ns->status = Ns_Dead;
277 }
278 else {
279 char *buf="Could not login you in. Check your name and password.\n";
280 cs_write_string(ns, buf, strlen(buf));
281 }
282 }
283 else {
284 char *buf="Could not login you in. Check your name and password.\n";
285 cs_write_string(ns, buf, strlen(buf));
286 }
287 return;
288 }
289
290 command = find_oldsocket_command((char*)ns->inbuf.buf);
291 if (!command && ns->old_mode==Old_Player) {
292 command = find_oldsocket_command2((char*)ns->inbuf.buf);
293 }
294 if (!command) {
295 snprintf(buf, sizeof(buf), "Could not find command: %s\n", ns->inbuf.buf);
296 cs_write_string(ns, buf, strlen(buf));
297 return;
298 }
299
300 /* This is a bit of a hack, but works. Basically, we make some
301 * fake object and player pointers and give at it.
302 * This works as long as the functions we are calling don't need
303 * to do anything to the object structure (ie, they are only
304 * outputting information and not actually updating anything much.)
305 */
306 ob.contr = &pl;
307 pl.ob = &ob;
308 ob.type = PLAYER;
309 pl.listening = 10;
310 pl.socket = *ns;
311 pl.outputs_count = 1;
312 ob.name = ns->comment;
313
314 command(&ob, cp);
315}
316
317 176
318/** 177/**
319 * Handle client input. 178 * Handle client input.
320 * 179 *
321 * HandleClient is actually not named really well - we only get here once 180 * HandleClient is actually not named really well - we only get here once
323 * sock is the output socket information. pl is the player associated 182 * sock is the output socket information. pl is the player associated
324 * with this socket, null if no player (one of the init_sockets for just 183 * with this socket, null if no player (one of the init_sockets for just
325 * starting a connection) 184 * starting a connection)
326 */ 185 */
327 186
187void
328void HandleClient(NewSocket *ns, player *pl) 188HandleClient (NewSocket * ns, player *pl)
329{ 189{
330 int len=0,i,cnt; 190 int len = 0, i, cnt;
331 char *data; 191 char *data;
332 192
333 /* Loop through this - maybe we have several complete packets here. */ 193 /* Loop through this - maybe we have several complete packets here. */
334 // limit to a few commands only, though, as to not monopolise the server 194 // limit to a few commands only, though, as to not monopolise the server
335 for (cnt = 16; cnt--; ) { 195 for (cnt = 16; cnt--;)
196 {
336 /* If it is a player, and they don't have any speed left, we 197 /* If it is a player, and they don't have any speed left, we
337 * return, and will read in the data when they do have time. 198 * return, and will read in the data when they do have time.
338 */ 199 */
339 if (pl && pl->state==ST_PLAYING && pl->ob != NULL && pl->ob->speed_left < 0) { 200 if (pl && pl->state == ST_PLAYING && pl->ob != NULL && pl->ob->speed_left < 0)
201 {
340 return; 202 return;
341 } 203 }
342 204
343 if (ns->status == Ns_Old) {
344 Handle_Oldsocket(ns);
345 return;
346 }
347 i=SockList_ReadPacket(ns->fd, &ns->inbuf, MAXSOCKBUF-1); 205 i = SockList_ReadPacket (ns->fd, &ns->inbuf, MAXSOCKBUF - 1);
348 /* Special hack - let the user switch to old mode if in the Ns_Add
349 * phase. Don't demand they add in the special length bytes
350 */
351 if (ns->status == Ns_Add) {
352 if (!strncasecmp((const char*)ns->inbuf.buf,"oldsocketmode", 13)) {
353 ns->status = Ns_Old;
354 ns->inbuf.len=0;
355 cs_write_string(ns, "Switched to old socket mode\n", 28);
356 LOG(llevDebug,"Switched socket to old socket mode\n");
357 return;
358 }
359 }
360 206
361 if (i<0) { 207 if (i < 0)
208 {
362#ifdef ESRV_DEBUG 209#ifdef ESRV_DEBUG
363 LOG(llevDebug,"HandleClient: Read error on connection player %s\n", (pl?pl->ob->name:"None")); 210 LOG (llevDebug, "HandleClient: Read error on connection player %s\n", (pl ? pl->ob->name : "None"));
364#endif 211#endif
365 /* Caller will take care of cleaning this up */ 212 /* Caller will take care of cleaning this up */
366 ns->status =Ns_Dead; 213 ns->status = Ns_Dead;
367 return; 214 return;
368 } 215 }
369 /* Still dont have a full packet */ 216 /* Still dont have a full packet */
370 if (i==0) return; 217 if (i == 0)
218 return;
371 219
372// //D//TODO//temporarily log long commands 220// //D//TODO//temporarily log long commands
373// if (ns->inbuf.len >= 40 && pl && pl->ob) 221// if (ns->inbuf.len >= 40 && pl && pl->ob)
374// LOG (llevDebug, "HandleClient: long comamnd from <%s,%s> %d<%s>\n", pl->ob->name, ns->host, ns->inbuf.len, ns->inbuf.buf + 2); 222// LOG (llevDebug, "HandleClient: long comamnd from <%s,%s> %d<%s>\n", pl->ob->name, ns->host, ns->inbuf.len, ns->inbuf.buf + 2);
375 223
376 /* First, break out beginning word. There are at least 224 /* First, break out beginning word. There are at least
377 * a few commands that do not have any paremeters. If 225 * a few commands that do not have any paremeters. If
378 * we get such a command, don't worry about trying 226 * we get such a command, don't worry about trying
379 * to break it up. 227 * to break it up.
380 */ 228 */
381 data = (char *)strchr((char*)ns->inbuf.buf +2, ' '); 229 data = (char *) strchr ((char *) ns->inbuf.buf + 2, ' ');
382 if (data) { 230 if (data)
231 {
383 *data='\0'; 232 *data = '\0';
384 data++; 233 data++;
385 len = ns->inbuf.len - (data - (char*)ns->inbuf.buf); 234 len = ns->inbuf.len - (data - (char *) ns->inbuf.buf);
386 } 235 }
387 else len=0; 236 else
237 len = 0;
388 238
389 ns->inbuf.buf[ns->inbuf.len]='\0'; /* Terminate buffer - useful for string data */ 239 ns->inbuf.buf[ns->inbuf.len] = '\0'; /* Terminate buffer - useful for string data */
390 for (i=0; nscommands[i].cmdname !=NULL; i++) { 240 for (i = 0; nscommands[i].cmdname != NULL; i++)
241 {
391 if (strcmp((char*)ns->inbuf.buf+2,nscommands[i].cmdname)==0) { 242 if (strcmp ((char *) ns->inbuf.buf + 2, nscommands[i].cmdname) == 0)
243 {
392 nscommands[i].cmdproc((char*)data,len,ns); 244 nscommands[i].cmdproc ((char *) data, len, ns);
393 ns->inbuf.len=0; 245 ns->inbuf.len = 0;
394 return;//D// not doing this causes random memory corruption 246 return; //D// not doing this causes random memory corruption
395 goto next_packet; 247 goto next_packet;
396 } 248 }
397 } 249 }
398 /* Player must be in the playing state or the flag on the 250 /* Player must be in the playing state or the flag on the
399 * the command must be zero for the user to use the command - 251 * the command must be zero for the user to use the command -
400 * otherwise, a player cam save, be in the play_again state, and 252 * otherwise, a player cam save, be in the play_again state, and
401 * the map they were on gets swapped out, yet things that try to look 253 * the map they were on gets swapped out, yet things that try to look
402 * at the map causes a crash. If the command is valid, but 254 * at the map causes a crash. If the command is valid, but
403 * one they can't use, we still swallow it up. 255 * one they can't use, we still swallow it up.
404 */ 256 */
257 if (pl)
405 if (pl) for (i=0; plcommands[i].cmdname !=NULL; i++) { 258 for (i = 0; plcommands[i].cmdname != NULL; i++)
259 {
406 if (strcmp((char*)ns->inbuf.buf+2,plcommands[i].cmdname)==0) { 260 if (strcmp ((char *) ns->inbuf.buf + 2, plcommands[i].cmdname) == 0)
261 {
407 if (pl->state == ST_PLAYING || !(plcommands[i].flag & 1)) 262 if (pl->state == ST_PLAYING || !(plcommands[i].flag & 1))
408 plcommands[i].cmdproc((char*)data,len,pl); 263 plcommands[i].cmdproc ((char *) data, len, pl);
409 ns->inbuf.len=0; 264 ns->inbuf.len = 0;
410 //D// not doing this causes random memory corruption 265 //D// not doing this causes random memory corruption
411 if (plcommands[i].flag & 2) 266 if (plcommands[i].flag & 2)
412 goto next_packet; 267 goto next_packet;
413 return; 268 return;
414 } 269 }
415 } 270 }
416 /* If we get here, we didn't find a valid command. Logging 271 /* If we get here, we didn't find a valid command. Logging
417 * this might be questionable, because a broken client/malicious 272 * this might be questionable, because a broken client/malicious
418 * user could certainly send a whole bunch of invalid commands. 273 * user could certainly send a whole bunch of invalid commands.
419 */ 274 */
420 LOG(llevDebug,"Bad command from client (%s)\n",ns->inbuf.buf+2); 275 LOG (llevDebug, "Bad command from client (%s)\n", ns->inbuf.buf + 2);
421 next_packet: 276 next_packet:
422 ; 277 ;
423 } 278 }
424} 279}
425 280
426 281
427/***************************************************************************** 282/*****************************************************************************
430 * sending. 285 * sending.
431 * 286 *
432 ******************************************************************************/ 287 ******************************************************************************/
433 288
434#ifdef WATCHDOG 289#ifdef WATCHDOG
290
435/** 291/**
436 * Tell watchdog that we are still alive 292 * Tell watchdog that we are still alive
437 * 293 *
438 * I put the function here since we should hopefully already be getting 294 * I put the function here since we should hopefully already be getting
439 * all the needed include files for socket support 295 * all the needed include files for socket support
440 */ 296 */
441 297
298void
442void watchdog(void) 299watchdog (void)
443{ 300{
444 static int fd=-1; 301 static int fd = -1;
445 static struct sockaddr_in insock; 302 static struct sockaddr_in insock;
446 303
447 if (fd==-1) 304 if (fd == -1)
448 { 305 {
449 struct protoent *protoent; 306 struct protoent *protoent;
450 307
451 if ((protoent=getprotobyname("udp"))==NULL || 308 if ((protoent = getprotobyname ("udp")) == NULL || (fd = socket (PF_INET, SOCK_DGRAM, protoent->p_proto)) == -1)
452 (fd=socket(PF_INET, SOCK_DGRAM, protoent->p_proto))==-1)
453 { 309 {
454 return; 310 return;
455 } 311 }
456 insock.sin_family=AF_INET; 312 insock.sin_family = AF_INET;
457 insock.sin_port=htons((unsigned short)13325); 313 insock.sin_port = htons ((unsigned short) 13325);
458 insock.sin_addr.s_addr=inet_addr("127.0.0.1"); 314 insock.sin_addr.s_addr = inet_addr ("127.0.0.1");
459 } 315 }
460 sendto(fd,(void *)&fd,1,0,(struct sockaddr *)&insock,sizeof(insock)); 316 sendto (fd, (void *) &fd, 1, 0, (struct sockaddr *) &insock, sizeof (insock));
461} 317}
462#endif 318#endif
463 319
464extern unsigned long todtick; 320void
465
466/** Waits for new connection */
467static void block_until_new_connection(void)
468{
469
470 struct timeval Timeout;
471 fd_set readfs;
472 int cycles;
473
474 LOG(llevInfo, "Waiting for connections...\n");
475
476 cycles=1;
477 do {
478 /* Every minutes is a bit often for updates - especially if nothing is going
479 * on. This slows it down to every 6 minutes.
480 */
481 cycles++;
482 if (cycles%2 == 0)
483 tick_the_clock();
484
485 FD_ZERO(&readfs);
486 FD_SET((uint32)init_sockets[0].fd, &readfs);
487
488 /* If fastclock is set, we need to seriously slow down the updates
489 * to the metaserver as well as watchdog. Do same for flush_old_maps() -
490 * that is time sensitive, so there is no good reason to call it 2000 times
491 * a second.
492 */
493 if (settings.fastclock > 0) {
494#ifdef WATCHDOG
495 if (cycles % 120000 == 0) {
496 watchdog();
497 flush_old_maps();
498 }
499#endif
500 if (cycles == 720000) {
501 metaserver_update();
502 cycles=1;
503 }
504 Timeout.tv_sec=0;
505 Timeout.tv_usec=50;
506 } else {
507 Timeout.tv_sec=60;
508 Timeout.tv_usec=0;
509 if (cycles == 7) {
510 metaserver_update();
511 cycles=1;
512 }
513 flush_old_maps();
514 }
515 }
516 while (select(socket_info.max_filedescriptor, &readfs, NULL, NULL, &Timeout)==0);
517
518 reset_sleep(); /* Or the game would go too fast */
519}
520
521void flush_sockets(void) 321flush_sockets (void)
522{ 322{
523 player *pl; 323 player *pl;
524 324
525 for (pl = first_player; pl != NULL; pl = pl->next) 325 for (pl = first_player; pl != NULL; pl = pl->next)
526 if (pl->socket.status != Ns_Dead) 326 if (pl->socket.status != Ns_Dead)
532 * 332 *
533 * A bit of this code is grabbed out of socket.c 333 * A bit of this code is grabbed out of socket.c
534 * There are 2 lists we need to look through - init_sockets is a list 334 * There are 2 lists we need to look through - init_sockets is a list
535 * 335 *
536 */ 336 */
337void
537void doeric_server(void) 338doeric_server (void)
538{ 339{
539 int i, pollret; 340 int i, pollret;
540 fd_set tmp_read, tmp_exceptions, tmp_write; 341 fd_set tmp_read, tmp_exceptions, tmp_write;
541 struct sockaddr_in addr; 342 struct sockaddr_in addr;
542 socklen_t addrlen=sizeof(struct sockaddr); 343 socklen_t addrlen = sizeof (struct sockaddr);
543 player *pl, *next; 344 player *pl, *next;
544 345
545#ifdef CS_LOGSTATS 346#ifdef CS_LOGSTATS
546 if ((time(NULL)-cst_lst.time_start)>=CS_LOGTIME) 347 if ((time (NULL) - cst_lst.time_start) >= CS_LOGTIME)
547 write_cs_stats(); 348 write_cs_stats ();
548#endif 349#endif
549 350
550 FD_ZERO(&tmp_read); 351 FD_ZERO (&tmp_read);
551 FD_ZERO(&tmp_write); 352 FD_ZERO (&tmp_write);
552 FD_ZERO(&tmp_exceptions); 353 FD_ZERO (&tmp_exceptions);
553 354
554 for(i=0;i<socket_info.allocated_sockets;i++) { 355 for (i = 0; i < socket_info.allocated_sockets; i++)
356 {
555 if (init_sockets[i].status == Ns_Dead) { 357 if (init_sockets[i].status == Ns_Dead)
358 {
556 free_newsocket(&init_sockets[i]); 359 free_newsocket (&init_sockets[i]);
557 init_sockets[i].status = Ns_Avail; 360 init_sockets[i].status = Ns_Avail;
558 socket_info.nconns--; 361 socket_info.nconns--;
362 }
559 } else if (init_sockets[i].status != Ns_Avail){ 363 else if (init_sockets[i].status != Ns_Avail)
364 {
560 FD_SET((uint32)init_sockets[i].fd, &tmp_read); 365 FD_SET ((uint32) init_sockets[i].fd, &tmp_read);
561 FD_SET((uint32)init_sockets[i].fd, &tmp_write); 366 FD_SET ((uint32) init_sockets[i].fd, &tmp_write);
562 FD_SET((uint32)init_sockets[i].fd, &tmp_exceptions); 367 FD_SET ((uint32) init_sockets[i].fd, &tmp_exceptions);
563 } 368 }
564 } 369 }
565 370
566 /* Go through the players. Let the loop set the next pl value, 371 /* Go through the players. Let the loop set the next pl value,
567 * since we may remove some 372 * since we may remove some
568 */ 373 */
569 for (pl=first_player; pl!=NULL; ) { 374 for (pl = first_player; pl != NULL;)
375 {
570 if (pl->socket.status == Ns_Dead) { 376 if (pl->socket.status == Ns_Dead)
377 {
571 player *npl=pl->next; 378 player *npl = pl->next;
572 379
573 save_player(pl->ob, 0); 380 save_player (pl->ob, 0);
574 if(!QUERY_FLAG(pl->ob,FLAG_REMOVED)) { 381 if (!QUERY_FLAG (pl->ob, FLAG_REMOVED))
382 {
575 terminate_all_pets(pl->ob); 383 terminate_all_pets (pl->ob);
576 remove_ob(pl->ob); 384 remove_ob (pl->ob);
577 } 385 }
578 leave(pl,1); 386 leave (pl, 1);
579 final_free_player(pl); 387 final_free_player (pl);
580 pl=npl; 388 pl = npl;
581 } 389 }
582 else { 390 else
391 {
583 FD_SET((uint32)pl->socket.fd, &tmp_read); 392 FD_SET ((uint32) pl->socket.fd, &tmp_read);
584 FD_SET((uint32)pl->socket.fd, &tmp_write); 393 FD_SET ((uint32) pl->socket.fd, &tmp_write);
585 FD_SET((uint32)pl->socket.fd, &tmp_exceptions); 394 FD_SET ((uint32) pl->socket.fd, &tmp_exceptions);
586 pl=pl->next; 395 pl = pl->next;
587 } 396 }
397 }
398
399 /* Reset timeout each time, since some OS's will change the values on
400 * the return from select.
401 */
402 socket_info.timeout.tv_sec = 0;
403 socket_info.timeout.tv_usec = 0;
404
405 pollret = select (socket_info.max_filedescriptor, &tmp_read, &tmp_write, &tmp_exceptions, &socket_info.timeout);
406
407 if (pollret == -1)
408 {
409 LOG (llevError, "select failed: %s\n", strerror (errno));
410 return;
411 }
412
413 /* We need to do some of the processing below regardless */
414
415/* if (!pollret) return;*/
416
417 /* Following adds a new connection */
418 if (pollret && FD_ISSET (init_sockets[0].fd, &tmp_read))
419 {
420 int newsocknum = 0;
421
422#ifdef ESRV_DEBUG
423 LOG (llevDebug, "doeric_server: New Connection\n");
424#endif
425 /* If this is the case, all sockets currently in used */
426 if (socket_info.allocated_sockets <= socket_info.nconns)
427 {
428 init_sockets = (NewSocket *) realloc (init_sockets, sizeof (NewSocket) * (socket_info.nconns + 1));
429 if (!init_sockets)
430 fatal (OUT_OF_MEMORY);
431 newsocknum = socket_info.allocated_sockets;
432 socket_info.allocated_sockets++;
433 init_sockets[newsocknum].faces_sent_len = nrofpixmaps;
434 init_sockets[newsocknum].faces_sent = (uint8 *) malloc (nrofpixmaps * sizeof (*init_sockets[newsocknum].faces_sent));
435 if (!init_sockets[newsocknum].faces_sent)
436 fatal (OUT_OF_MEMORY);
437 init_sockets[newsocknum].status = Ns_Avail;
438 }
439 else
440 {
441 int j;
442
443 for (j = 1; j < socket_info.allocated_sockets; j++)
444 if (init_sockets[j].status == Ns_Avail)
445 {
446 newsocknum = j;
447 break;
448 }
449 }
450 init_sockets[newsocknum].fd = accept (init_sockets[0].fd, (struct sockaddr *) &addr, &addrlen);
451 if (init_sockets[newsocknum].fd == -1)
452 {
453 LOG (llevError, "accept failed: %s\n", strerror (errno));
454 }
455 else
456 {
457 char buf[MAX_BUF];
458 long ip;
459 NewSocket *ns;
460
461 ns = &init_sockets[newsocknum];
462
463 ip = ntohl (addr.sin_addr.s_addr);
464 sprintf (buf, "%ld.%ld.%ld.%ld", (ip >> 24) & 255, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
465
466 if (checkbanned (NULL, buf))
467 {
468 LOG (llevInfo, "Banned host tried to connect: [%s]\n", buf);
469 close (init_sockets[newsocknum].fd);
470 init_sockets[newsocknum].fd = -1;
471 }
472 else
473 {
474 InitConnection (ns, buf);
475 socket_info.nconns++;
476 }
477 }
478 }
479
480 /* Check for any exceptions/input on the sockets */
481 if (pollret)
482 for (i = 1; i < socket_info.allocated_sockets; i++)
483 {
484 if (init_sockets[i].status == Ns_Avail)
485 continue;
486 if (FD_ISSET (init_sockets[i].fd, &tmp_exceptions))
487 {
488 free_newsocket (&init_sockets[i]);
489 init_sockets[i].status = Ns_Avail;
490 socket_info.nconns--;
491 continue;
492 }
493 if (FD_ISSET (init_sockets[i].fd, &tmp_read))
494 {
495 HandleClient (&init_sockets[i], NULL);
496 }
497 if (FD_ISSET (init_sockets[i].fd, &tmp_write))
498 {
499 init_sockets[i].can_write = 1;
500 }
588 } 501 }
589 502
503 /* This does roughly the same thing, but for the players now */
504 for (pl = first_player; pl != NULL; pl = next)
505 {
506
507 next = pl->next;
508 if (pl->socket.status == Ns_Dead)
509 continue;
510
511 if (FD_ISSET (pl->socket.fd, &tmp_write))
512 {
513 if (!pl->socket.can_write)
514 {
590#if 0 515#if 0
591 // the event system and plugins require the server ti run at all times.
592 // since its primarily cf.schmorp.de we are interested in, and
593 // that is supposed to run all the time anyway, its globally disabled
594 // until we can use Event.
595 if (socket_info.nconns==1 && first_player==NULL)
596 block_until_new_connection();
597#endif
598
599 /* Reset timeout each time, since some OS's will change the values on
600 * the return from select.
601 */
602 socket_info.timeout.tv_sec = 0;
603 socket_info.timeout.tv_usec = 0;
604
605 pollret= select(socket_info.max_filedescriptor, &tmp_read, &tmp_write,
606 &tmp_exceptions, &socket_info.timeout);
607
608 if (pollret==-1) {
609 LOG(llevError, "select failed: %s\n", strerror_local(errno));
610 return;
611 }
612
613 /* We need to do some of the processing below regardless */
614/* if (!pollret) return;*/
615
616 /* Following adds a new connection */
617 if (pollret && FD_ISSET(init_sockets[0].fd, &tmp_read)) {
618 int newsocknum=0;
619
620#ifdef ESRV_DEBUG
621 LOG(llevDebug,"doeric_server: New Connection\n");
622#endif
623 /* If this is the case, all sockets currently in used */
624 if (socket_info.allocated_sockets <= socket_info.nconns) {
625 init_sockets = (NewSocket *) realloc(init_sockets,sizeof(NewSocket)*(socket_info.nconns+1));
626 if (!init_sockets) fatal(OUT_OF_MEMORY);
627 newsocknum = socket_info.allocated_sockets;
628 socket_info.allocated_sockets++;
629 init_sockets[newsocknum].faces_sent_len = nrofpixmaps;
630 init_sockets[newsocknum].faces_sent = (uint8*) malloc(nrofpixmaps*sizeof(*init_sockets[newsocknum].faces_sent));
631 if (!init_sockets[newsocknum].faces_sent) fatal(OUT_OF_MEMORY);
632 init_sockets[newsocknum].status = Ns_Avail;
633 }
634 else {
635 int j;
636
637 for (j=1; j<socket_info.allocated_sockets; j++)
638 if (init_sockets[j].status == Ns_Avail) {
639 newsocknum=j;
640 break;
641 }
642 }
643 init_sockets[newsocknum].fd=accept(init_sockets[0].fd, (struct sockaddr *)&addr, &addrlen);
644 if (init_sockets[newsocknum].fd==-1) {
645 LOG(llevError, "accept failed: %s\n", strerror_local(errno));
646 }
647 else {
648 char buf[MAX_BUF];
649 long ip;
650 NewSocket *ns;
651
652 ns = &init_sockets[newsocknum];
653
654 ip = ntohl(addr.sin_addr.s_addr);
655 sprintf(buf, "%ld.%ld.%ld.%ld", (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, ip&255);
656
657 if (checkbanned(NULL, buf)) {
658 LOG(llevInfo, "Banned host tried to connect: [%s]\n", buf);
659 close(init_sockets[newsocknum].fd);
660 init_sockets[newsocknum].fd = -1;
661 }
662 else {
663 InitConnection(ns, buf);
664 socket_info.nconns++;
665 }
666 }
667 }
668
669 /* Check for any exceptions/input on the sockets */
670 if (pollret) for(i=1;i<socket_info.allocated_sockets;i++) {
671 if (init_sockets[i].status == Ns_Avail) continue;
672 if (FD_ISSET(init_sockets[i].fd,&tmp_exceptions)) {
673 free_newsocket(&init_sockets[i]);
674 init_sockets[i].status = Ns_Avail;
675 socket_info.nconns--;
676 continue;
677 }
678 if (FD_ISSET(init_sockets[i].fd, &tmp_read)) {
679 HandleClient(&init_sockets[i], NULL);
680 }
681 if (FD_ISSET(init_sockets[i].fd, &tmp_write)) {
682 init_sockets[i].can_write=1;
683 }
684 }
685
686 /* This does roughly the same thing, but for the players now */
687 for (pl=first_player; pl!=NULL; pl=next) {
688
689 next=pl->next;
690 if (pl->socket.status==Ns_Dead) continue;
691
692 if (FD_ISSET(pl->socket.fd,&tmp_write)) {
693 if (!pl->socket.can_write) {
694#if 0
695 LOG(llevDebug,"Player %s socket now write enabled\n", pl->ob->name); 516 LOG (llevDebug, "Player %s socket now write enabled\n", pl->ob->name);
696#endif 517#endif
697 pl->socket.can_write=1; 518 pl->socket.can_write = 1;
698 write_socket_buffer(&pl->socket); 519 write_socket_buffer (&pl->socket);
699 } 520 }
700 /* if we get an error on the write_socket buffer, no reason to 521 /* if we get an error on the write_socket buffer, no reason to
701 * continue on this socket. 522 * continue on this socket.
702 */ 523 */
703 if (pl->socket.status==Ns_Dead) continue; 524 if (pl->socket.status == Ns_Dead)
704 } 525 continue;
526 }
527 else
705 else pl->socket.can_write=0; 528 pl->socket.can_write = 0;
706 529
707 if (FD_ISSET(pl->socket.fd,&tmp_exceptions)) { 530 if (FD_ISSET (pl->socket.fd, &tmp_exceptions))
531 {
708 save_player(pl->ob, 0); 532 save_player (pl->ob, 0);
709 if(!QUERY_FLAG(pl->ob,FLAG_REMOVED)) { 533 if (!QUERY_FLAG (pl->ob, FLAG_REMOVED))
534 {
710 terminate_all_pets(pl->ob); 535 terminate_all_pets (pl->ob);
711 remove_ob(pl->ob); 536 remove_ob (pl->ob);
712 } 537 }
713 leave(pl,1); 538 leave (pl, 1);
714 final_free_player(pl); 539 final_free_player (pl);
715 } 540 }
716 else { 541 else
542 {
717 HandleClient(&pl->socket, pl); 543 HandleClient (&pl->socket, pl);
718 /* If the player has left the game, then the socket status 544 /* If the player has left the game, then the socket status
719 * will be set to this be the leave function. We don't 545 * will be set to this be the leave function. We don't
720 * need to call leave again, as it has already been called 546 * need to call leave again, as it has already been called
721 * once. 547 * once.
722 */ 548 */
723 if (pl->socket.status==Ns_Dead) { 549 if (pl->socket.status == Ns_Dead)
724 save_player(pl->ob, 0); 550 {
551 save_player (pl->ob, 0);
725 if(!QUERY_FLAG(pl->ob,FLAG_REMOVED)) { 552 if (!QUERY_FLAG (pl->ob, FLAG_REMOVED))
553 {
726 terminate_all_pets(pl->ob); 554 terminate_all_pets (pl->ob);
727 remove_ob(pl->ob); 555 remove_ob (pl->ob);
728 } 556 }
729 leave(pl,1); 557 leave (pl, 1);
730 final_free_player(pl); 558 final_free_player (pl);
731 } else { 559 }
560 else
561 {
732 562
733 /* Update the players stats once per tick. More efficient than 563 /* Update the players stats once per tick. More efficient than
734 * sending them whenever they change, and probably just as useful 564 * sending them whenever they change, and probably just as useful
735 */ 565 */
736 esrv_update_stats(pl); 566 esrv_update_stats (pl);
737 if (pl->last_weight != -1 && pl->last_weight != WEIGHT(pl->ob)) { 567 if (pl->last_weight != -1 && pl->last_weight != WEIGHT (pl->ob))
568 {
738 esrv_update_item(UPD_WEIGHT, pl->ob, pl->ob); 569 esrv_update_item (UPD_WEIGHT, pl->ob, pl->ob);
739 if(pl->last_weight != WEIGHT(pl->ob)) 570 if (pl->last_weight != WEIGHT (pl->ob))
740 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)); 571 LOG (llevError, "esrv_update_item(UPD_WEIGHT) did not set player weight: is %lu, should be %lu\n",
741 } 572 (unsigned long) pl->last_weight, WEIGHT (pl->ob));
573 }
742 /* draw_client_map does sanity checking that map is 574 /* draw_client_map does sanity checking that map is
743 * valid, so don't do it here. 575 * valid, so don't do it here.
744 */ 576 */
745 draw_client_map(pl->ob); 577 draw_client_map (pl->ob);
746 if (pl->socket.update_look) esrv_draw_look(pl->ob); 578 if (pl->socket.update_look)
747 } 579 esrv_draw_look (pl->ob);
748 } 580 }
581 }
749 } 582 }
750} 583}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines