Crossfire Server  1.75.0
loop.cpp
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 <assert.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #ifndef WIN32 /* ---win32 exclude unix headers */
35 #include <arpa/inet.h>
36 #include <sys/types.h>
37 #include <sys/time.h>
38 #include <netinet/in.h>
39 #include <netdb.h>
40 #else
41 #include <winsock2.h>
42 #endif /* end win32 */
43 
44 #include "image.h"
45 #include "newserver.h"
46 #include "sockproto.h"
47 #include "sproto.h"
48 
49 extern uint32_t last_time;
50 
51 /*****************************************************************************
52  * Start of command dispatch area.
53  * The commands here are protocol commands.
54  ****************************************************************************/
55 
56 /* Either keep this near the start or end of the file so it is
57  * at least reasonablye easy to find.
58  * There are really 2 commands - those which are sent/received
59  * before player joins, and those happen after the player has joined.
60  * As such, we have function types that might be called, so
61  * we end up having 2 tables.
62  */
63 
65 typedef void (*func_uint8_int_ns)(char *, int, socket_struct *);
66 
69  const char *cmdname;
71 };
72 
74 typedef void (*func_uint8_int_pl)(char *, int, player *);
77  const char *cmdname;
79  const uint8_t flag;
80 };
81 
97 static const struct player_cmd_mapping player_commands[] = {
98  { "examine", examine_cmd, 1 },
99  { "apply", apply_cmd, 1 },
100  { "move", move_cmd, 1 },
101  { "reply", reply_cmd, 0 },
102  { "ncom", (func_uint8_int_pl)new_player_cmd, 1 },
103  { "lookat", look_at_cmd, 1 },
104  { "lock", (func_uint8_int_pl)lock_item_cmd, 1 },
105  { "mark", (func_uint8_int_pl)mark_item_cmd, 1 },
106  { "inscribe", inscribe_scroll_cmd, 0 },
107  { NULL, NULL, 0 } /* terminator */
108 };
109 
111 static const struct client_cmd_mapping client_commands[] = {
112  { "addme", add_me_cmd },
113  { "askface", send_face_cmd }, /* Added: phil */
114  { "beat", NULL },
115  { "requestinfo", request_info_cmd },
116  { "setup", set_up_cmd },
117  { "version", version_cmd },
118  { "asksmooth", ask_smooth_cmd }, /*Added: tchize (smoothing technologies)*/
119  { "accountlogin", account_login_cmd },
120  { "accountnew", account_new_cmd },
121  { "accountaddplayer", account_add_player_cmd },
122  { "accountplay", account_play_cmd },
123  { "accountpw", account_password },
124  { "createplayer", create_player_cmd },
125  { NULL, NULL } /* terminator (I, II & III)*/
126 };
127 
136 void request_info_cmd(char *buf, int len, socket_struct *ns) {
137  char *params = NULL, *cp;
138  /* No match */
139  SockList sl;
140 
141  if (len <= 0 || !buf) {
142  LOG(llevDebug, "IP '%s' sent bogus request_info_cmd information\n", ns->host);
143  return;
144  }
145 
146  /* Set up replyinfo before we modify any of the buffers - this is used
147  * if we don't find a match.
148  */
149  SockList_Init(&sl);
150  SockList_AddString(&sl, "replyinfo ");
151  SockList_AddString(&sl, buf);
152 
153  /* find the first space, make it null, and update the
154  * params pointer.
155  */
156  for (cp = buf; *cp != '\0'; cp++)
157  if (*cp == ' ') {
158  *cp = '\0';
159  params = cp+1;
160  break;
161  }
162  if (!strcmp(buf, "image_info"))
163  send_image_info(ns);
164  else if (!strcmp(buf, "image_sums"))
165  send_image_sums(ns, params);
166  else if (!strcmp(buf, "skill_info"))
167  send_skill_info(ns, params);
168  else if (!strcmp(buf, "skill_extra"))
169  send_skill_extra(ns, params);
170  else if (!strcmp(buf, "spell_paths"))
171  send_spell_paths(ns);
172  else if (!strcmp(buf, "exp_table"))
173  send_exp_table(ns);
174  else if (!strcmp(buf, "race_list"))
175  send_race_list(ns);
176  else if (!strcmp(buf, "race_info"))
177  send_race_info(ns, params);
178  else if (!strcmp(buf, "class_list"))
179  send_class_list(ns);
180  else if (!strcmp(buf, "class_info"))
181  send_class_info(ns, params);
182  else if (!strcmp(buf, "rules"))
183  send_file(ns, "rules");
184  else if (!strcmp(buf, "motd"))
185  send_file(ns, "motd");
186  else if (!strcmp(buf, "news"))
187  send_file(ns, "news");
188  else if (!strcmp(buf,"newcharinfo"))
189  send_new_char_info(ns);
190  else if (!strcmp(buf,"startingmap"))
191  send_map_info(ns);
192  else if (!strcmp(buf, "knowledge_info"))
194  else
195  Send_With_Handling(ns, &sl);
196  SockList_Term(&sl);
197 }
198 
208 static int
209 handle_cmd(socket_struct *ns, player *pl, char *cmd, char *data, int len) {
210  /* Fuzz testing indicated a way to get a null command here
211  * --> make an empty command, but have a length.
212  * So, if we get here with a null command, log it and exit the function.
213  * Neila Hawkins 2020-01-16
214  */
215  if (cmd == NULL) {
216  LOG(llevDebug, "%s: missing command. Sending garbage?\n", ns->host);
217  return 0;
218  }
219  for (int i = 0; client_commands[i].cmdname != NULL; i++) {
220  if (strcmp(cmd, client_commands[i].cmdname) == 0) {
221  if (client_commands[i].cmdproc != NULL) {
222  client_commands[i].cmdproc(data, len, ns);
223  }
224  return 0;
225  }
226  }
227  /* Player must be in the playing state or the flag on the
228  * the command must be zero for the user to use the command -
229  * otherwise, a player cam save, be in the play_again state, and
230  * the map they were on getsswapped out, yet things that try to look
231  * at the map causes a crash. If the command is valid, but
232  * one they can't use, we still swallow it up.
233  */
234  if (pl) {
235  for (int i = 0; player_commands[i].cmdname != NULL; i++) {
236  if (strcmp(cmd, player_commands[i].cmdname) == 0) {
237  if (pl->state == ST_PLAYING || player_commands[i].flag == 0) {
238  player_commands[i].cmdproc(data, len, pl);
239  }
240  return 1;
241  }
242  }
243  }
244  LOG(llevDebug, "%s: invalid command '%s'\n", ns->host, cmd);
245  return 0;
246 }
247 
258  /* Loop through this - maybe we have several complete packets here. */
259  /* Command_count is used to limit the number of requests from
260  * clients that have not logged in - we do not want an unauthenticated
261  * connection to spew us with hundreds of requests. As such,
262  * this counter is only increased in the case of socket level commands.
263  * Note that this also has the effect of throttling down face and other
264  * socket commands from the client. As such, if we have a player attached,
265  * we will process more of these, as getting a fair number when entering
266  * a map may not be uncommon.
267  */
268  int command_count = 0;
269  while (command_count < 5 || (pl && command_count < 25)) {
270  if (pl && pl->state == ST_PLAYING && pl->ob != NULL && pl->ob->speed_left < 0) {
271  // Skip processing players with no turns left.
272  return false;
273  }
274 
275  int status = SockList_ReadPacket(ns->fd, &ns->inbuf, sizeof(ns->inbuf.buf)-1);
276  if (status != 1) {
277  if (status < 0) {
278  ns->status = Ns_Dead;
279  }
280  return false;
281  }
282 
283  if (pl && pl->state == ST_PLAYING && pl->ob != NULL)
285 
286  /* Since we have a full packet, reset last tick time. */
287  ns->last_tick = 0;
288 
290  assert(ns->inbuf.len >= 2);
291  char *data;
292  char *cmd = strtok_r((char *)ns->inbuf.buf + 2, " ", &data);
293 
294  int got_player_cmd;
295  if (data != NULL) {
296  int rem = ns->inbuf.len - ((unsigned char *)data - ns->inbuf.buf);
297  got_player_cmd = handle_cmd(ns, pl, cmd, data, rem);
298  } else {
299  got_player_cmd = handle_cmd(ns, pl, cmd, NULL, 0);
300  }
301 
303  if (got_player_cmd) {
304  return true;
305  }
306 
307  command_count += 1;
308  /* Evil case, and not a nice workaround, but well...
309  * If we receive eg an accountplay command, the socket is copied
310  * to the player structure, and its faces_sent is set to NULL.
311  * This leads to issues when processing the next commands in the queue,
312  * especially if related to faces...
313  * So get out of here in this case, which we detect because faces_sent is NULL.
314  */
315  if (ns->faces_sent == NULL) {
316  command_count = 6;
317  }
318  }
319  return false;
320 }
321 
322 /*****************************************************************************
323  *
324  * Low level socket looping - select calls and watchdog udp packet
325  * sending.
326  *
327  ******************************************************************************/
328 
329 #ifdef WATCHDOG
330 
336 void watchdog(void) {
337  static int fd = -1;
338  static struct sockaddr_in insock;
339 
340  if (fd == -1) {
341  struct protoent *protoent;
342 
343  if ((protoent = getprotobyname("udp")) == NULL
344  || (fd = socket(PF_INET, SOCK_DGRAM, protoent->p_proto)) == -1) {
345  return;
346  }
347  insock.sin_family = AF_INET;
348  insock.sin_port = htons((unsigned short)13325);
349  insock.sin_addr.s_addr = inet_addr("127.0.0.1");
350  }
351  char buf[MAX_BUF];
352  snprintf(buf, sizeof(buf), "%d\n", pticks);
353  sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&insock, sizeof(insock));
354 }
355 #endif
356 
365 static int is_fd_valid(int fd) {
366 #ifndef WIN32
367  return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
368 #else
369  return 1;
370 #endif
371 }
372 
377 static void new_connection(int listen_fd) {
378  int newsocknum = -1, j;
379 #ifdef HAVE_GETNAMEINFO
380  struct sockaddr_storage addr;
381 #else
382  struct sockaddr_in addr;
383 #endif
384  socklen_t addrlen = sizeof(addr);
385 
386 #ifdef ESRV_DEBUG
387  LOG(llevDebug, "do_server: New Connection\n");
388 #endif
389 
390  for (j = 0; j < socket_info.allocated_sockets; j++)
391  if (init_sockets[j].status == Ns_Avail) {
392  newsocknum = j;
393  break;
394  }
395 
396  if (newsocknum == -1) {
397  /* If this is the case, all sockets currently in used */
398  init_sockets = static_cast<socket_struct *>(realloc(init_sockets, sizeof(socket_struct)*(socket_info.allocated_sockets+1)));
399  if (!init_sockets)
401  newsocknum = socket_info.allocated_sockets;
403  memset(&init_sockets[newsocknum], 0, sizeof(*init_sockets));
404  init_sockets[newsocknum].listen = NULL;
406  init_sockets[newsocknum].faces_sent = static_cast<uint8_t *>(calloc(get_faces_count(), sizeof(*init_sockets[newsocknum].faces_sent)));
407  if (!init_sockets[newsocknum].faces_sent)
409  init_sockets[newsocknum].status = Ns_Avail;
410  }
411 
412  if (newsocknum < 0) {
413  LOG(llevError, "FATAL: didn't allocate a newsocket?? alloc = %d, newsocknum = %d", socket_info.allocated_sockets, newsocknum);
415  }
416 
417  init_sockets[newsocknum].fd = accept(listen_fd, (struct sockaddr *)&addr, &addrlen);
418  if (init_sockets[newsocknum].fd == -1) {
419  LOG(llevError, "accept failed: %s\n", strerror(errno));
420  } else {
421  char buf[MAX_BUF];
422 #ifndef HAVE_GETNAMEINFO
423  long ip;
424 #endif
425  socket_struct *ns;
426 
427  ns = &init_sockets[newsocknum];
428 
429 #ifdef HAVE_GETNAMEINFO
430  getnameinfo((struct sockaddr *) &addr, addrlen, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
431 #else
432  ip = ntohl(addr.sin_addr.s_addr);
433  snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld", (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, ip&255);
434 #endif
435 
436  if (checkbanned(NULL, buf)) {
437  LOG(llevInfo, "Banned host tried to connect: [%s]\n", buf);
438  close(init_sockets[newsocknum].fd);
439  init_sockets[newsocknum].fd = -1;
440  } else {
441  init_connection(ns, buf);
442  }
443  }
444 }
445 
451 bool connection_alive(const socket_struct *socket) {
452  // If the client doesn't send heartbeats, assume it's connected.
453  if (!socket->heartbeat) {
454  return true;
455  }
456 
457  // If a client message was received recently, it's connected.
458  if (socket->last_tick < tick_length(BEAT_INTERVAL + 1)) {
459  return true;
460  }
461 
462  return false;
463 }
464 
468 static void send_updates(player *pl) {
469  /* Update the players stats once per tick. More efficient than
470  * sending them whenever they change, and probably just as useful
471  */
472  esrv_update_stats(pl);
473  if (pl->last_weight != -1 && pl->last_weight != WEIGHT(pl->ob)) {
474  esrv_update_item(UPD_WEIGHT, pl->ob, pl->ob);
475  if (pl->last_weight != WEIGHT(pl->ob))
476  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));
477  }
478  /* draw_client_map does sanity checking that map is
479  * valid, so don't do it here.
480  */
481  draw_client_map(pl->ob);
482  if (pl->socket->update_look)
483  esrv_draw_look(pl->ob);
484  if (pl->socket->update_inventory) {
485  if (pl->ob->container != NULL)
486  esrv_send_inventory(pl->ob, pl->ob->container);
487  pl->socket->update_inventory = 0;
488  }
489 }
490 
505  for (int i = 0; i < socket_info.allocated_sockets; i++) {
506  if (!is_fd_valid(init_sockets[i].fd)) {
508  // prevent a memory leak in pre-player clients with faces sent
509  FREE_AND_CLEAR(init_sockets[i].faces_sent);
510  }
511  }
512 
513  for (player *pl = first_player; pl != NULL; pl = pl->next) {
514  if (!is_fd_valid(pl->socket->fd)) {
515  pl->socket->status = Ns_Dead;
516  }
517  }
518 }
519 
527 void do_server(void) {
528  fd_set tmp_read, tmp_exceptions;
529  FD_ZERO(&tmp_read);
530  FD_ZERO(&tmp_exceptions);
531 
532  for (int i = 0; i < socket_info.allocated_sockets; i++) {
533  if (init_sockets[i].status == Ns_Dead) {
534  LOG(llevInfo, "Disconnected from %s\n", init_sockets[i].host);
535  if (init_sockets[i].listen) {
536  /* try to reopen the listening socket */
538  } else {
541  }
542  } else if (init_sockets[i].status != Ns_Avail) {
543  FD_SET((uint32_t)init_sockets[i].fd, &tmp_read);
544  FD_SET((uint32_t)init_sockets[i].fd, &tmp_exceptions);
545  }
546  }
547 
548  /* Go through the players. Let the loop set the next pl value,
549  * since we may remove some
550  */
551  player *pl, *next;
552  for (pl = first_player; pl != NULL; ) {
553  if (pl->socket->status == Ns_Dead) {
554  player *npl = pl->next;
555  save_player(pl->ob, 0);
556  leave(pl, 1);
557  final_free_player(pl);
558  pl = npl;
559  } else {
560  FD_SET((uint32_t)pl->socket->fd, &tmp_read);
561  FD_SET((uint32_t)pl->socket->fd, &tmp_exceptions);
562  pl = pl->next;
563  }
564  }
565 
566  long sleep_time = get_sleep_remaining();
567  if (sleep_time < 0) {
568  LOG(llevInfo, "skipping time (over by %ld ms)\n", -sleep_time/1000);
569  jump_time();
570 #ifdef CS_LOGSTATS
572 #endif
573  }
574 
575  // Log information about last tick. This can't be in log_time() because
576  // CS_Stat is in socket/, and time is in common/.
577 #ifdef CS_LOGSTATS
580  cst_lst.ticks++;
581 #endif
582 
583  // Since we don't report cumulative tick time information, we don't need to
584  // compute it for cst_tot. Those statistics are available from the
585  // process_*_utime variables anyway.
586 
587  while (sleep_time > 0) {
588  socket_info.timeout.tv_sec = 0;
589  socket_info.timeout.tv_usec = sleep_time;
590  int pollret = select(socket_info.max_filedescriptor, &tmp_read, NULL,
591  &tmp_exceptions, &socket_info.timeout);
592  if (pollret == -1) {
593  if (errno == EINTR) {
594  // ignore
595  return;
596  } else if (errno == EBADF) {
597  check_all_fds();
598  }
599  LOG(llevError, "select failed: %s\n", strerror(errno));
600  return;
601  } else if (!pollret) {
602  return;
603  }
604 
605  /* Check for any exceptions/input on the sockets */
606  for (int i = 0; i < socket_info.allocated_sockets; i++) {
607  /* listen sockets can stay in status Ns_Dead */
608  if (init_sockets[i].status != Ns_Add) {
609  continue;
610  }
611  if (FD_ISSET(init_sockets[i].fd, &tmp_exceptions)) {
614  continue;
615  }
616  if (FD_ISSET(init_sockets[i].fd, &tmp_read)) {
617  if (init_sockets[i].listen)
619  else
620  handle_client(&init_sockets[i], NULL);
621  }
622  }
623 
624  /* This does roughly the same thing, but for the players now */
625  for (pl = first_player; pl != NULL; pl = next) {
626  next = pl->next;
627  if (pl->socket->status == Ns_Dead)
628  continue;
629 
630  if (FD_ISSET(pl->socket->fd, &tmp_exceptions)) {
631  save_player(pl->ob, 0);
632  leave(pl, 1);
633  final_free_player(pl);
634  } else {
635  bool keep_processing = handle_client(pl->socket, pl);
636  if (!keep_processing) {
637  FD_CLR(pl->socket->fd, &tmp_read);
638  }
639 
640  /* There seems to be rare cases where next points to a removed/freed player.
641  * My belief is that this player does something (shout, move, whatever)
642  * that causes data to be sent to the next player on the list, but
643  * that player is defunct, so the socket codes removes that player.
644  * End result is that next now points at the removed player, and
645  * that has garbage data so we crash. So update the next pointer
646  * while pl is still valid. MSW 2007-04-21
647  */
648  next = pl->next;
649 
650 
651  /* If the player has left the game, then the socket status
652  * will be set to this be the leave function. We don't
653  * need to call leave again, as it has already been called
654  * once.
655  */
656  if (pl->socket->status == Ns_Dead) {
657  save_player(pl->ob, 0);
658  leave(pl, 1);
659  final_free_player(pl);
660  } else {
661  // Send updates that may have resulted from processing the
662  // latest command. This lets the client get a response to a
663  // command without waiting for the current tick to finish
664  // inside this select() loop. Note that we will call
665  // send_updates() again later in process players(),
666  send_updates(pl);
667  }
668  }
669  }
670  sleep_time = get_sleep_remaining();
671  }
672 }
673 
678  player *pl, *next;
679  for (pl = first_player; pl != NULL; pl = next) {
680  next = pl->next;
681  send_updates(pl);
682  /* Increment time since last contact only if logged in. */
683  if (pl->state == ST_PLAYING) {
684  pl->socket->last_tick++;
685 
686  if (!connection_alive(pl->socket)) {
687  // TODO: Handle a lost client connection.
688  LOG(llevDebug, "Lost client connection!\n");
689  }
690 
691  if (pl->socket->tick)
692  send_tick(pl);
693  }
694  }
695 }
Error, serious thing.
Definition: logger.h:11
const char * cmdname
Command name.
Definition: loop.cpp:77
size_t len
Definition: newclient.h:726
static const struct player_cmd_mapping player_commands[]
Dispatch tables for the server.
Definition: loop.cpp:97
uint32_t tick
Client wishes to get tick commands.
Definition: newserver.h:110
Information.
Definition: logger.h:12
static int is_fd_valid(int fd)
Checks if file descriptor is valid.
Definition: loop.cpp:365
void leave(player *pl, int draw_exit)
Player logs out, or was disconnected.
Definition: server.cpp:1308
const func_uint8_int_ns cmdproc
Function to call.
Definition: loop.cpp:70
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
unsigned char buf[MAXSOCKBUF]
Definition: newclient.h:727
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
void send_skill_extra(socket_struct *ns, char *params)
Send extra skill information.
void account_login_cmd(char *buf, int len, socket_struct *ns)
Handles the account login.
Definition: request.cpp:2230
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.cpp:83
void mark_item_cmd(uint8_t *data, int len, player *pl)
Client wants to mark some object.
Definition: item.cpp:767
void look_at_cmd(char *buf, int len, player *pl)
Client wants to look at some object.
Definition: item.cpp:869
unsigned long max_ticktime
Definition: newclient.h:745
void version_cmd(char *buf, int len, socket_struct *ns)
Client tells its version.
Definition: request.cpp:651
const func_uint8_int_pl cmdproc
Function to call.
Definition: loop.cpp:78
uint32_t last_tick
Number of ticks since last communication.
Definition: newserver.h:134
player * first_player
First player.
Definition: init.cpp:106
bool connection_alive(const socket_struct *socket)
Check whether the given socket&#39;s connection is alive or not.
Definition: loop.cpp:451
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.cpp:239
long get_sleep_remaining()
Definition: time.cpp:189
void request_info_cmd(char *buf, int len, socket_struct *ns)
request_info_cmd is sort of a meta command.
Definition: loop.cpp:136
static const struct client_cmd_mapping client_commands[]
Commands sent directly by client, when connecting or when needed.
Definition: loop.cpp:111
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
void send_map_info(socket_struct *ns)
Send information on available start maps.
void send_image_sums(socket_struct *ns, char *params)
Sends requested face information.
Definition: image.cpp:138
Socket structure, represents a client-server connection.
Definition: newserver.h:93
void esrv_send_inventory(object *pl, object *op)
Sends inventory of a container.
Definition: item.cpp:316
bool heartbeat
Client will send hearbeats.
Definition: newserver.h:116
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.cpp:527
int checkbanned(const char *login, const char *host)
Check if a player and/or host is banned.
Definition: ban.cpp:32
enum Sock_Status status
Definition: newserver.h:94
#define socklen_t
Definition: win32.h:17
#define MAX(x, y)
Definition: compat.h:24
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.cpp:964
int max_filedescriptor
max filedescriptor on the system.
Definition: newserver.h:147
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.cpp:71
#define ST_PLAYING
Usual state.
Definition: define.h:562
char * host
Which host it is connected from (ip address).
Definition: newserver.h:104
socket_struct * init_sockets
Established connections for clients not yet playing.
Definition: init.cpp:66
void free_newsocket(socket_struct *ns)
Frees a socket.
Definition: init.cpp:418
void update_players()
Send updates to players.
Definition: loop.cpp:677
size_t faces_sent_len
This is the number of elements allocated in faces_sent[].
Definition: newserver.h:99
static void send_updates(player *pl)
Send updated stats, map, look, and inventory to the player.
Definition: loop.cpp:468
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:108
void check_all_fds()
Check all file descriptors and mark sockets with invalid ones as dead.
Definition: loop.cpp:504
const uint8_t flag
If set, the player must be in the ST_PLAYING state for this command to be available.
Definition: loop.cpp:79
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:108
unsigned long ticks_overtime
Definition: newclient.h:744
Socket_Info socket_info
Socket information.
Definition: init.cpp:52
void do_server(void)
This checks the sockets for input and exceptions, does the right thing.
Definition: loop.cpp:527
Image-related structures.
CS_Stats cst_lst
#define BEAT_INTERVAL
Interval between heartbeat requests.
Definition: config.h:636
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
Definition of a function the client sends without player interaction.
Definition: loop.cpp:68
void send_exp_table(socket_struct *ns)
This sends the experience table the sever is using.
void account_password(char *buf, int len, socket_struct *ns)
Handles the account password change.
Definition: request.cpp:3097
void(* func_uint8_int_ns)(char *, int, socket_struct *)
Prototype for functions the client sends without player interaction.
Definition: loop.cpp:65
socket_struct * socket
Socket information for this player.
Definition: player.h:109
#define WEIGHT(op)
Returns the weight of the given object.
Definition: define.h:674
void init_listening_socket(socket_struct *ns)
This opens *ns for listening to connections.
Definition: init.cpp:192
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.cpp:157
uint8_t state
Input state of the player (name, password, etc).
Definition: player.h:133
object * ob
The object representing the player.
Definition: player.h:179
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.cpp:2329
bool handle_client(socket_struct *ns, player *pl)
Handle commands from a client.
Definition: loop.cpp:257
size_t get_faces_count()
Definition: assets.cpp:297
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:160
uint32_t update_inventory
If true, we need to send the inventory list.
Definition: newserver.h:109
unsigned long total_ticktime
Definition: newclient.h:746
void send_race_info(socket_struct *ns, char *params)
Sends information on specified race to the client.
#define UPD_WEIGHT
Definition: newclient.h:332
static int handle_cmd(socket_struct *ns, player *pl, char *cmd, char *data, int len)
Handle a command, either directly sent by the client, or sent for a player&#39;s action.
Definition: loop.cpp:209
uint32_t pticks
Number of ticks since time reset.
Definition: time.cpp:47
int allocated_sockets
Number of allocated items in init_sockets.
Definition: newserver.h:148
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.cpp:113
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
void send_class_info(socket_struct *ns, char *params)
Send information on the specified class.
void set_up_cmd(char *buf, int len, socket_struct *ns)
This is the Setup cmd - easy first implementation.
Definition: request.cpp:143
void draw_client_map(object *pl)
Draws client map.
Definition: request.cpp:1692
void esrv_draw_look(object *pl)
Send the look window.
Definition: item.cpp:193
void send_spell_paths(socket_struct *ns)
This sends the spell path to name mapping.
object * container
Current container being used.
Definition: object.h:299
void init_connection(socket_struct *ns, const char *from_ip)
Initializes a connection.
Definition: init.cpp:96
const char * cmdname
Command name.
Definition: loop.cpp:69
void send_tick(player *pl)
Definition: request.cpp:2048
void send_class_list(socket_struct *ns)
Sends the list of classes to the client.
void send_race_list(socket_struct *ns)
Send the list of player races to the client.
void lock_item_cmd(uint8_t *data, int len, player *pl)
Client wants to apply some object.
Definition: item.cpp:708
Only for debugging purposes.
Definition: logger.h:13
struct timeval timeout
Timeout for select.
Definition: newserver.h:146
static void new_connection(int listen_fd)
Handle a new connection from a client.
Definition: loop.cpp:377
unsigned long ticks
Definition: newclient.h:743
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.cpp:503
void(* func_uint8_int_pl)(char *, int, player *)
Prototype for functions used to handle player actions.
Definition: loop.cpp:74
void send_file(socket_struct *ns, const char *file)
Sends the desired file to the client.
void examine_cmd(char *buf, int len, player *pl)
Client wants to examine some object.
Definition: item.cpp:646
void apply_cmd(char *buf, int len, player *pl)
Client wants to apply some object.
Definition: item.cpp:668
void account_add_player_cmd(char *buf, int len, socket_struct *ns)
Handle accountaddplayer from server (add a character to this account).
Definition: request.cpp:2443
void watchdog(void)
void final_free_player(player *pl)
Sends the &#39;goodbye&#39; command to the player, and closes connection.
Definition: init.cpp:453
void add_me_cmd(char *buf, int len, socket_struct *ns)
The client has requested to be added to the game.
Definition: request.cpp:415
One player.
Definition: player.h:107
Definition of a function called in reaction to player&#39;s action.
Definition: loop.cpp:76
void jump_time()
Definition: time.cpp:198
void reply_cmd(char *buf, int len, player *pl)
This is a reply to a previous query.
Definition: request.cpp:589
void send_new_char_info(socket_struct *ns)
Sends information related to creating a new character to the client.
StringBuffer * buf
Definition: readable.cpp:1563
void knowledge_send_info(socket_struct *ns)
Send the reply_info for &#39;knowledge_info&#39;.
Definition: knowledge.cpp:1374
void player_cancel_repeat(player *pl)
If the player is repeating an action, cancel it.
Definition: player.cpp:320
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:721
#define FREE_AND_CLEAR(xyz)
Free the pointer and then set it to NULL.
Definition: global.h:195
void SockList_NullTerminate(SockList *sl)
Adds a NUL byte without changing the length.
Definition: lowlevel.cpp:237
void esrv_update_stats(player *pl)
Sends a statistics update.
Definition: request.cpp:866
int SockList_ReadPacket(int fd, SockList *sl, int len)
This reads from fd and puts the data in sl.
Definition: lowlevel.cpp:275
void send_face_cmd(char *buff, int len, socket_struct *ns)
Client has requested pixmap that it somehow missed getting.
Definition: image.cpp:45
struct listen_info * listen
Definition: newserver.h:96
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:100
void move_cmd(char *buf, int len, player *pl)
Moves an object (typically, container to inventory).
Definition: request.cpp:708
void create_player_cmd(char *buf, int len, socket_struct *ns)
We have received a createplayer command.
Definition: request.cpp:2677
SockList inbuf
If we get an incomplete packet, this is used to hold the data.
Definition: newserver.h:103
unsigned int tick_length(float seconds)
Calculate the number of ticks that correspond to real time.
Definition: time.cpp:382
uint32_t last_time
Definition: time.cpp:50
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447
void account_play_cmd(char *buf, int len, socket_struct *ns)
We have received an accountplay command.
Definition: request.cpp:2572