Crossfire Server, Trunk  R20513
init.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 include files */
36 #include <sys/types.h>
37 #include <sys/time.h>
38 #include <netinet/in.h>
39 #include <netdb.h>
40 #endif /* win32 */
41 
42 #include "image.h"
43 #include "newserver.h"
44 #include "sproto.h"
45 
48 
57 
63 void init_connection(socket_struct *ns, const char *from_ip) {
64  SockList sl;
65  int bufsize = 65535; /*Supposed absolute upper limit */
66  int oldbufsize;
67  socklen_t buflen = sizeof(int);
68 
69 #ifdef WIN32 /* ***WIN32 SOCKET: init win32 non blocking socket */
70  int temp = 1;
71 
72  if (ioctlsocket(ns->fd, FIONBIO , &temp) == -1)
73  LOG(llevError, "init_connection: Error on ioctlsocket.\n");
74 #else
75  if (fcntl(ns->fd, F_SETFL, O_NONBLOCK) == -1) {
76  LOG(llevError, "init_connection: Error on fcntl.\n");
77  }
78 #endif /* end win32 */
79 
80  if (getsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&oldbufsize, &buflen) == -1)
81  oldbufsize = 0;
82  if (oldbufsize < bufsize) {
83 #ifdef ESRV_DEBUG
84  LOG(llevDebug, "Default buffer size was %d bytes, will reset it to %d\n", oldbufsize, bufsize);
85 #endif
86  if (setsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize))) {
87  LOG(llevError, "init_connection: setsockopt unable to set output buf size to %d\n", bufsize);
88  }
89  }
90  buflen = sizeof(oldbufsize);
91  getsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&oldbufsize, &buflen);
92 #ifdef ESRV_DEBUG
93  LOG(llevDebug, "Socket buffer size now %d bytes\n", oldbufsize);
94 #endif
95 
96  ns->faceset = 0;
97  ns->facecache = 0;
98  ns->sound = 0;
99  ns->sounds_this_tick = 0;
100  ns->monitor_spells = 0;
101  ns->darkness = 1;
102  ns->status = Ns_Add;
103  ns->mapx = 11;
104  ns->mapy = 11;
105  ns->look_position = 0;
106  ns->container_position = 0;
107  ns->update_look = 0;
108  ns->update_inventory = 0;
109  ns->tick = 0;
110  ns->is_bot = 0;
112  ns->want_pickup = 0;
113  ns->extended_stats = 0;
114  ns->account_name = NULL;
115  ns->account_chars = NULL;
116  ns->login_method = 0;
117  ns->notifications = 0;
118  ns->heartbeat = 0;
119 
120  /* we should really do some checking here - if total clients overflows
121  * we need to do something more intelligent, because client id's will start
122  * duplicating (not likely in normal cases, but malicous attacks that
123  * just open and close connections could get this total up.
124  */
125  SockList_Init(&ns->inbuf);
127  /* Basic initialization. Needed because we do a check in
128  * handle_client for oldsocketmode without checking the
129  * length of data.
130  */
131  memset(ns->inbuf.buf, 0, sizeof(ns->inbuf.buf));
132  memset(&ns->lastmap, 0, sizeof(struct Map));
133  if (!ns->faces_sent)
134  ns->faces_sent = calloc(sizeof(*ns->faces_sent), nrofpixmaps);
136 
137  memset(&ns->anims_sent, 0, sizeof(ns->anims_sent));
138  memset(&ns->stats, 0, sizeof(struct statsinfo));
139  ns->map_scroll_x = 0;
140  ns->map_scroll_y = 0;
141  /* Do this so we don't send a face command for the client for
142  * this face. Face 0 is sent to the client to say clear
143  * face information.
144  */
145  ns->faces_sent[0] = NS_FACESENT_FACE;
146 
147  ns->outputbuffer.start = 0;
148  ns->outputbuffer.len = 0;
149  ns->can_write = 1;
150  ns->password_fails = 0;
151 
152  ns->host = strdup_local(from_ip);
153  SockList_Init(&sl);
154  SockList_AddPrintf(&sl, "version %d %d %s\n", VERSION_CS, VERSION_SC, VERSION_INFO);
155  Send_With_Handling(ns, &sl);
156  SockList_Term(&sl);
157 #ifdef CS_LOGSTATS
158  if (socket_info.allocated_sockets > cst_tot.max_conn)
159  cst_tot.max_conn = socket_info.allocated_sockets;
160  if (socket_info.allocated_sockets > cst_lst.max_conn)
161  cst_lst.max_conn = socket_info.allocated_sockets;
162 #endif
163 }
164 
172  struct linger linger_opt;
173  char buf1[MAX_BUF], buf2[MAX_BUF];
174 
175  if (ns == NULL || ns->listen == NULL) {
176  LOG(llevError, "init_listening_socket: missing listen info in socket_struct?!\n");
178  }
179 
180  ns->status = Ns_Dead;
181 
182  ns->fd = socket(ns->listen->family, ns->listen->socktype, ns->listen->protocol);
183  if (ns->fd == -1) {
184  LOG(llevError, "Cannot create socket: %s\n", strerror(errno));
185  return;
186  }
187 
188  linger_opt.l_onoff = 0;
189  linger_opt.l_linger = 0;
190  if (setsockopt(ns->fd, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, sizeof(struct linger))) {
191  LOG(llevError, "Cannot setsockopt(SO_LINGER): %s\n", strerror(errno));
192  }
193 /* Would be nice to have an autoconf check for this. It appears that
194  * these functions are both using the same calling syntax, just one
195  * of them needs extra valus passed.
196  */
197 #if defined(__osf__) || defined(hpux) || defined(sgi) || defined(NeXT) || \
198  defined(__sun__) || defined(__linux__) || defined(SVR4) || \
199  defined(__FreeBSD__) || defined(__OpenBSD__) || \
200  defined(WIN32) /* ---win32 add this here */ || \
201  defined(__GNU__) /* HURD */
202  {
203 #ifdef WIN32
204  char tmp = 1;
205 #else
206  int tmp = 1;
207 #endif
208 
209  if (setsockopt(ns->fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp))) {
210  LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
211  }
212 #ifdef HAVE_GETADDRINFO
213  if ((ns->listen->family == AF_INET6) && setsockopt(ns->fd, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp))) {
214  LOG(llevError, "Cannot setsockopt(IPV6_V6ONLY): %s\n", strerror(errno));
215  }
216 #endif
217  }
218 #else
219  if (setsockopt(ns->fd, SOL_SOCKET, SO_REUSEADDR, (char *)NULL, 0)) {
220  LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
221  }
222 #endif
223 
224  if (bind(ns->fd, ns->listen->addr, ns->listen->addrlen) == (-1)) {
225 #ifdef HAVE_GETNAMEINFO
226  getnameinfo(ns->listen->addr, ns->listen->addrlen, buf1, sizeof(buf1), buf2, sizeof(buf2), NI_NUMERICHOST|NI_NUMERICSERV);
227 #else
228  short port;
229  long ip;
230 
231  ip = ntohl(((struct sockaddr_in *)ns->listen->addr)->sin_addr.s_addr);
232  port = ntohs(((struct sockaddr_in *)ns->listen->addr)->sin_port);
233  snprintf(buf1, sizeof(buf1), "%ld.%ld.%ld.%ld", (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, ip&255);
234  snprintf(buf2, sizeof(buf2), "%d", port&65535);
235 #endif
236  LOG(llevError, "Cannot bind socket to [%s]:%s: %s\n", buf1, buf2, strerror(errno));
237 #ifdef WIN32 /* ***win32: close() -> closesocket() */
238  shutdown(ns->fd, SD_BOTH);
239  closesocket(ns->fd);
240 #else
241  close(ns->fd);
242 #endif /* win32 */
243  ns->fd = -1;
244  return;
245  }
246  if (listen(ns->fd, 5) == (-1)) {
247  LOG(llevError, "Cannot listen on socket: %s\n", strerror(errno));
248 #ifdef WIN32 /* ***win32: close() -> closesocket() */
249  shutdown(ns->fd, SD_BOTH);
250  closesocket(ns->fd);
251 #else
252  close(ns->fd);
253 #endif /* win32 */
254  ns->fd = -1;
255  return;
256  }
257  ns->status = Ns_Add;
258 }
259 
262 void init_server(void) {
263  int i, e, listen_socket_count;
264 #ifdef HAVE_GETADDRINFO
265  struct addrinfo *ai, *ai_p;
266  struct addrinfo hints;
267  char buf[MAX_BUF];
268 #else
269  struct sockaddr_in *insock;
270  struct protoent *protox;
271 #endif
272 
273 #ifdef WIN32 /* ***win32 - we init a windows socket */
274  WSADATA w;
275 
276  socket_info.max_filedescriptor = 1; /* used in select, ignored in winsockets */
277  WSAStartup(0x0101, &w); /* this setup all socket stuff */
278  /* ill include no error tests here, winsocket 1.1 should always work */
279  /* except some old win95 versions without tcp/ip stack */
280 #else /* non windows */
281 
282 #ifdef HAVE_SYSCONF
283  socket_info.max_filedescriptor = sysconf(_SC_OPEN_MAX);
284 #else
285 # ifdef HAVE_GETDTABLESIZE
286  socket_info.max_filedescriptor = getdtablesize();
287 # else
288  "Unable to find usable function to get max filedescriptors";
289 # endif
290 #endif
291 #endif /* win32 */
292 
293  /*
294  * There is a bug on FreeBSD 9 in that the value we get here is over 1024,
295  * which is the limit FD_ZERO and friends will use.
296  * So later on file descriptors are not correctly cleared, and select() fails.
297  * Therefore here's a hack to prevent that, but the real solution would be
298  * to figure why this happens and how to fix it.
299  * Nicolas W, 2012 feb 07.
300  */
301  if (socket_info.max_filedescriptor > 1024) {
302  LOG(llevDebug, "warning, socket_info.max_filedescriptor is %d, setting to 1024.\n", socket_info.max_filedescriptor);
303  socket_info.max_filedescriptor = 1024;
304  }
305  /* end of hack */
306 
307  socket_info.timeout.tv_sec = 0;
308  socket_info.timeout.tv_usec = 0;
309 
310 #ifdef CS_LOGSTATS
311  memset(&cst_tot, 0, sizeof(CS_Stats));
312  memset(&cst_lst, 0, sizeof(CS_Stats));
313  cst_tot.time_start = time(NULL);
314  cst_lst.time_start = time(NULL);
315 #endif
316 
317 #ifdef HAVE_GETADDRINFO
318  memset(&hints, '\0', sizeof(hints));
319  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
320  hints.ai_socktype = SOCK_STREAM;
321  snprintf(buf, sizeof(buf), "%d", settings.csport);
322  e = getaddrinfo(NULL, buf, &hints, &ai);
323  if (e != 0) {
324  LOG(llevError, "init_server: getaddrinfo: %s\n", gai_strerror(e));
326  }
327 
328  listen_socket_count = 0;
329  for (ai_p = ai; ai_p != NULL; ai_p = ai_p->ai_next) {
330  listen_socket_count++;
331  }
332 
333  assert(listen_socket_count > 0);
334 #else
335  listen_socket_count = 1;
336 #endif
337 
338  LOG(llevDebug, "Initialize new client/server data\n");
339  init_sockets = malloc(sizeof(socket_struct) * listen_socket_count);
340  socket_info.allocated_sockets = listen_socket_count;
341  for (i = 0; i < listen_socket_count; i++) {
342  init_sockets[i].listen = calloc(sizeof(struct listen_info), 1);
343  init_sockets[i].faces_sent = NULL; /* unused */
344  init_sockets[i].account_name = NULL; /* Must be set to avoid undef behaviour elsewhere. */
345  }
346 
347 #ifdef HAVE_GETADDRINFO
348  for (i = 0, ai_p = ai; i < listen_socket_count && ai_p != NULL; i++, ai_p = ai_p->ai_next) {
349  init_sockets[i].listen->family = ai_p->ai_family;
350  init_sockets[i].listen->socktype = ai_p->ai_socktype;
351  init_sockets[i].listen->protocol = ai_p->ai_protocol;
352  init_sockets[i].listen->addrlen = ai_p->ai_addrlen;
353  init_sockets[i].listen->addr = malloc(ai_p->ai_addrlen);
354  memcpy(init_sockets[i].listen->addr, ai_p->ai_addr, ai_p->ai_addrlen);
355  }
356  freeaddrinfo(ai);
357 #else
358  protox = getprotobyname("tcp");
359  if (protox == NULL) {
360  LOG(llevError, "init_server: Error getting protox\n");
362  }
363  init_sockets[0].listen->family = PF_INET;
364  init_sockets[0].listen->socktype = SOCK_STREAM;
365  init_sockets[0].listen->protocol = protox->p_proto;
366  insock = calloc(sizeof(struct sockaddr_in), 1);
367  insock->sin_family = AF_INET;
368  insock->sin_port = htons(settings.csport);
369  insock->sin_addr.s_addr = htonl(INADDR_ANY);
370  init_sockets[0].listen->addr = (struct sockaddr *) insock;
371  init_sockets[0].listen->addrlen = sizeof(struct sockaddr_in);
372 #endif
373 
374  e = 1;
375  for (i = 0; i < listen_socket_count; i++) {
376  init_listening_socket(&init_sockets[i]);
377  if (init_sockets[i].fd != -1)
378  e = 0;
379  }
380  if (e != 0) {
381  LOG(llevError, "init_server: can't open any listening socket\n");
383  }
384 
386 }
387 
388 /*******************************************************************************
389  *
390  * Start of functions dealing with freeing of the data.
391  *
392  ******************************************************************************/
393 
395 void free_all_newserver(void) {
396  int i;
397  LOG(llevDebug, "Freeing all new client/server information.\n");
399  for (i = 0; i < socket_info.allocated_sockets && init_sockets[i].listen; i++) {
400  free(init_sockets[i].listen->addr);
401  free(init_sockets[i].listen);
402  }
403  free(init_sockets);
404 }
405 
414 #ifdef WIN32 /* ***win32: closesocket in windows style */
415  shutdown(ns->fd, SD_BOTH);
416  if (closesocket(ns->fd)) {
417 #else
418  if (close(ns->fd)) {
419 #endif /* win32 */
420 
421 #ifdef ESRV_DEBUG
422  LOG(llevDebug, "Error closing socket %d\n", ns->fd);
423 #endif
424  }
425  ns->fd = -1;
426  if (ns->stats.range)
428  if (ns->stats.title)
430  if (ns->host)
431  FREE_AND_CLEAR(ns->host);
432  if (ns->account_name) {
435  }
436  if (ns->account_chars) {
438  ns->account_chars = NULL;
439  }
440  SockList_Term(&ns->inbuf);
441 }
442 
445  SockList sl;
446 
447  SockList_Init(&sl);
448  SockList_AddString(&sl, "goodbye");
449  Send_With_Handling(&pl->socket, &sl);
450  SockList_Term(&sl);
451  free_newsocket(&pl->socket);
452  free_player(pl);
453 }
Error, serious thing.
Definition: logger.h:11
uint8_t login_method
Login method this client is using.
Definition: newserver.h:140
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.c:194
One player.
Definition: player.h:92
uint8_t faceset
Set the client is using, default 0.
Definition: newserver.h:129
void free_player(player *pl)
Clears player structure, including pointed object (through object_free_drop_inventory()).
Definition: player.c:57
uint32_t tick
Client wishes to get tick commands.
Definition: newserver.h:118
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:149
uint32_t want_pickup
Client wants pickup information when logging in.
Definition: newserver.h:120
char * account_name
Name of the account logged in on this socket.
Definition: newserver.h:138
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.c:48
unsigned char buf[MAXSOCKBUF]
Definition: newclient.h:686
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.c:75
int protocol
Definition: newserver.h:78
#define strdup_local
Definition: compat.h:25
uint16_t look_position
Start of drawing of look window.
Definition: newserver.h:126
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.c:596
uint16_t csport
Port for new client/server.
Definition: global.h:239
struct Map lastmap
Definition: newserver.h:103
Socket structure, represents a client-server connection.
Definition: newserver.h:99
socket_struct socket
Socket information for this player.
Definition: player.h:94
struct sockaddr * addr
Definition: newserver.h:80
bool heartbeat
Client will send hearbeats.
Definition: newserver.h:124
int8_t sounds_this_tick
Number of sounds sent this tick.
Definition: newserver.h:133
uint16_t container_position
Start of container contents to send to client.
Definition: newserver.h:127
enum Sock_Status status
Definition: newserver.h:100
#define socklen_t
Definition: win32.h:130
int max_filedescriptor
max filedescriptor on the system.
Definition: newserver.h:155
void account_char_free(Account_Char *chars)
This frees all data associated with the character information.
Definition: account_char.c:332
void free_newsocket(socket_struct *ns)
Frees a socket.
Definition: init.c:413
Global type definitions and header inclusions.
char * title
Definition: newserver.h:57
int socktype
Definition: newserver.h:77
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
socklen_t addrlen
Definition: newserver.h:79
#define VERSION_SC
Definition: newserver.h:162
uint16_t notifications
Notifications this client wants to get.
Definition: newserver.h:141
size_t faces_sent_len
This is the number of elements allocated in faces_sent[].
Definition: newserver.h:105
void init_server(void)
This sets up the socket and reads all the image information into memory.
Definition: init.c:262
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:115
uint32_t facecache
If true, client is caching images.
Definition: newserver.h:113
buffer_struct outputbuffer
For undeliverable data.
Definition: newserver.h:111
#define DEFAULT_NUM_LOOK_OBJECTS
Default value for the number of objects to send for the &#39;look&#39; window (container or ground view)...
Definition: newserver.h:22
uint32_t sound
Client sound mode.
Definition: newserver.h:123
Account_Char * account_chars
Detailed information on characters on this account.
Definition: newserver.h:139
uint8_t num_look_objects
The maximum number of objects to show on the ground view; this number includes the prev/next group fa...
Definition: newserver.h:134
Holds some system-related information.
Definition: newserver.h:153
void init_listening_socket(socket_struct *ns)
This opens *ns for listening to connections.
Definition: init.c:171
Image-related structures.
CS_Stats cst_lst
Contains the last range/title information sent to client.
Definition: newserver.h:56
void free_all_newserver(void)
Free&#39;s all the memory that ericserver allocates.
Definition: init.c:395
short max_conn
Maximum connections received.
Definition: newclient.h:696
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.c:58
One map for a player.
Definition: newserver.h:48
#define snprintf
Definition: win32.h:46
int8_t map_scroll_y
Definition: newserver.h:104
Contains parameters for socket() and bind() for listening sockets.
Definition: newserver.h:75
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 free_socket_images(void)
Frees all faceset information.
Definition: image.c:572
uint32_t update_inventory
If true, we need to send the inventory list.
Definition: newserver.h:116
#define VERSION_CS
Version >= 1023 understand setup cmd.
Definition: newserver.h:161
void read_client_images(void)
Loads all the image types into memory.
Definition: image.c:448
char * range
Definition: newserver.h:57
int allocated_sockets
Number of allocated items in init_sockets.
Definition: newserver.h:156
uint32_t is_bot
Client shouldn&#39;t be reported to metaserver.
Definition: newserver.h:119
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
uint32_t extended_stats
Client wants base and maximum statistics information.
Definition: newserver.h:121
uint8_t mapx
Definition: newserver.h:128
void init_connection(socket_struct *ns, const char *from_ip)
Initializes a connection.
Definition: init.c:63
uint32_t darkness
True if client wants darkness information.
Definition: newserver.h:114
uint8_t password_fails
How many times the player has failed to give the right password.
Definition: newserver.h:112
Only for debugging purposes.
Definition: logger.h:13
struct timeval timeout
Timeout for select.
Definition: newserver.h:154
void account_char_save(const char *account, Account_Char *chars)
Saves the character information for the given account.
Definition: account_char.c:145
CS_Stats cst_tot
uint8_t anims_sent[MAXANIMNUM]
What animations we sent.
Definition: newserver.h:107
Statistics on server.
Definition: newclient.h:693
struct statsinfo stats
Definition: newserver.h:108
struct Settings settings
Server settings.
Definition: init.c:40
uint32_t monitor_spells
Client wishes to be informed when their spell list changes.
Definition: newserver.h:122
Socket_Info socket_info
Socket information.
Definition: init.c:47
socket_struct * init_sockets
Established connections for clients not yet playing.
Definition: init.c:56
time_t time_start
When we started logging this.
Definition: newclient.h:697
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
int8_t map_scroll_x
Definition: newserver.h:104
int family
Definition: newserver.h:76
void final_free_player(player *pl)
Sends the &#39;goodbye&#39; command to the player, and closes connection.
Definition: init.c:444
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:680
#define VERSION_INFO
Definition: newserver.h:163
#define FREE_AND_CLEAR(xyz)
Free the pointer and then set it to NULL.
Definition: global.h:203
uint8_t mapy
How large a map the client wants.
Definition: newserver.h:128
struct listen_info * listen
Definition: newserver.h:102
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:106
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