Crossfire Server  1.75.0
requestinfo.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 
26 #include "global.h"
27 
28 #include <assert.h>
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/time.h>
33 #include <unistd.h>
34 
35 /* This block is basically taken from socket.c - I assume if it works there,
36  * it should work here.
37  */
38 #ifndef WIN32 /* ---win32 exclude unix headers */
39 #include <sys/types.h>
40 #include <sys/time.h>
41 #include <netinet/in.h>
42 #include <netinet/tcp.h>
43 #include <netdb.h>
44 #endif /* win32 */
45 
46 #include "commands.h"
47 #include "living.h"
48 #include "newserver.h"
49 #include "shared/newclient.h"
50 #include "sounds.h"
51 #include "sproto.h"
52 #include "assets.h"
53 #include "AssetsManager.h"
54 
55 /* Note that following protocol commands (was corresponding function)
56  * are in image.c and not this file, even though they are requestinfo
57  * commands:
58  * image_sums -> send_image_sums()
59  * image_info -> send_image_info()
60  *
61  * The order of the functions here is basically the order they
62  * are called in from request_info_cmd() from loop.c
63  */
64 
71 void send_skill_info(socket_struct *ns, char *params) {
72  SockList sl;
73  int i;
74 
75  SockList_Init(&sl);
76  SockList_AddString(&sl, "replyinfo skill_info\n");
77  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++) {
78  size_t len;
79 
80  len = 16+strlen(skill_names[i]); /* upper bound for length */
81  if (SockList_Avail(&sl) < len) {
82  LOG(llevError, "Buffer overflow in send_skill_info, not sending all skill information\n");
83  break;
84  }
85 
86  if (params != NULL && *params == '1') {
87  if ((skill_faces[i] != NULL) && !(ns->faces_sent[skill_faces[i]->number]&NS_FACESENT_FACE))
88  esrv_send_face(ns, skill_faces[i], 0);
89  SockList_AddPrintf(&sl, "%d:%s:%d\n", i+CS_STAT_SKILLINFO, skill_names[i], skill_faces[i] ? skill_faces[i]->number : 0);
90  } else
91  SockList_AddPrintf(&sl, "%d:%s\n", i+CS_STAT_SKILLINFO, skill_names[i]);
92  }
93  Send_With_Handling(ns, &sl);
94  SockList_Term(&sl);
95 }
96 
102 void send_skill_extra(socket_struct *ns, char *params)
103 {
104  (void)params;
105  SockList sl;
106 
107  SockList_Init(&sl);
108  SockList_AddString(&sl, "replyinfo skill_extra\n");
109  for (uint8_t i = 0; i < MAX_SKILLS && skill_names[i]; i++) {
110  if (skill_messages[i] == NULL)
111  continue;
112 
113  size_t len = 4 + strlen(skill_messages[i]); /* upper bound for length */
114  if (SockList_Avail(&sl) < len) {
115  LOG(llevError, "Buffer overflow in send_skill_extra, not sending all skill information\n");
116  break;
117  }
118 
121  }
122  SockList_AddShort(&sl, 0);
123  Send_With_Handling(ns, &sl);
124  SockList_Term(&sl);
125 }
126 
133  SockList sl;
134  int i;
135 
136  SockList_Init(&sl);
137  SockList_AddString(&sl, "replyinfo spell_paths\n");
138  for (i = 0; i < NRSPELLPATHS; i++) {
139  size_t len;
140 
141  len = 16+strlen(spellpathnames[i]); /* upper bound for length */
142  if (SockList_Avail(&sl) < len) {
143  LOG(llevError, "Buffer overflow in send_spell_paths, not sending all spell information\n");
144  break;
145  }
146 
147  SockList_AddPrintf(&sl, "%d:%s\n", 1<<i, spellpathnames[i]);
148  }
149  Send_With_Handling(ns, &sl);
150  SockList_Term(&sl);
151 }
152 
159  SockList sl;
160  int i;
161  extern int64_t *levels;
162 
163  SockList_Init(&sl);
164  SockList_AddString(&sl, "replyinfo exp_table\n");
166  for (i = 1; i <= settings.max_level; i++) {
167  if (SockList_Avail(&sl) < 8) {
168  LOG(llevError, "Buffer overflow in send_exp_table, not sending all information\n");
169  break;
170  }
171  SockList_AddInt64(&sl, levels[i]);
172  }
173  Send_With_Handling(ns, &sl);
174  SockList_Term(&sl);
175 }
176 
177 /* This is like the AddIf... routines, but instead of
178  * checking against another value which we overwrite,
179  * we just check against 0.
180  */
181 #define AddShortAttr(New, Type) \
182  if (New) { \
183  SockList_AddChar(sl, Type); \
184  SockList_AddShort(sl, New); \
185  }
186 
198 static void send_arch_info(SockList *sl, const object *op)
199 {
200  if (op->name) {
201  SockList_AddString(sl, "name ");
202  SockList_AddLen8Data(sl, op->name, strlen(op->name));
203  }
204 
205  /* It is conceivable some may lack messages */
206  if (op->msg) {
207  SockList_AddString(sl, "msg ");
208  SockList_AddShort(sl, strlen(op->msg));
209  SockList_AddData(sl, op->msg, strlen(op->msg));
210  }
211 
212  SockList_AddString(sl, "stats ");
213  /* Only send non zero stats. More stats could be added here,
214  * but ideally, the text description (op->msg) should give information
215  * about resistances and other abilities.
216  * Send stats last - if the client gets a stat it does not understand,
217  * it stops processing this replyinfo.
218  */
226 
227  /* Terminator for the stats line */
228  SockList_AddChar(sl, 0);
229 
230  /* Handle any race/class_choice options -
231  * the code is exactly the same, except for
232  * name of field we are looking for.
233  */
234  if (op->type == CLASS || op->type == PLAYER) {
235  int i=1;
236  char buf[MAX_BUF];
237  const char *value, *value1;
238  char *lasts, *mychoices, *token;
239 
240  while (1) {
241  if (op->type == PLAYER) {
242  snprintf(buf, MAX_BUF, "race_choice_description_%d", i);
243  value = object_get_value(op, buf);
244  snprintf(buf, MAX_BUF, "race_choice_%d", i);
245  value1 = object_get_value(op, buf);
246  } else { /* Must be class */
247  snprintf(buf, MAX_BUF, "class_choice_description_%d", i);
248  value = object_get_value(op, buf);
249  snprintf(buf, MAX_BUF, "class_choice_%d", i);
250  value1 = object_get_value(op, buf);
251  }
252 
253  if (value && value1) {
254  SockList_AddString(sl, "choice ");
255  SockList_AddLen8Data(sl, buf, strlen(buf));
256  SockList_AddLen8Data(sl, value, strlen(value));
257  i++;
258  /* value1 now contains a list of archetypes */
259  /* Following operations modify string */
260  mychoices = strdup_local(value1);
261 
262  /* split_string() requires we have some
263  * idea on number of fields - in this case,
264  * we really have no idea - one could conceive
265  * of a choice of 50 weapons - using strtok_r
266  * is just as safe and will scale to any amount.
267  */
268  token = strtok_r(mychoices, " ", &lasts);
269  while (token) {
270  archetype *arch;
271 
272  arch = try_find_archetype(token);
273  if (arch) {
274  SockList_AddLen8Data(sl, token, strlen(token));
275  SockList_AddLen8Data(sl, arch->clone.name,
276  strlen(arch->clone.name));
277  } else {
278  LOG(llevError, "send_arch_info: Unable to find archetype %s\n", token);
279  }
280  token = strtok_r(NULL, " ", &lasts);
281  }
282  free(mychoices);
283  /* Terminator byte */
284  SockList_AddChar(sl, 0);
285  } else {
286  break;
287  }
288  }
289  }
290 
291 
292  /* Any addition to data to send should be at the end of the
293  * function - in other words, the order of data sent here should
294  * match order of addition. In that way, the newest additions are
295  * sent last, so client can process this data until it gets
296  * something it does not understand - if new data (subfields in the
297  * replyinfo) are sent first, the client basically has to stop
298  * processing once it gets something it does not understand.
299  */
300 
301 }
302 
309 static void build_race_list_reply(SockList *sl) {
310  SockList_AddString(sl, "replyinfo race_list ");
311 
312  getManager()->archetypes()->each([&sl] (const archetype *race) {
313  if (race->clone.type == PLAYER) {
314  SockList_AddPrintf(sl, "|%s", race->name);
315  }
316  });
317 }
318 
327  static SockList sl;
328  static int sl_initialized = 0;
329 
330  if (!sl_initialized) {
331  sl_initialized = 1;
332  SockList_Init(&sl);
334  }
335 
336  Send_With_Handling(ns, &sl);
337 }
338 
347 void send_race_info(socket_struct *ns, char *params) {
348  if (params == NULL) {
349  LOG(llevError, "send_race_info: IP '%s' sent bogus race_info command.\n", ns->host);
350  return;
351  }
352  archetype *race = try_find_archetype(params);
353  SockList sl;
354 
355  SockList_Init(&sl);
356  SockList_AddPrintf(&sl, "replyinfo race_info %s\n", params);
357 
358  /* do not let the client arbitrarily request information about
359  * any archetype, so put a check in here for the right clone type.
360  */
361  if (race && race->clone.type == PLAYER) {
362  send_arch_info(&sl, &race->clone);
363  }
364 
365  Send_With_Handling(ns, &sl);
366  SockList_Term(&sl);
367 }
368 
376  SockList_Reset(sl);
377  SockList_AddString(sl, "replyinfo class_list ");
378  getManager()->archetypes()->each([&sl] (const archetype *cl) {
379  if (cl->clone.type == CLASS) {
380  SockList_AddPrintf(sl, "|%s", cl->name);
381  }
382  });
383 }
384 
393  static SockList sl;
394  static int sl_initialized = 0;
395 
396  if (!sl_initialized) {
397  sl_initialized = 1;
398  SockList_Init(&sl);
400  }
401 
402  Send_With_Handling(ns, &sl);
403 }
404 
413 void send_class_info(socket_struct *ns, char *params) {
414  if (params == NULL) {
415  LOG(llevError, "send_class_info: IP '%s' sent bogus class_info request.\n", ns->host);
416  return;
417  }
418  archetype *class_arch = try_find_archetype(params);
419  SockList sl;
420 
421  SockList_Init(&sl);
422  SockList_AddPrintf(&sl, "replyinfo class_info %s\n", params);
423 
424  /* do not let the client arbitrarily request information about
425  * any archetype, so put a check in here for the right clone type.
426  */
427  if (class_arch && class_arch->clone.type == CLASS) {
428  send_arch_info(&sl, &class_arch->clone);
429  }
430 
431  Send_With_Handling(ns, &sl);
432  SockList_Term(&sl);
433 }
434 
442  SockList sl;
443 
444  SockList_Init(&sl);
445  SockList_AddPrintf(&sl, "replyinfo startingmap\n");
446 
447  getManager()->archetypes()->each([&sl] (const archetype *m) {
448  if (m->clone.type == MAP && m->clone.subtype == MAP_TYPE_CHOICE) {
449  SockList_AddChar(&sl, INFO_MAP_ARCH_NAME);
450  SockList_AddLen16Data(&sl, m->name, strlen(m->name));
451 
452  SockList_AddChar(&sl, INFO_MAP_NAME);
453  SockList_AddLen16Data(&sl, m->clone.name, strlen(m->clone.name));
454 
455  /* In theory, this should always be set, but better not to crash
456  * if it is not.
457  */
458  if (m->clone.msg) {
459  SockList_AddChar(&sl, INFO_MAP_DESCRIPTION);
460  SockList_AddLen16Data(&sl, m->clone.msg, strlen(m->clone.msg));
461  }
462  }
463  });
464 
465  Send_With_Handling(ns, &sl);
466  SockList_Term(&sl);
467 }
468 
479 void send_file(socket_struct *ns, const char *file) {
480  char buf[MAX_BUF];
481  FILE *fp;
482  SockList sl;
483 
484  if (!strcmp(file,"motd"))
485  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
486  else if (!strcmp(file,"rules"))
487  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
488  else if (!strcmp(file,"news"))
489  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
490  else {
491  LOG(llevError,"send_file requested to send unknown file: %s\n", file);
492  return;
493  }
494  fp = fopen(buf, "r");
495  if (fp == NULL)
496  return;
497  SockList_Init(&sl);
498  SockList_AddString(&sl, "replyinfo ");
499  SockList_AddString(&sl, file);
500  SockList_AddString(&sl, "\n");
501 
502  while (fgets(buf, MAX_BUF, fp) != NULL) {
503  if (*buf == '#')
504  continue;
505  SockList_AddString(&sl, buf);
506  }
507  fclose(fp);
508  SockList_AddChar(&sl, 0); /* Null terminate it */
509  Send_With_Handling(ns, &sl);
510  SockList_Term(&sl);
511 }
512 
521  char buf[MAX_BUF];
522  int i;
523  size_t len;
524  SockList sl;
525 
526  SockList_Init(&sl);
527 
528  SockList_AddString(&sl, "replyinfo newcharinfo\n");
529  snprintf(buf, MAX_BUF, "V points %d", settings.starting_stat_points);
530  /* We add +1 to the length so that the null (terminator) byte
531  * gets included - this make processing on the client side easier.
532  */
533  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
534 
535  snprintf(buf, MAX_BUF, "V statrange %d %d",
537  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
538 
539  snprintf(buf, MAX_BUF, "V statname");
540  len = strlen(buf);
541  for (i=0; i<NUM_STATS; i++) {
542  safe_strcat(buf, " ", &len, MAX_BUF);
543  safe_strcat(buf, short_stat_name[i], &len, MAX_BUF);
544  }
545 
546  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
547 
548  snprintf(buf, MAX_BUF, "R race requestinfo");
549  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
550 
551  snprintf(buf, MAX_BUF, "R class requestinfo");
552  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
553 
554  snprintf(buf, MAX_BUF, "O startingmap requestinfo");
555  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
556 
557  Send_With_Handling(ns, &sl);
558  SockList_Term(&sl);
559 }
Error, serious thing.
Definition: logger.h:11
static void build_race_list_reply(SockList *sl)
Creates the appropriate reply to the &#39;race_list&#39; request info.
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.cpp:202
const char * rules
Name of rules file.
Definition: global.h:280
Sound-related defines.
void send_skill_extra(socket_struct *ns, char *params)
Send extra skill information.
const char * skill_names[MAX_SKILLS]
Will contain a number-name mapping for skills, initialized by init_skills().
Definition: skill_util.cpp:57
void send_race_list(socket_struct *ns)
Send the list of player races to the client.
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.cpp:74
const char *const short_stat_name[NUM_STATS]
Short name of stats.
Definition: living.cpp:194
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:141
Definition: object.h:130
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
uint8_t starting_stat_min
Minimum value of a starting stat.
Definition: global.h:321
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
#define CS_STAT_INT
Definition: newclient.h:96
#define strdup_local
Definition: compat.h:29
Defines various flags that both the new client and new server use.
Number of statistics.
Definition: living.h:18
const char * motd
Name of the motd file.
Definition: global.h:279
int16_t max_level
This is read out of exp_table.
Definition: global.h:303
const Face * skill_faces[MAX_SKILLS]
Will contain the face numbers for the skills, initialized by init_skill().
Definition: skill_util.cpp:61
sstring skill_messages[MAX_SKILLS]
Will contain the message for the skills, initialized by init_skill().
Definition: skill_util.cpp:67
void SockList_AddShort(SockList *sl, uint16_t data)
Adds a 16 bit value.
Definition: lowlevel.cpp:116
Socket structure, represents a client-server connection.
Definition: newserver.h:93
void send_file(socket_struct *ns, const char *file)
Sends the desired file to the client.
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 16 bit length field.
Definition: lowlevel.cpp:191
#define CS_STAT_DEX
Definition: newclient.h:98
Object for applying character class modifications to someone.
Definition: object.h:143
static void send_arch_info(SockList *sl, const object *op)
This sends information about object op to client - used in response to requestinfo.
static void build_class_list_reply(SockList *sl)
Creates the appropriate reply to the &#39;class_list&#39; request info.
uint8_t starting_stat_max
Maximum value of a starting stat.
Definition: global.h:322
void send_new_char_info(socket_struct *ns)
Sends information related to creating a new character to the client.
#define CS_STAT_WIS
Definition: newclient.h:97
void send_race_info(socket_struct *ns, char *params)
Sends information on specified race to the client.
Global type definitions and header inclusions.
int8_t Con
Use
Definition: living.h:36
char * host
Which host it is connected from (ip address).
Definition: newserver.h:104
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:274
#define MAP_TYPE_CHOICE
Choice of maps presented to player.
Definition: map.h:61
AssetsManager * getManager()
Definition: assets.cpp:309
const char * news
Name of news file.
Definition: global.h:281
const char *const spellpathnames[NRSPELLPATHS]
Perhaps not the best place for this, but needs to be in some file in the common area so that standalo...
Definition: init.cpp:236
void SockList_AddData(SockList *sl, const void *data, size_t len)
Adds a data block.
Definition: lowlevel.cpp:167
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Simple function we use below to keep adding to the same string but also make sure we don&#39;t overwrite ...
Definition: porting.cpp:202
int8_t Dex
Use
Definition: living.h:36
int8_t Wis
Use
Definition: living.h:36
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
int64_t * levels
Number of levels for which we have experience.
Definition: exp.cpp:26
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
Archetypes * archetypes()
Get archetypes.
Definition: AssetsManager.h:44
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.cpp:157
void send_map_info(socket_struct *ns)
Send information on available start maps.
Defines various structures and values that are used for the new client server communication method...
#define CS_STAT_CHA
Definition: newclient.h:100
Defines and structures related to commands the player can send.
struct Settings settings
Global settings.
Definition: init.cpp:139
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.cpp:246
#define AddShortAttr(New, Type)
uint16_t number
This is the image unique identifier.
Definition: face.h:15
void send_spell_paths(socket_struct *ns)
This sends the spell path to name mapping.
void send_class_list(socket_struct *ns)
Sends the list of classes to the client.
#define CS_STAT_STR
Definition: newclient.h:95
living stats
Str, Con, Dex, etc.
Definition: object.h:378
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define NRSPELLPATHS
Number of spell paths.
Definition: spells.h:40
void send_class_info(socket_struct *ns, char *params)
Send information on the specified class.
const char * confdir
Configuration files.
Definition: global.h:248
void SockList_AddChar(SockList *sl, unsigned char c)
Adds an 8 bit value.
Definition: lowlevel.cpp:106
void send_skill_info(socket_struct *ns, char *params)
This sends the skill number to name mapping.
Definition: requestinfo.cpp:71
See Player.
Definition: object.h:112
static event_registration m
Definition: citylife.cpp:424
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Sends a face to a client if they are in pixmap mode, nothing gets sent in bitmap mode.
Definition: image.cpp:72
uint8_t starting_stat_points
How many stat points character starts with.
Definition: global.h:323
sstring name
The name of the object, obviously...
Definition: object.h:319
int8_t Cha
Use
Definition: living.h:36
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 8 bit length field.
Definition: lowlevel.cpp:179
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
int8_t Pow
Use
Definition: living.h:36
C function wrappers to interact with assets.
#define CS_STAT_POW
Definition: newclient.h:112
StringBuffer * buf
Definition: readable.cpp:1563
Structure containing object statistics.
uint8_t subtype
Subtype of object.
Definition: object.h:349
#define MAX_SKILLS
This is the maximum number of skills the game may handle.
Definition: skills.h:70
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:721
void SockList_AddInt64(SockList *sl, uint64_t data)
Adds a 64 bit value.
Definition: lowlevel.cpp:140
int8_t Int
Use
Definition: living.h:36
#define CS_STAT_CON
Definition: newclient.h:99
#define CS_STAT_SKILLINFO
CS_STAT_SKILLINFO is used as the starting index point.
Definition: newclient.h:176
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:100
object clone
An object from which to do object_copy()
Definition: object.h:487
void send_exp_table(socket_struct *ns)
This sends the experience table the sever is using.
int8_t Str
Use
Definition: living.h:36
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447
void each(std::function< void(T *)> op)
Apply a function to each asset.