Crossfire Server, Trunk  R20513
loop.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
25 #include "global.h"
26 
27 #include <arpa/inet.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 
35 #ifndef WIN32 /* ---win32 exclude unix headers */
36 #include <sys/types.h>
37 #include <sys/time.h>
38 #include <netinet/in.h>
39 #include <netdb.h>
40 #endif /* end win32 */
41 
42 #include "image.h"
43 #include "newserver.h"
44 #include "server.h"
45 #include "sockproto.h"
46 #include "sproto.h"
47 
48 /*****************************************************************************
49  * Start of command dispatch area.
50  * The commands here are protocol commands.
51  ****************************************************************************/
52 
53 /* Either keep this near the start or end of the file so it is
54  * at least reasonablye easy to find.
55  * There are really 2 commands - those which are sent/received
56  * before player joins, and those happen after the player has joined.
57  * As such, we have function types that might be called, so
58  * we end up having 2 tables.
59  */
60 
62 typedef void (*func_uint8_int_ns)(char *, int, socket_struct *);
63 
66  const char *cmdname;
68 };
69 
71 typedef void (*func_uint8_int_pl)(char *, int, player *);
74  const char *cmdname;
76  const uint8_t flag;
77 };
78 
94 static const struct player_cmd_mapping player_commands[] = {
95  { "examine", examine_cmd, 1 },
96  { "apply", apply_cmd, 1 },
97  { "move", move_cmd, 1 },
98  { "reply", reply_cmd, 0 },
99  { "ncom", (func_uint8_int_pl)new_player_cmd, 1 },
100  { "lookat", look_at_cmd, 1 },
101  { "lock", (func_uint8_int_pl)lock_item_cmd, 1 },
102  { "mark", (func_uint8_int_pl)mark_item_cmd, 1 },
103  { "inscribe", inscribe_scroll_cmd, 0 },
104  { NULL, NULL, 0 } /* terminator */
105 };
106 
108 static const struct client_cmd_mapping client_commands[] = {
109  { "addme", add_me_cmd },
110  { "askface", send_face_cmd }, /* Added: phil */
111  { "beat", NULL },
112  { "requestinfo", request_info_cmd },
113  { "setup", set_up_cmd },
114  { "version", version_cmd },
115  { "asksmooth", ask_smooth_cmd }, /*Added: tchize (smoothing technologies)*/
116  { "accountlogin", account_login_cmd },
117  { "accountnew", account_new_cmd },
118  { "accountaddplayer", account_add_player_cmd },
119  { "accountplay", account_play_cmd },
120  { "accountpw", account_password },
121  { "createplayer", create_player_cmd },
122  { NULL, NULL } /* terminator (I, II & III)*/
123 };
124 
133 void request_info_cmd(char *buf, int len, socket_struct *ns) {
134  char *params = NULL, *cp;
135  /* No match */
136  SockList sl;
137 
138  if (len <= 0 || !buf) {
139  LOG(llevDebug, "IP '%s' sent bogus request_info_cmd information\n", ns->host);
140  return;
141  }
142 
143  /* Set up replyinfo before we modify any of the buffers - this is used
144  * if we don't find a match.
145  */
146  SockList_Init(&sl);
147  SockList_AddString(&sl, "replyinfo ");
148  SockList_AddString(&sl, buf);
149 
150  /* find the first space, make it null, and update the
151  * params pointer.
152  */
153  for (cp = buf; *cp != '\0'; cp++)
154  if (*cp == ' ') {
155  *cp = '\0';
156  params = cp+1;
157  break;
158  }
159  if (!strcmp(buf, "image_info"))
160  send_image_info(ns);
161  else if (!strcmp(buf, "image_sums"))
162  send_image_sums(ns, params);
163  else if (!strcmp(buf, "skill_info"))
164  send_skill_info(ns, params);
165  else if (!strcmp(buf, "spell_paths"))
166  send_spell_paths(ns, params);
167  else if (!strcmp(buf, "exp_table"))
168  send_exp_table(ns, params);
169  else if (!strcmp(buf, "race_list"))
170  send_race_list(ns, params);
171  else if (!strcmp(buf, "race_info"))
172  send_race_info(ns, params);
173  else if (!strcmp(buf, "class_list"))
174  send_class_list(ns, params);
175  else if (!strcmp(buf, "class_info"))
176  send_class_info(ns, params);
177  else if (!strcmp(buf, "rules"))
178  send_file(ns, "rules");
179  else if (!strcmp(buf, "motd"))
180  send_file(ns, "motd");
181  else if (!strcmp(buf, "news"))
182  send_file(ns, "news");
183  else if (!strcmp(buf,"newcharinfo"))
184  send_new_char_info(ns);
185  else if (!strcmp(buf,"startingmap"))
186  send_map_info(ns);
187  else if (!strcmp(buf, "knowledge_info"))
189  else
190  Send_With_Handling(ns, &sl);
191  SockList_Term(&sl);
192 }
193 
194 static int
195 handle_cmd(socket_struct *ns, player *pl, char *cmd, char *data, int len) {
196  assert(cmd != NULL);
197  for (int i = 0; client_commands[i].cmdname != NULL; i++) {
198  if (strcmp(cmd, client_commands[i].cmdname) == 0) {
199  if (client_commands[i].cmdproc != NULL) {
200  client_commands[i].cmdproc(data, len, ns);
201  }
202  return 0;
203  }
204  }
205  /* Player must be in the playing state or the flag on the
206  * the command must be zero for the user to use the command -
207  * otherwise, a player cam save, be in the play_again state, and
208  * the map they were on getsswapped out, yet things that try to look
209  * at the map causes a crash. If the command is valid, but
210  * one they can't use, we still swallow it up.
211  */
212  if (pl) {
213  for (int i = 0; player_commands[i].cmdname != NULL; i++) {
214  if (strcmp(cmd, player_commands[i].cmdname) == 0) {
215  if (pl->state == ST_PLAYING || player_commands[i].flag == 0) {
216  player_commands[i].cmdproc(data, len, pl);
217  }
218  return 1;
219  }
220  }
221  }
222  LOG(llevDebug, "%s: invalid command '%s'\n", ns->host, cmd);
223  return 0;
224 }
225 
235  /* Loop through this - maybe we have several complete packets here. */
236  /* Command_count is used to limit the number of requests from
237  * clients that have not logged in - we do not want an unauthenticated
238  * connection to spew us with hundreds of requests. As such,
239  * this counter is only increased in the case of socket level commands.
240  * Note that this also has the effect of throttling down face and other
241  * socket commands from the client. As such, if we have a player attached,
242  * we will process more of these, as getting a fair number when entering
243  * a map may not be uncommon.
244  */
245  int command_count = 0;
246  while (command_count < 5 || (pl && command_count < 25)) {
247  if (pl && pl->state == ST_PLAYING && pl->ob != NULL && pl->ob->speed_left < 0) {
248  // Skip processing players with no turns left.
249  return;
250  }
251 
252  int status = SockList_ReadPacket(ns->fd, &ns->inbuf, sizeof(ns->inbuf.buf)-1);
253  if (status != 1) {
254  if (status < 0) {
255  ns->status = Ns_Dead;
256  }
257  return;
258  }
259 
260  /* Since we have a full packet, reset last tick time. */
261  ns->last_tick = 0;
262 
264  assert(ns->inbuf.len >= 2);
265  char *data;
266  char *cmd = strtok_r((char *)ns->inbuf.buf + 2, " ", &data);
267 
268  int got_player_cmd;
269  if (data != NULL) {
270  int rem = ns->inbuf.len - ((unsigned char *)data - ns->inbuf.buf);
271  got_player_cmd = handle_cmd(ns, pl, cmd, data, rem);
272  } else {
273  got_player_cmd = handle_cmd(ns, pl, cmd, NULL, 0);
274  }
275 
277  if (got_player_cmd) {
278  return;
279  }
280 
281  command_count += 1;
282  /* Evil case, and not a nice workaround, but well...
283  * If we receive eg an accountplay command, the socket is copied
284  * to the player structure, and its faces_sent is set to NULL.
285  * This leads to issues when processing the next commands in the queue,
286  * especially if related to faces...
287  * So get out of here in this case, which we detect because faces_sent is NULL.
288  */
289  if (ns->faces_sent == NULL) {
290  command_count = 6;
291  }
292  }
293 }
294 
295 /*****************************************************************************
296  *
297  * Low level socket looping - select calls and watchdog udp packet
298  * sending.
299  *
300  ******************************************************************************/
301 
302 #ifdef WATCHDOG
303 
309 void watchdog(void) {
310  static int fd = -1;
311  static struct sockaddr_in insock;
312 
313  if (fd == -1) {
314  struct protoent *protoent;
315 
316  if ((protoent = getprotobyname("udp")) == NULL
317  || (fd = socket(PF_INET, SOCK_DGRAM, protoent->p_proto)) == -1) {
318  return;
319  }
320  insock.sin_family = AF_INET;
321  insock.sin_port = htons((unsigned short)13325);
322  insock.sin_addr.s_addr = inet_addr("127.0.0.1");
323  }
324  sendto(fd, (void *)&fd, 1, 0, (struct sockaddr *)&insock, sizeof(insock));
325 }
326 #endif
327 
328 extern unsigned long todtick;
329 
333 static void block_until_new_connection(void) {
334  struct timeval Timeout;
335  fd_set readfs;
336  int cycles;
337  int i;
338 
339  LOG(llevInfo, "Waiting for connections...\n");
340 
341  cycles = 1;
342  do {
343  /* Every minutes is a bit often for updates - especially if nothing is going
344  * on. This slows it down to every 6 minutes.
345  */
346  cycles++;
347  if (cycles%2 == 0)
348  tick_the_clock();
349 
350  FD_ZERO(&readfs);
351  for (i = 0; i < socket_info.allocated_sockets && init_sockets[i].listen; i++)
352  if (init_sockets[i].status == Ns_Add)
353  FD_SET((uint32_t)init_sockets[i].fd, &readfs);
354 
355  /* If fastclock is set, we need to seriously slow down the updates
356  * to the metaserver as well as watchdog. Do same for flush_old_maps() -
357  * that is time sensitive, so there is no good reason to call it 2000 times
358  * a second.
359  */
360  if (settings.fastclock > 0) {
361 #ifdef WATCHDOG
362  if (cycles%120000 == 0) {
363  watchdog();
364  flush_old_maps();
365  }
366 #endif
367  if (cycles == 720000) {
369  cycles = 1;
370  }
371  Timeout.tv_sec = 0;
372  Timeout.tv_usec = 50;
373  } else {
374  Timeout.tv_sec = 60;
375  Timeout.tv_usec = 0;
376  if (cycles == 7) {
378  cycles = 1;
379  }
380  flush_old_maps();
381  }
382  } while (select(socket_info.max_filedescriptor, &readfs, NULL, NULL, &Timeout) == 0);
383 
384  reset_sleep(); /* Or the game would go too fast */
385 }
386 
395 static int is_fd_valid(int fd) {
396 #ifndef WIN32
397  return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
398 #else
399  return 1;
400 #endif
401 }
402 
407 static void new_connection(int listen_fd) {
408  int newsocknum = -1, j;
409 #ifdef HAVE_GETNAMEINFO
410  struct sockaddr_storage addr;
411 #else
412  struct sockaddr_in addr;
413 #endif
414  socklen_t addrlen = sizeof(addr);
415 
416 #ifdef ESRV_DEBUG
417  LOG(llevDebug, "do_server: New Connection\n");
418 #endif
419 
420  for (j = 0; j < socket_info.allocated_sockets; j++)
421  if (init_sockets[j].status == Ns_Avail) {
422  newsocknum = j;
423  break;
424  }
425 
426  if (newsocknum == -1) {
427  /* If this is the case, all sockets currently in used */
429  if (!init_sockets)
431  newsocknum = socket_info.allocated_sockets;
433  init_sockets[newsocknum].listen = NULL;
435  init_sockets[newsocknum].faces_sent = calloc(nrofpixmaps, sizeof(*init_sockets[newsocknum].faces_sent));
436  if (!init_sockets[newsocknum].faces_sent)
438  init_sockets[newsocknum].status = Ns_Avail;
439  }
440 
441  if (newsocknum < 0) {
442  LOG(llevError, "FATAL: didn't allocate a newsocket?? alloc = %d, newsocknum = %d", socket_info.allocated_sockets, newsocknum);
444  }
445 
446  init_sockets[newsocknum].fd = accept(listen_fd, (struct sockaddr *)&addr, &addrlen);
447  if (init_sockets[newsocknum].fd == -1) {
448  LOG(llevError, "accept failed: %s\n", strerror(errno));
449  } else {
450  char buf[MAX_BUF];
451 #ifndef HAVE_GETNAMEINFO
452  long ip;
453 #endif
454  socket_struct *ns;
455 
456  ns = &init_sockets[newsocknum];
457 
458 #ifdef HAVE_GETNAMEINFO
459  getnameinfo((struct sockaddr *) &addr, addrlen, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
460 #else
461  ip = ntohl(addr.sin_addr.s_addr);
462  snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld", (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, ip&255);
463 #endif
464 
465  if (checkbanned(NULL, buf)) {
466  LOG(llevInfo, "Banned host tried to connect: [%s]\n", buf);
467  close(init_sockets[newsocknum].fd);
468  init_sockets[newsocknum].fd = -1;
469  } else {
470  init_connection(ns, buf);
471  }
472  }
473 }
474 
481  // If the client doesn't send heartbeats, assume it's connected.
482  if (!socket.heartbeat) {
483  return true;
484  }
485 
486  // If a client message was received recently, it's connected.
487  if (socket.last_tick < tick_length(BEAT_INTERVAL + 1)) {
488  return true;
489  }
490 
491  return false;
492 }
493 
501 void do_server(void) {
502  int i, pollret, active = 0;
503  fd_set tmp_read, tmp_exceptions, tmp_write;
504  player *pl, *next;
505 
506  if (shutdown_flag == 1) {
507  LOG(llevInfo, "Shutting down...\n");
508  shutdown_flag += 1;
509  cmd_shutdown_time = time(NULL);
510  }
511 
512 #ifdef CS_LOGSTATS
513  if ((time(NULL)-cst_lst.time_start) >= CS_LOGTIME)
514  write_cs_stats();
515 #endif
516 
517  FD_ZERO(&tmp_read);
518  FD_ZERO(&tmp_write);
519  FD_ZERO(&tmp_exceptions);
520 
521  for (i = 0; i < socket_info.allocated_sockets; i++) {
522  if (init_sockets[i].status == Ns_Add && !is_fd_valid(init_sockets[i].fd)) {
523  LOG(llevError, "do_server: invalid waiting fd %d\n", i);
525  }
526  if (init_sockets[i].status == Ns_Dead) {
527  if (init_sockets[i].listen) {
528  /* try to reopen the listening socket */
530  } else {
533  }
534  } else if (init_sockets[i].status != Ns_Avail) {
535  FD_SET((uint32_t)init_sockets[i].fd, &tmp_read);
536  FD_SET((uint32_t)init_sockets[i].fd, &tmp_write);
537  FD_SET((uint32_t)init_sockets[i].fd, &tmp_exceptions);
538  active++;
539  }
540  }
541 
542  /* Go through the players. Let the loop set the next pl value,
543  * since we may remove some
544  */
545  for (pl = first_player; pl != NULL; ) {
546  if (pl->socket.status != Ns_Dead && !is_fd_valid(pl->socket.fd)) {
547  LOG(llevError, "do_server: invalid file descriptor for player %s [%s]: %d\n", (pl->ob && pl->ob->name) ? pl->ob->name : "(unnamed player?)", (pl->socket.host) ? pl->socket.host : "(unknown ip?)", pl->socket.fd);
548  pl->socket.status = Ns_Dead;
549  }
550 
551  if (pl->socket.status == Ns_Dead) {
552  player *npl = pl->next;
553 
554  save_player(pl->ob, 0);
555  leave(pl, 1);
556  final_free_player(pl);
557  pl = npl;
558  } else {
559  FD_SET((uint32_t)pl->socket.fd, &tmp_read);
560  FD_SET((uint32_t)pl->socket.fd, &tmp_write);
561  FD_SET((uint32_t)pl->socket.fd, &tmp_exceptions);
562  pl = pl->next;
563  }
564  }
565 
566  if (active == 1 && first_player == NULL)
568 
569  /* Reset timeout each time, since some OS's will change the values on
570  * the return from select.
571  */
572  socket_info.timeout.tv_sec = 0;
573  socket_info.timeout.tv_usec = 0;
574 
575  pollret = select(socket_info.max_filedescriptor, &tmp_read, &tmp_write, &tmp_exceptions, &socket_info.timeout);
576 
577  if (pollret == -1) {
578  LOG(llevError, "select failed: %s\n", strerror(errno));
579  return;
580  }
581 
582  /* We need to do some of the processing below regardless */
583  /* if (!pollret) return;*/
584 
585  /* Check for any exceptions/input on the sockets */
586  if (pollret)
587  for (i = 0; i < socket_info.allocated_sockets; i++) {
588  /* listen sockets can stay in status Ns_Dead */
589  if (init_sockets[i].status != Ns_Add)
590  continue;
591  if (FD_ISSET(init_sockets[i].fd, &tmp_exceptions)) {
594  continue;
595  }
596  if (FD_ISSET(init_sockets[i].fd, &tmp_read)) {
597  if (init_sockets[i].listen)
599  else
600  handle_client(&init_sockets[i], NULL);
601  }
602  if (FD_ISSET(init_sockets[i].fd, &tmp_write)) {
603  init_sockets[i].can_write = 1;
604  }
605  }
606 
607  /* This does roughly the same thing, but for the players now */
608  for (pl = first_player; pl != NULL; pl = next) {
609  next = pl->next;
610  if (pl->socket.status == Ns_Dead)
611  continue;
612 
613  if (FD_ISSET(pl->socket.fd, &tmp_write)) {
614  if (!pl->socket.can_write) {
615  pl->socket.can_write = 1;
617  }
618  /* if we get an error on the write_socket buffer, no reason to
619  * continue on this socket.
620  */
621  if (pl->socket.status == Ns_Dead)
622  continue;
623  } else
624  pl->socket.can_write = 0;
625 
626  if (FD_ISSET(pl->socket.fd, &tmp_exceptions)) {
627  save_player(pl->ob, 0);
628  leave(pl, 1);
629  final_free_player(pl);
630  } else {
631  handle_client(&pl->socket, pl);
632 
633  /* There seems to be rare cases where next points to a removed/freed player.
634  * My belief is that this player does something (shout, move, whatever)
635  * that causes data to be sent to the next player on the list, but
636  * that player is defunct, so the socket codes removes that player.
637  * End result is that next now points at the removed player, and
638  * that has garbage data so we crash. So update the next pointer
639  * while pl is still valid. MSW 2007-04-21
640  */
641  next = pl->next;
642 
643 
644  /* If the player has left the game, then the socket status
645  * will be set to this be the leave function. We don't
646  * need to call leave again, as it has already been called
647  * once.
648  */
649  if (pl->socket.status == Ns_Dead) {
650  save_player(pl->ob, 0);
651  leave(pl, 1);
652  final_free_player(pl);
653  } else {
654  /* Increment time since last contact only if logged in. */
655  if (pl->state == ST_PLAYING) {
656  pl->socket.last_tick++;
657 
658  if (!connection_alive(pl->socket)) {
659  // TODO: Handle a lost client connection.
660  LOG(llevDebug, "Lost client connection!\n");
661  }
662  }
663 
664  /* Update the players stats once per tick. More efficient than
665  * sending them whenever they change, and probably just as useful
666  */
667  esrv_update_stats(pl);
668  if (pl->last_weight != -1 && pl->last_weight != WEIGHT(pl->ob)) {
669  esrv_update_item(UPD_WEIGHT, pl->ob, pl->ob);
670  if (pl->last_weight != WEIGHT(pl->ob))
671  LOG(llevError, "esrv_update_item(UPD_WEIGHT) did not set player weight: is %lu, should be %lu\n", (unsigned long)pl->last_weight, (unsigned long)WEIGHT(pl->ob));
672  }
673  /* draw_client_map does sanity checking that map is
674  * valid, so don't do it here.
675  */
676  draw_client_map(pl->ob);
677  if (pl->socket.update_look)
678  esrv_draw_look(pl->ob);
679  if (pl->socket.update_inventory) {
680  if (pl->ob->container != NULL)
681  esrv_send_inventory(pl->ob, pl->ob->container);
682  pl->socket.update_inventory = 0;
683  }
684  if (pl->socket.tick)
685  send_tick(pl);
686  }
687  }
688  }
689 }
Error, serious thing.
Definition: logger.h:11
const char * cmdname
Command name.
Definition: loop.c:74
One player.
Definition: player.h:92
size_t len
Definition: newclient.h:685
uint32_t tick
Client wishes to get tick commands.
Definition: newserver.h:118
Information.
Definition: logger.h:12
void leave(player *pl, int draw_exit)
Player logs out, or was disconnected.
Definition: server.c:1180
const func_uint8_int_ns cmdproc
Function to call.
Definition: loop.c:67
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.c:48
unsigned char buf[MAXSOCKBUF]
Definition: newclient.h:686
void account_login_cmd(char *buf, int len, socket_struct *ns)
Handles the account login.
Definition: request.c:2037
unsigned char uint8_t
Definition: win32.h:161
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.c:75
void mark_item_cmd(uint8_t *data, int len, player *pl)
Client wants to mark some object.
Definition: item.c:723
void look_at_cmd(char *buf, int len, player *pl)
Client wants to look at some object.
Definition: item.c:819
void version_cmd(char *buf, int len, socket_struct *ns)
Client tells its version.
Definition: request.c:581
void metaserver_update(void)
Updates our info in the metaserver Note that this is used for both metaserver1 and metaserver2 - for ...
Definition: metaserver.c:49
struct obj * container
Current container being used.
Definition: object.h:291
const func_uint8_int_pl cmdproc
Function to call.
Definition: loop.c:75
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.c:596
uint32_t last_tick
Number of ticks since last communication.
Definition: newserver.h:142
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.c:211
void do_server(void)
This checks the sockets for input and exceptions, does the right thing.
Definition: loop.c:501
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.c:342
void send_map_info(socket_struct *ns)
Send information on the specified class.
Definition: requestinfo.c:404
void send_image_sums(socket_struct *ns, char *params)
Sends requested face information.
Definition: image.c:139
Socket structure, represents a client-server connection.
Definition: newserver.h:99
socket_struct socket
Socket information for this player.
Definition: player.h:94
void esrv_send_inventory(object *pl, object *op)
Sends inventory of a container.
Definition: item.c:307
bool heartbeat
Client will send hearbeats.
Definition: newserver.h:124
void new_player_cmd(uint8_t *buf, int len, player *pl)
This handles the commands issued by the player (ie, north, fire, cast, etc.).
Definition: request.c:447
int checkbanned(const char *login, const char *host)
Check if a player and/or host is banned.
Definition: ban.c:32
enum Sock_Status status
Definition: newserver.h:100
#define socklen_t
Definition: win32.h:130
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.c:908
int max_filedescriptor
max filedescriptor on the system.
Definition: newserver.h:155
Global type definitions and header inclusions.
void send_skill_info(socket_struct *ns, char *params)
This sends the skill number to name mapping.
Definition: requestinfo.c:67
#define ST_PLAYING
Usual state.
Definition: define.h:577
int tick_length(float seconds)
Calculate the number of ticks that correspond to real time.
Definition: time.c:378
char * host
Which host it is connected from (ip address).
Definition: newserver.h:110
unsigned int nrofpixmaps
Number of bitmaps loaded from the "bmaps" file.
Definition: image.c:45
socket_struct * init_sockets
Established connections for clients not yet playing.
Definition: init.c:56
void send_class_list(socket_struct *ns, char *params)
Sends the list of classes to the client.
Definition: requestinfo.c:359
void free_newsocket(socket_struct *ns)
Frees a socket.
Definition: init.c:413
int cmd_shutdown_time
Time, in seconds from epoch, of server shutdown.
Definition: c_wiz.c:43
size_t faces_sent_len
This is the number of elements allocated in faces_sent[].
Definition: newserver.h:105
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:115
static int handle_cmd(socket_struct *ns, player *pl, char *cmd, char *data, int len)
Definition: loop.c:195
const uint8_t flag
If set, the player must be in the ST_PLAYING state for this command to be available.
Definition: loop.c:76
void flush_old_maps(void)
Removes tmp-files of maps which are going to be reset next time they are visited. ...
Definition: swap.c:294
static const struct client_cmd_mapping client_commands[]
Commands sent directly by client, when connecting or when needed.
Definition: loop.c:108
#define strtok_r(x, y, z)
Definition: win32.h:62
Socket_Info socket_info
Socket information.
Definition: init.c:47
Image-related structures.
CS_Stats cst_lst
float speed_left
How much speed is left to spend this round.
Definition: object.h:329
void handle_client(socket_struct *ns, player *pl)
Handle commands from a client.
Definition: loop.c:234
void send_exp_table(socket_struct *ns, char *params)
This sends the experience table the sever is using.
Definition: requestinfo.c:121
#define BEAT_INTERVAL
Interval between heartbeat requests.
Definition: config.h:689
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.c:58
Definition of a function the client sends without player interaction.
Definition: loop.c:65
#define snprintf
Definition: win32.h:46
void(* func_uint8_int_ns)(char *, int, socket_struct *)
Prototype for functions the client sends without player interaction.
Definition: loop.c:62
void account_password(char *buf, int len, socket_struct *ns)
Handles the account password change.
Definition: request.c:2862
void write_socket_buffer(socket_struct *ns)
Writes data to socket.
Definition: lowlevel.c:424
bool connection_alive(socket_struct socket)
Check whether the given socket&#39;s connection is alive or not.
Definition: loop.c:480
const char * name
The name of the object, obviously...
Definition: object.h:311
#define WEIGHT(op)
Returns the weight of the given object.
Definition: define.h:686
void init_listening_socket(socket_struct *ns)
This opens *ns for listening to connections.
Definition: init.c:171
uint8_t state
Input state of the player (name, password, etc).
Definition: player.h:118
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.c:149
uint32_t can_write
Can we write to this socket?
Definition: newserver.h:117
Defines various structures and values that are used for the new client server communication method...
void account_new_cmd(char *buf, int len, socket_struct *ns)
Handles the account creation This function shares a fair amount of the same logic as account_login_cm...
Definition: request.c:2163
uint32_t update_inventory
If true, we need to send the inventory list.
Definition: newserver.h:116
void send_race_info(socket_struct *ns, char *params)
Sends information on specified race to the client.
Definition: requestinfo.c:313
#define UPD_WEIGHT
Definition: newclient.h:291
void tick_the_clock(void)
This performs the basic function of advancing the clock one tick forward.
Definition: weather.c:96
int allocated_sockets
Number of allocated items in init_sockets.
Definition: newserver.h:156
void send_image_info(socket_struct *ns)
Sends the number of images, checksum of the face file, and the image_info file information.
Definition: image.c:112
volatile sig_atomic_t shutdown_flag
Definition: server.h:6
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
static int is_fd_valid(int fd)
Checks if file descriptor is valid.
Definition: loop.c:395
#define CS_LOGTIME
Definition: config.h:187
void reset_sleep(void)
Initialise all variables used in the timing routines.
Definition: time.c:130
void send_class_info(socket_struct *ns, char *params)
Send information on the specified class.
Definition: requestinfo.c:380
void set_up_cmd(char *buf, int len, socket_struct *ns)
This is the Setup cmd - easy first implementation.
Definition: request.c:93
object * ob
The object representing the player.
Definition: player.h:158
void draw_client_map(object *pl)
Draws client map.
Definition: request.c:1438
unsigned int uint32_t
Definition: win32.h:162
void esrv_draw_look(object *pl)
Send the look window.
Definition: item.c:187
static const struct player_cmd_mapping player_commands[]
Dispatch tables for the server.
Definition: loop.c:94
unsigned long todtick
Ingame time.
Definition: init.c:440
void init_connection(socket_struct *ns, const char *from_ip)
Initializes a connection.
Definition: init.c:63
const char * cmdname
Command name.
Definition: loop.c:66
void send_tick(player *pl)
Definition: request.c:1797
void send_spell_paths(socket_struct *ns, char *params)
This sends the spell path to name mapping.
Definition: requestinfo.c:97
void request_info_cmd(char *buf, int len, socket_struct *ns)
request_info_cmd is sort of a meta command.
Definition: loop.c:133
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:142
void lock_item_cmd(uint8_t *data, int len, player *pl)
Client wants to apply some object.
Definition: item.c:671
void write_cs_stats(void)
Only for debugging purposes.
Definition: logger.h:13
struct timeval timeout
Timeout for select.
Definition: newserver.h:154
struct Settings settings
Server settings.
Definition: init.c:40
void ask_smooth_cmd(char *buf, int len, socket_struct *ns)
Tells client the picture it has to use to smooth a picture number given as argument.
Definition: request.c:423
void(* func_uint8_int_pl)(char *, int, player *)
Prototype for functions used to handle player actions.
Definition: loop.c:71
void send_file(socket_struct *ns, const char *file)
Sends the desired file to the client.
Definition: requestinfo.c:443
void examine_cmd(char *buf, int len, player *pl)
Client wants to examine some object.
Definition: item.c:612
uint8_t fastclock
If true, clock goes warp 9.
Definition: global.h:295
void apply_cmd(char *buf, int len, player *pl)
Client wants to apply some object.
Definition: item.c:631
static void block_until_new_connection(void)
Waits for new connection when there is no one connected.
Definition: loop.c:333
EXTERN player * first_player
First player.
Definition: global.h:117
time_t time_start
When we started logging this.
Definition: newclient.h:697
struct pl * next
Pointer to next player, NULL if this is last.
Definition: player.h:93
void account_add_player_cmd(char *buf, int len, socket_struct *ns)
Handle accountaddplayer from server (add a character to this account).
Definition: request.c:2271
void watchdog(void)
void final_free_player(player *pl)
Sends the &#39;goodbye&#39; command to the player, and closes connection.
Definition: init.c:444
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
void add_me_cmd(char *buf, int len, socket_struct *ns)
The client has requested to be added to the game.
Definition: request.c:347
Definition of a function called in reaction to player&#39;s action.
Definition: loop.c:73
void send_race_list(socket_struct *ns, char *params)
Send the list of player races to the client.
Definition: requestinfo.c:292
void reply_cmd(char *buf, int len, player *pl)
This is a reply to a previous query.
Definition: request.c:509
void send_new_char_info(socket_struct *ns)
Sends information related to creating a new character to the client.
Definition: requestinfo.c:484
static void new_connection(int listen_fd)
Handle a new connection from a client.
Definition: loop.c:407
void knowledge_send_info(socket_struct *ns)
Send the reply_info for &#39;knowledge_info&#39;.
Definition: knowledge.c:1382
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:680
void SockList_NullTerminate(SockList *sl)
Adds a NUL byte without changing the length.
Definition: lowlevel.c:229
void esrv_update_stats(player *pl)
Sends a statistics update.
Definition: request.c:725
int SockList_ReadPacket(int fd, SockList *sl, int len)
This reads from fd and puts the data in sl.
Definition: lowlevel.c:267
void send_face_cmd(char *buff, int len, socket_struct *ns)
Client has requested pixmap that it somehow missed getting.
Definition: image.c:43
struct listen_info * listen
Definition: newserver.h:102
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:106
void move_cmd(char *buf, int len, player *pl)
Moves an object (typically, container to inventory).
Definition: request.c:636
void create_player_cmd(char *buf, int len, socket_struct *ns)
We have received a createplayer command.
Definition: request.c:2487
SockList inbuf
If we get an incomplete packet, this is used to hold the data.
Definition: newserver.h:109
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.c:542
void account_play_cmd(char *buf, int len, socket_struct *ns)
We have received an accountplay command.
Definition: request.c:2400