Crossfire Server, Trunk  R20513
requestinfo.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 
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 
53 /* Note that following protocol commands (was corresponding function)
54  * are in image.c and not this file, even though they are requestinfo
55  * commands:
56  * image_sums -> send_image_sums()
57  * image_info -> send_image_info()
58  *
59  * The order of the functions here is basically the order they
60  * are called in from request_info_cmd() from loop.c
61  */
62 
67 void send_skill_info(socket_struct *ns, char *params) {
68  SockList sl;
69  int i;
70 
71  SockList_Init(&sl);
72  SockList_AddString(&sl, "replyinfo skill_info\n");
73  for (i = 1; i < NUM_SKILLS; i++) {
74  size_t len;
75 
76  len = 16+strlen(skill_names[i]); /* upper bound for length */
77  if (SockList_Avail(&sl) < len) {
78  LOG(llevError, "Buffer overflow in send_skill_info, not sending all skill information\n");
79  break;
80  }
81 
82  if (params != NULL && *params == '1') {
83  if ((skill_faces[i] != -1) && !(ns->faces_sent[skill_faces[i]]&NS_FACESENT_FACE))
84  esrv_send_face(ns, skill_faces[i], 0);
85  SockList_AddPrintf(&sl, "%d:%s:%d\n", i+CS_STAT_SKILLINFO, skill_names[i], skill_faces[i]);
86  } else
87  SockList_AddPrintf(&sl, "%d:%s\n", i+CS_STAT_SKILLINFO, skill_names[i]);
88  }
89  Send_With_Handling(ns, &sl);
90  SockList_Term(&sl);
91 }
92 
97 void send_spell_paths(socket_struct *ns, char *params) {
98  SockList sl;
99  int i;
100 
101  SockList_Init(&sl);
102  SockList_AddString(&sl, "replyinfo spell_paths\n");
103  for (i = 0; i < NRSPELLPATHS; i++) {
104  size_t len;
105 
106  len = 16+strlen(spellpathnames[i]); /* upper bound for length */
107  if (SockList_Avail(&sl) < len) {
108  LOG(llevError, "Buffer overflow in send_spell_paths, not sending all spell information\n");
109  break;
110  }
111 
112  SockList_AddPrintf(&sl, "%d:%s\n", 1<<i, spellpathnames[i]);
113  }
114  Send_With_Handling(ns, &sl);
115  SockList_Term(&sl);
116 }
117 
121 void send_exp_table(socket_struct *ns, char *params) {
122  SockList sl;
123  int i;
124  extern int64_t *levels;
125 
126  SockList_Init(&sl);
127  SockList_AddString(&sl, "replyinfo exp_table\n");
129  for (i = 1; i <= settings.max_level; i++) {
130  if (SockList_Avail(&sl) < 8) {
131  LOG(llevError, "Buffer overflow in send_exp_table, not sending all information\n");
132  break;
133  }
134  SockList_AddInt64(&sl, levels[i]);
135  }
136  Send_With_Handling(ns, &sl);
137  SockList_Term(&sl);
138 }
139 
140 /* This is like the AddIf... routines, but instead of
141  * checking against another value which we overwrite,
142  * we just check against 0.
143  */
144 #define AddShortAttr(New, Type) \
145  if (New) { \
146  SockList_AddChar(sl, Type); \
147  SockList_AddShort(sl, New); \
148  }
149 
160 static void send_arch_info(SockList *sl, const object *op)
161 {
162  if (op->name) {
163  SockList_AddString(sl, "name ");
164  SockList_AddLen8Data(sl, op->name, strlen(op->name));
165  }
166 
167  /* It is conceivable some may lack messages */
168  if (op->msg) {
169  SockList_AddString(sl, "msg ");
170  SockList_AddShort(sl, strlen(op->msg));
171  SockList_AddData(sl, op->msg, strlen(op->msg));
172  }
173 
174  SockList_AddString(sl, "stats ");
175  /* Only send non zero stats. More stats could be added here,
176  * but ideally, the text description (op->msg) should give information
177  * about resistances and other abilities.
178  * Send stats last - if the client gets a stat it does not understand,
179  * it stops processing this replyinfo.
180  */
188 
189  /* Terminator for the stats line */
190  SockList_AddChar(sl, 0);
191 
192  /* Handle any race/class_choice options -
193  * the code is exactly the same, except for
194  * name of field we are looking for.
195  */
196  if (op->type == CLASS || op->type == PLAYER) {
197  int i=1;
198  char buf[MAX_BUF];
199  const char *value, *value1;
200  char *lasts, *mychoices, *token;
201 
202  while (1) {
203  if (op->type == PLAYER) {
204  snprintf(buf, MAX_BUF, "race_choice_description_%d", i);
205  value = object_get_value(op, buf);
206  snprintf(buf, MAX_BUF, "race_choice_%d", i);
207  value1 = object_get_value(op, buf);
208  } else { /* Must be class */
209  snprintf(buf, MAX_BUF, "class_choice_description_%d", i);
210  value = object_get_value(op, buf);
211  snprintf(buf, MAX_BUF, "class_choice_%d", i);
212  value1 = object_get_value(op, buf);
213  }
214 
215  if (value && value1) {
216  SockList_AddString(sl, "choice ");
217  SockList_AddLen8Data(sl, buf, strlen(buf));
218  SockList_AddLen8Data(sl, value, strlen(value));
219  i++;
220  /* value1 now contains a list of archetypes */
221  /* Following operations modify string */
222  mychoices = strdup_local(value1);
223 
224  /* split_string() requires we have some
225  * idea on number of fields - in this case,
226  * we really have no idea - one could conceive
227  * of a choice of 50 weapons - using strtok_r
228  * is just as safe and will scale to any amount.
229  */
230  token = strtok_r(mychoices, " ", &lasts);
231  while (token) {
232  archetype *arch;
233 
234  arch = try_find_archetype(token);
235  if (arch) {
236  SockList_AddLen8Data(sl, token, strlen(token));
237  SockList_AddLen8Data(sl, arch->clone.name,
238  strlen(arch->clone.name));
239  } else {
240  LOG(llevError, "send_arch_info: Unable to find archetype %s\n", token);
241  }
242  token = strtok_r(NULL, " ", &lasts);
243  }
244  free(mychoices);
245  /* Terminator byte */
246  SockList_AddChar(sl, 0);
247  } else {
248  break;
249  }
250  }
251  }
252 
253 
254  /* Any addition to data to send should be at the end of the
255  * function - in other words, the order of data sent here should
256  * match order of addition. In that way, the newest additions are
257  * sent last, so client can process this data until it gets
258  * something it does not understand - if new data (subfields in the
259  * replyinfo) are sent first, the client basically has to stop
260  * processing once it gets something it does not understand.
261  */
262 
263 }
264 
271 static void build_race_list_reply(SockList *sl) {
272  archetype *race;
273 
274  SockList_AddString(sl, "replyinfo race_list ");
275 
276  for (race = first_archetype; race; race = race->next) {
277  if (race->clone.type == PLAYER) {
278  SockList_AddPrintf(sl, "|%s", race->name);
279  }
280  }
281 }
282 
292 void send_race_list(socket_struct *ns, char *params) {
293  static SockList sl;
294  static int sl_initialized = 0;
295 
296  if (!sl_initialized) {
297  sl_initialized = 1;
298  SockList_Init(&sl);
300  }
301 
302  Send_With_Handling(ns, &sl);
303 }
304 
313 void send_race_info(socket_struct *ns, char *params) {
314  archetype *race = try_find_archetype(params);
315  SockList sl;
316 
317  SockList_Init(&sl);
318  SockList_AddPrintf(&sl, "replyinfo race_info %s\n", params);
319 
320  /* do not let the client arbitrarily request information about
321  * any archetype, so put a check in here for the right clone type.
322  */
323  if (race && race->clone.type == PLAYER) {
324  send_arch_info(&sl, &race->clone);
325  }
326 
327  Send_With_Handling(ns, &sl);
328  SockList_Term(&sl);
329 }
330 
338  archetype *cl;
339 
340  SockList_Reset(sl);
341  SockList_AddString(sl, "replyinfo class_list ");
342 
343  for (cl = first_archetype; cl; cl = cl->next) {
344  if (cl->clone.type == CLASS) {
345  SockList_AddPrintf(sl, "|%s", cl->name);
346  }
347  }
348 }
349 
359 void send_class_list(socket_struct *ns, char *params) {
360  static SockList sl;
361  static int sl_initialized = 0;
362 
363  if (!sl_initialized) {
364  sl_initialized = 1;
365  SockList_Init(&sl);
367  }
368 
369  Send_With_Handling(ns, &sl);
370 }
371 
380 void send_class_info(socket_struct *ns, char *params) {
381  archetype *class = try_find_archetype(params);
382  SockList sl;
383 
384  SockList_Init(&sl);
385  SockList_AddPrintf(&sl, "replyinfo class_info %s\n", params);
386 
387  /* do not let the client arbitrarily request information about
388  * any archetype, so put a check in here for the right clone type.
389  */
390  if (class && class->clone.type == CLASS) {
391  send_arch_info(&sl, &class->clone);
392  }
393 
394  Send_With_Handling(ns, &sl);
395  SockList_Term(&sl);
396 }
397 
405  archetype *m;
406  SockList sl;
407 
408  SockList_Init(&sl);
409  SockList_AddPrintf(&sl, "replyinfo startingmap\n");
410 
411  for (m = first_archetype; m; m = m->next) {
412  if (m->clone.type == MAP && m->clone.subtype == MAP_TYPE_CHOICE) {
414  SockList_AddLen16Data(&sl, m->name, strlen(m->name));
415 
417  SockList_AddLen16Data(&sl, m->clone.name, strlen(m->clone.name));
418 
419  /* In theory, this should always be set, but better not to crash
420  * if it is not.
421  */
422  if (m->clone.msg) {
424  SockList_AddLen16Data(&sl, m->clone.msg, strlen(m->clone.msg));
425  }
426  }
427  }
428 
429  Send_With_Handling(ns, &sl);
430  SockList_Term(&sl);
431 }
432 
443 void send_file(socket_struct *ns, const char *file) {
444  char buf[MAX_BUF];
445  FILE *fp;
446  SockList sl;
447 
448  if (!strcmp(file,"motd"))
449  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
450  else if (!strcmp(file,"rules"))
451  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
452  else if (!strcmp(file,"news"))
453  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
454  else {
455  LOG(llevError,"send_file requested to send unknown file: %s\n", file);
456  return;
457  }
458  fp = fopen(buf, "r");
459  if (fp == NULL)
460  return;
461  SockList_Init(&sl);
462  SockList_AddString(&sl, "replyinfo ");
463  SockList_AddString(&sl, file);
464  SockList_AddString(&sl, "\n");
465 
466  while (fgets(buf, MAX_BUF, fp) != NULL) {
467  if (*buf == '#')
468  continue;
469  SockList_AddString(&sl, buf);
470  }
471  fclose(fp);
472  SockList_AddChar(&sl, 0); /* Null terminate it */
473  Send_With_Handling(ns, &sl);
474  SockList_Term(&sl);
475 }
476 
485  char buf[MAX_BUF];
486  int i;
487  size_t len;
488  SockList sl;
489 
490  SockList_Init(&sl);
491 
492  SockList_AddString(&sl, "replyinfo newcharinfo\n");
493  snprintf(buf, MAX_BUF, "V points %d", settings.starting_stat_points);
494  /* We add +1 to the length so that the null (terminator) byte
495  * gets included - this make processing on the client side easier.
496  */
497  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
498 
499  snprintf(buf, MAX_BUF, "V statrange %d %d",
501  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
502 
503  snprintf(buf, MAX_BUF, "V statname");
504  len = strlen(buf);
505  for (i=0; i<NUM_STATS; i++) {
506  safe_strcat(buf, " ", &len, MAX_BUF);
507  safe_strcat(buf, short_stat_name[i], &len, MAX_BUF);
508  }
509 
510  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
511 
512  snprintf(buf, MAX_BUF, "R race requestinfo");
513  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
514 
515  snprintf(buf, MAX_BUF, "R class requestinfo");
516  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
517 
518  snprintf(buf, MAX_BUF, "O startingmap requestinfo");
519  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
520 
521  Send_With_Handling(ns, &sl);
522  SockList_Term(&sl);
523 }
Error, serious thing.
Definition: logger.h:11
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.c:194
const char * rules
Name of rules file.
Definition: global.h:276
int8_t Int
Definition: living.h:35
Sound-related defines.
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.c:66
#define INFO_MAP_ARCH_NAME
Definitions for the requestion/replyinfo map data.
Definition: newclient.h:673
void esrv_send_face(socket_struct *ns, uint16_t face_num, int nocache)
Sends a face to a client if they are in pixmap mode, nothing gets sent in bitmap mode.
Definition: image.c:70
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:149
Definition: object.h:125
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.c:48
uint8_t starting_stat_min
Minimum value of a starting stat.
Definition: global.h:318
#define CS_STAT_INT
Definition: newclient.h:92
#define strdup_local
Definition: compat.h:25
Defines various flags that both the new client and new server use.
char motd[MAX_BUF]
Name of the motd file.
Definition: global.h:275
int16_t max_level
This is read out of exp_table.
Definition: global.h:300
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.c:4246
static void send_arch_info(SockList *sl, const object *op)
This sends information about object op to client - used in response to requestinfo.
Definition: requestinfo.c:160
void SockList_AddShort(SockList *sl, uint16_t data)
Adds a 16 bit value.
Definition: lowlevel.c:108
Socket structure, represents a client-server connection.
Definition: newserver.h:99
object clone
An object from which to do object_copy()
Definition: object.h:470
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 16 bit length field.
Definition: lowlevel.c:183
void send_skill_info(socket_struct *ns, char *params)
This sends the skill number to name mapping.
Definition: requestinfo.c:67
#define CS_STAT_DEX
Definition: newclient.h:94
Object for applying character class modifications to someone.
Definition: object.h:138
const char * skill_names[NUM_SKILLS]
Will contain a number-name mapping for skills, initialized by init_skills().
Definition: skill_util.c:57
void send_spell_paths(socket_struct *ns, char *params)
This sends the spell path to name mapping.
Definition: requestinfo.c:97
uint8_t subtype
Subtype of object.
Definition: object.h:339
#define INFO_MAP_NAME
Proper name of this entry.
Definition: newclient.h:674
void send_map_info(socket_struct *ns)
Send information on the specified class.
Definition: requestinfo.c:404
uint8_t starting_stat_max
Maximum value of a starting stat.
Definition: global.h:319
void send_race_list(socket_struct *ns, char *params)
Send the list of player races to the client.
Definition: requestinfo.c:292
#define CS_STAT_WIS
Definition: newclient.h:93
#define INFO_MAP_DESCRIPTION
Description of this map.
Definition: newclient.h:675
Global type definitions and header inclusions.
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
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.c:120
int8_t Con
Definition: living.h:35
void send_new_char_info(socket_struct *ns)
Sends information related to creating a new character to the client.
Definition: requestinfo.c:484
const char * news
Name of news file.
Definition: global.h:277
#define strtok_r(x, y, z)
Definition: win32.h:62
void SockList_AddData(SockList *sl, const void *data, size_t len)
Adds a data block.
Definition: lowlevel.c:159
void send_file(socket_struct *ns, const char *file)
Sends the desired file to the client.
Definition: requestinfo.c:443
int8_t Wis
Definition: living.h:35
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.c:58
#define snprintf
Definition: win32.h:46
const char * name
The name of the object, obviously...
Definition: object.h:311
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.c:149
int8_t Cha
Definition: living.h:35
Defines various structures and values that are used for the new client server communication method...
Number of statistics.
Definition: living.h:18
#define CS_STAT_CHA
Definition: newclient.h:96
Defines and structures related to commands the player can send.
void send_class_list(socket_struct *ns, char *params)
Sends the list of classes to the client.
Definition: requestinfo.c:359
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.c:238
archetype * try_find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:666
#define CS_STAT_STR
Definition: newclient.h:91
#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_race_info(socket_struct *ns, char *params)
Sends information on specified race to the client.
Definition: requestinfo.c:313
#define NUM_SKILLS
This is the highest number skill in the table +1 This is used to store pointers to the actual skills ...
Definition: skills.h:71
const char * confdir
Configuration files.
Definition: global.h:243
void SockList_AddChar(SockList *sl, char c)
Adds an 8 bit value.
Definition: lowlevel.c:98
#define AddShortAttr(New, Type)
Definition: requestinfo.c:144
signed __int64 int64_t
Definition: win32.h:168
int8_t Str
Definition: living.h:35
See Player.
Definition: object.h:107
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.c:346
void send_exp_table(socket_struct *ns, char *params)
This sends the experience table the sever is using.
Definition: requestinfo.c:121
int skill_faces[NUM_SKILLS]
Will contain the face numbers for the skills, initialized by init_skill().
Definition: skill_util.c:61
living stats
Str, Con, Dex, etc.
Definition: object.h:368
uint8_t starting_stat_points
How many stat points character starts with.
Definition: global.h:320
int8_t Dex
Definition: living.h:35
#define MAP_TYPE_CHOICE
Choice of maps presented to player.
Definition: map.h:59
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
struct Settings settings
Server settings.
Definition: init.c:40
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 8 bit length field.
Definition: lowlevel.c:171
struct archt * next
Next archetype in a linked list.
Definition: object.h:467
const char * msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
int64_t * levels
Number of levels for which we have experience.
Definition: exp.c:26
int8_t Pow
Definition: living.h:35
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
static void build_race_list_reply(SockList *sl)
Creates the appropriate reply to the &#39;race_list&#39; request info.
Definition: requestinfo.c:271
#define CS_STAT_POW
Definition: newclient.h:108
Structure containing object statistics.
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:680
void SockList_AddInt64(SockList *sl, uint64_t data)
Adds a 64 bit value.
Definition: lowlevel.c:132
#define CS_STAT_CON
Definition: newclient.h:95
static void build_class_list_reply(SockList *sl)
Creates the appropriate reply to the &#39;class_list&#39; request info.
Definition: requestinfo.c:337
const char *const short_stat_name[NUM_STATS]
Short name of stats.
Definition: living.c:194
void send_class_info(socket_struct *ns, char *params)
Send information on the specified class.
Definition: requestinfo.c:380
EXTERN archetype * first_archetype
First archetype.
Definition: global.h:122
#define CS_STAT_SKILLINFO
CS_STAT_SKILLINFO is used as the starting index point.
Definition: newclient.h:168
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:106
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.c:542