Crossfire Server, Trunk
init.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 include files */
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 /* win32 */
43 
44 #include "image.h"
45 #include "newserver.h"
46 #include "sproto.h"
47 
50 
59 
60 static void set_output_sock_buf(socket_struct *ns, int bufsize) {
61  int oldbufsize;
62  socklen_t buflen = sizeof(oldbufsize);
63  if (getsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&oldbufsize, &buflen) == -1)
64  oldbufsize = 0;
65  if (oldbufsize < bufsize) {
66 #ifdef ESRV_DEBUG
67  LOG(llevDebug, "Default buffer size was %d bytes, will reset it to %d\n", oldbufsize, bufsize);
68 #endif
69  if (setsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize))) {
70  LOG(llevError, "init_connection: setsockopt unable to set output buf size to %d\n", bufsize);
71  }
72  }
73  buflen = sizeof(oldbufsize);
74  getsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&oldbufsize, &buflen);
75 #ifdef ESRV_DEBUG
76  LOG(llevDebug, "Socket buffer size now %d bytes\n", oldbufsize);
77 #endif
78 }
79 
85 void init_connection(socket_struct *ns, const char *from_ip) {
86  SockList sl;
87 
88 #ifdef WIN32 /* ***WIN32 SOCKET: init win32 non blocking socket */
89 #ifdef CF_MXE_CROSS_COMPILE
90  u_long temp = 1;
91 #else
92  long temp = 1;
93 #endif
94 
95  if (ioctlsocket(ns->fd, FIONBIO , &temp) == -1)
96  LOG(llevError, "init_connection: Error on ioctlsocket.\n");
97 #else
98  if (fcntl(ns->fd, F_SETFL, O_NONBLOCK) == -1) {
99  LOG(llevError, "init_connection: Error on fcntl.\n");
100  }
101 #endif /* end win32 */
102 
104 
105  ns->faceset = 0;
106  ns->facecache = 0;
107  ns->sound = 0;
108  ns->sounds_this_tick = 0;
109  ns->monitor_spells = 0;
110  ns->darkness = 1;
111  ns->status = Ns_Add;
112  ns->mapx = 11;
113  ns->mapy = 11;
114  ns->look_position = 0;
115  ns->container_position = 0;
116  ns->update_look = 0;
117  ns->update_inventory = 0;
118  ns->tick = 0;
119  ns->is_bot = 0;
121  ns->want_pickup = 0;
122  ns->extended_stats = 0;
124  if (ns->account_chars) {
126  ns->account_chars = NULL;
127  }
128  ns->login_method = 0;
129  ns->notifications = 0;
130  ns->heartbeat = 0;
131 
132  /* we should really do some checking here - if total clients overflows
133  * we need to do something more intelligent, because client id's will start
134  * duplicating (not likely in normal cases, but malicous attacks that
135  * just open and close connections could get this total up.
136  */
137  SockList_Init(&ns->inbuf);
139  /* Basic initialization. Needed because we do a check in
140  * handle_client for oldsocketmode without checking the
141  * length of data.
142  */
143  memset(ns->inbuf.buf, 0, sizeof(ns->inbuf.buf));
144  memset(&ns->lastmap, 0, sizeof(struct Map));
145  free(ns->faces_sent);
146  ns->faces_sent = static_cast<uint8_t *>(calloc(sizeof(*ns->faces_sent), get_faces_count()));
148 
149  memset(&ns->anims_sent, 0, sizeof(ns->anims_sent));
150  memset(&ns->stats, 0, sizeof(struct statsinfo));
151  ns->map_scroll_x = 0;
152  ns->map_scroll_y = 0;
153  /* Do this so we don't send a face command for the client for
154  * this face. Face 0 is sent to the client to say clear
155  * face information.
156  */
157  ns->faces_sent[0] = NS_FACESENT_FACE;
158 
159  ns->password_fails = 0;
160 
161  free(ns->host);
162  ns->host = strdup_local(from_ip);
163  SockList_Init(&sl);
164  SockList_AddPrintf(&sl, "version %d %d %s\n", VERSION_CS, VERSION_SC, VERSION_INFO);
165  Send_With_Handling(ns, &sl);
166  SockList_Term(&sl);
167 #ifdef CS_LOGSTATS
172 #endif
173 }
174 
182  struct linger linger_opt;
183  char buf1[MAX_BUF], buf2[MAX_BUF];
184 
185  if (ns == NULL || ns->listen == NULL) {
186  LOG(llevError, "init_listening_socket: missing listen info in socket_struct?!\n");
188  }
189 
190  ns->status = Ns_Dead;
191 
192  ns->fd = socket(ns->listen->family, ns->listen->socktype, ns->listen->protocol);
193  if (ns->fd == -1) {
194  LOG(llevError, "Cannot create socket: %s\n", strerror(errno));
195  return;
196  }
197 
198  linger_opt.l_onoff = 0;
199  linger_opt.l_linger = 0;
200  if (setsockopt(ns->fd, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, sizeof(struct linger))) {
201  LOG(llevError, "Cannot setsockopt(SO_LINGER): %s\n", strerror(errno));
202  }
203 /* Would be nice to have an autoconf check for this. It appears that
204  * these functions are both using the same calling syntax, just one
205  * of them needs extra valus passed.
206  */
207 #if defined(__osf__) || defined(hpux) || defined(sgi) || defined(NeXT) || \
208  defined(__sun__) || defined(__linux__) || defined(SVR4) || \
209  defined(__FreeBSD__) || defined(__OpenBSD__) || \
210  defined(WIN32) /* ---win32 add this here */ || \
211  defined(__GNU__) /* HURD */
212  {
213 #ifdef WIN32
214  char tmp = 1;
215 #else
216  int tmp = 1;
217 #endif
218 
219  if (setsockopt(ns->fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp))) {
220  LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
221  }
222 #ifdef HAVE_GETADDRINFO
223  if ((ns->listen->family == AF_INET6) && setsockopt(ns->fd, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp))) {
224  LOG(llevError, "Cannot setsockopt(IPV6_V6ONLY): %s\n", strerror(errno));
225  }
226 #endif
227  }
228 #else
229  if (setsockopt(ns->fd, SOL_SOCKET, SO_REUSEADDR, (char *)NULL, 0)) {
230  LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
231  }
232 #endif
233 
234  if (bind(ns->fd, ns->listen->addr, ns->listen->addrlen) == (-1)) {
235 #ifdef HAVE_GETNAMEINFO
236  getnameinfo(ns->listen->addr, ns->listen->addrlen, buf1, sizeof(buf1), buf2, sizeof(buf2), NI_NUMERICHOST|NI_NUMERICSERV);
237 #else
238  short port;
239  long ip;
240 
241  ip = ntohl(((struct sockaddr_in *)ns->listen->addr)->sin_addr.s_addr);
242  port = ntohs(((struct sockaddr_in *)ns->listen->addr)->sin_port);
243  snprintf(buf1, sizeof(buf1), "%ld.%ld.%ld.%ld", (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, ip&255);
244  snprintf(buf2, sizeof(buf2), "%d", port&65535);
245 #endif
246  LOG(llevError, "Cannot bind socket to [%s]:%s: %s\n", buf1, buf2, strerror(errno));
247 #ifdef WIN32 /* ***win32: close() -> closesocket() */
248  shutdown(ns->fd, SD_BOTH);
249  closesocket(ns->fd);
250 #else
251  close(ns->fd);
252 #endif /* win32 */
253  ns->fd = -1;
254  return;
255  }
256  if (listen(ns->fd, 5) == (-1)) {
257  LOG(llevError, "Cannot listen on socket: %s\n", strerror(errno));
258 #ifdef WIN32 /* ***win32: close() -> closesocket() */
259  shutdown(ns->fd, SD_BOTH);
260  closesocket(ns->fd);
261 #else
262  close(ns->fd);
263 #endif /* win32 */
264  ns->fd = -1;
265  return;
266  }
267  ns->status = Ns_Add;
268 }
269 
272 void init_server(void) {
273  int i, e, listen_socket_count;
274 #ifdef HAVE_GETADDRINFO
275  struct addrinfo *ai, *ai_p;
276  struct addrinfo hints;
277  char buf[MAX_BUF];
278 #else
279  struct sockaddr_in *insock;
280  struct protoent *protox;
281 #endif
282 
283 #ifdef WIN32 /* ***win32 - we init a windows socket */
284  WSADATA w;
285 
286  socket_info.max_filedescriptor = 1; /* used in select, ignored in winsockets */
287  WSAStartup(0x0101, &w); /* this setup all socket stuff */
288  /* ill include no error tests here, winsocket 1.1 should always work */
289  /* except some old win95 versions without tcp/ip stack */
290 #else /* non windows */
291 
292 #ifdef HAVE_SYSCONF
293  socket_info.max_filedescriptor = sysconf(_SC_OPEN_MAX);
294 #else
295 # ifdef HAVE_GETDTABLESIZE
296  socket_info.max_filedescriptor = getdtablesize();
297 # else
298 #error "Unable to find usable function to get max filedescriptors"
299 # endif
300 #endif
301 #endif /* win32 */
302 
303  /*
304  * There is a bug on FreeBSD 9 in that the value we get here is over 1024,
305  * which is the limit FD_ZERO and friends will use.
306  * So later on file descriptors are not correctly cleared, and select() fails.
307  * Therefore here's a hack to prevent that, but the real solution would be
308  * to figure why this happens and how to fix it.
309  * Nicolas W, 2012 feb 07.
310  */
311  if (socket_info.max_filedescriptor > 1024) {
312  LOG(llevDebug, "warning, socket_info.max_filedescriptor is %d, setting to 1024.\n", socket_info.max_filedescriptor);
314  }
315  /* end of hack */
316 
317  socket_info.timeout.tv_sec = 0;
318  socket_info.timeout.tv_usec = 0;
319 
320 #ifdef CS_LOGSTATS
321  memset(&cst_tot, 0, sizeof(CS_Stats));
322  memset(&cst_lst, 0, sizeof(CS_Stats));
323  cst_tot.time_start = time(NULL);
324  cst_lst.time_start = time(NULL);
325 #endif
326 
327 #ifdef HAVE_GETADDRINFO
328  memset(&hints, '\0', sizeof(hints));
329  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
330  hints.ai_socktype = SOCK_STREAM;
331  snprintf(buf, sizeof(buf), "%d", settings.csport);
332  e = getaddrinfo(NULL, buf, &hints, &ai);
333  if (e != 0) {
334  LOG(llevError, "init_server: getaddrinfo: %s\n", gai_strerror(e));
336  }
337 
338  listen_socket_count = 0;
339  for (ai_p = ai; ai_p != NULL; ai_p = ai_p->ai_next) {
340  listen_socket_count++;
341  }
342 
343  assert(listen_socket_count > 0);
344 #else
345  listen_socket_count = 1;
346 #endif
347 
348  LOG(llevDebug, "Initialize new client/server data\n");
349  init_sockets = static_cast<socket_struct *>(malloc(sizeof(socket_struct) * listen_socket_count));
350  socket_info.allocated_sockets = listen_socket_count;
351  for (i = 0; i < listen_socket_count; i++) {
352  init_sockets[i].listen = static_cast<listen_info *>(calloc(sizeof(struct listen_info), 1));
353  init_sockets[i].faces_sent = NULL; /* unused */
354  init_sockets[i].account_name = NULL; /* Must be set to avoid undef behaviour elsewhere. */
355  }
356 
357 #ifdef HAVE_GETADDRINFO
358  for (i = 0, ai_p = ai; i < listen_socket_count && ai_p != NULL; i++, ai_p = ai_p->ai_next) {
359  init_sockets[i].listen->family = ai_p->ai_family;
360  init_sockets[i].listen->socktype = ai_p->ai_socktype;
361  init_sockets[i].listen->protocol = ai_p->ai_protocol;
362  init_sockets[i].listen->addrlen = ai_p->ai_addrlen;
363  init_sockets[i].listen->addr = static_cast<sockaddr *>(malloc(ai_p->ai_addrlen));
364  memcpy(init_sockets[i].listen->addr, ai_p->ai_addr, ai_p->ai_addrlen);
365  }
366  freeaddrinfo(ai);
367 #else
368  protox = getprotobyname("tcp");
369  if (protox == NULL) {
370  LOG(llevError, "init_server: Error getting protox\n");
372  }
373  init_sockets[0].listen->family = PF_INET;
374  init_sockets[0].listen->socktype = SOCK_STREAM;
375  init_sockets[0].listen->protocol = protox->p_proto;
376  insock = static_cast<struct sockaddr_in *>(calloc(sizeof(struct sockaddr_in), 1));
377  insock->sin_family = AF_INET;
378  insock->sin_port = htons(settings.csport);
379  insock->sin_addr.s_addr = htonl(INADDR_ANY);
380  init_sockets[0].listen->addr = (struct sockaddr *) insock;
381  init_sockets[0].listen->addrlen = sizeof(struct sockaddr_in);
382 #endif
383 
384  e = 1;
385  for (i = 0; i < listen_socket_count; i++) {
387  if (init_sockets[i].fd != -1)
388  e = 0;
389  }
390  if (e != 0) {
391  LOG(llevError, "init_server: can't open any listening socket\n");
393  }
394 }
395 
396 /*******************************************************************************
397  *
398  * Start of functions dealing with freeing of the data.
399  *
400  ******************************************************************************/
401 
403 void free_all_newserver(void) {
404  int i;
405  LOG(llevDebug, "Freeing all new client/server information.\n");
406  for (i = 0; i < socket_info.allocated_sockets && init_sockets[i].listen; i++) {
407  free(init_sockets[i].listen->addr);
408  free(init_sockets[i].listen);
409  }
410  free(init_sockets);
411 }
412 
421 #ifdef WIN32 /* ***win32: closesocket in windows style */
422  shutdown(ns->fd, SD_BOTH);
423  if (closesocket(ns->fd)) {
424 #else
425  if (close(ns->fd)) {
426 #endif /* win32 */
427 
428 #ifdef ESRV_DEBUG
429  LOG(llevDebug, "Error closing socket %d\n", ns->fd);
430 #endif
431  }
432  ns->fd = -1;
434  if (ns->stats.range)
436  if (ns->stats.title)
439  FREE_AND_CLEAR(ns->stats.god);
440  if (ns->host)
441  FREE_AND_CLEAR(ns->host);
442  if (ns->account_name) {
445  }
446  if (ns->account_chars) {
449  ns->account_chars = NULL;
450  }
451  SockList_Term(&ns->inbuf);
452 }
453 
456  SockList sl;
457 
458  SockList_Init(&sl);
459  SockList_AddString(&sl, "goodbye");
461  SockList_Term(&sl);
462  // If the player wasn't saved (new for instance), then pl->ob isn't removed,
463  // and the socket is needed for updating inventory. So keep it and free after.
464  socket_struct *socket = pl->socket;
465  free_player(pl);
466  free_newsocket(socket);
467  free(socket);
468 }
socket_struct::tick
uint32_t tick
Definition: newserver.h:106
global.h
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Definition: newserver.h:137
settings
struct Settings settings
Definition: init.cpp:139
socket_struct::heartbeat
bool heartbeat
Definition: newserver.h:112
llevError
@ llevError
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
Map
Definition: newserver.h:48
socket_info
Socket_Info socket_info
Definition: init.cpp:49
socket_struct::container_position
uint16_t container_position
Definition: newserver.h:115
strdup_local
#define strdup_local
Definition: compat.h:29
socket_struct::look_position
uint16_t look_position
Definition: newserver.h:114
listen_info::protocol
int protocol
Definition: newserver.h:78
listen_info
Definition: newserver.h:75
socket_struct::sound
uint32_t sound
Definition: newserver.h:111
socket_struct
Definition: newserver.h:89
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:116
Socket_Info::allocated_sockets
int allocated_sockets
Definition: newserver.h:144
free_all_newserver
void free_all_newserver(void)
Definition: init.cpp:403
socket_struct::num_look_objects
uint8_t num_look_objects
Definition: newserver.h:122
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.cpp:154
pl
Definition: player.h:105
DEFAULT_NUM_LOOK_OBJECTS
#define DEFAULT_NUM_LOOK_OBJECTS
Definition: newserver.h:22
socket_struct::extended_stats
uint32_t extended_stats
Definition: newserver.h:109
init_listening_socket
void init_listening_socket(socket_struct *ns)
Definition: init.cpp:181
socket_struct::update_inventory
uint32_t update_inventory
Definition: newserver.h:105
listen_info::addr
struct sockaddr * addr
Definition: newserver.h:80
Socket_Info::max_filedescriptor
int max_filedescriptor
Definition: newserver.h:143
socket_struct::is_bot
uint32_t is_bot
Definition: newserver.h:107
set_output_sock_buf
static void set_output_sock_buf(socket_struct *ns, int bufsize)
Definition: init.cpp:60
socket_struct::listen
struct listen_info * listen
Definition: newserver.h:92
Ice.tmp
int tmp
Definition: Ice.py:207
listen_info::socktype
int socktype
Definition: newserver.h:77
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
socket_struct::inbuf
SockList inbuf
Definition: newserver.h:99
Settings::csport
uint16_t csport
Definition: global.h:242
socket_struct::map_scroll_x
int8_t map_scroll_x
Definition: newserver.h:94
buf
StringBuffer * buf
Definition: readable.cpp:1611
init_server
void init_server(void)
Definition: init.cpp:272
Socket_Info
Definition: newserver.h:141
socket_struct::update_look
uint32_t update_look
Definition: newserver.h:104
Ns_Dead
@ Ns_Dead
Definition: newserver.h:67
CS_Stats::time_start
time_t time_start
Definition: newclient.h:698
init_sockets
socket_struct * init_sockets
Definition: init.cpp:58
socket_struct::account_chars
Account_Chars * account_chars
Definition: newserver.h:127
socket_struct::mapy
uint8_t mapy
Definition: newserver.h:116
socket_struct::stats
struct statsinfo stats
Definition: newserver.h:98
socklen_t
#define socklen_t
Definition: win32.h:17
socket_struct::facecache
uint32_t facecache
Definition: newserver.h:102
account_char_free
void account_char_free(Account_Chars *chars)
Definition: account_char.cpp:374
statsinfo
Definition: newserver.h:56
socket_struct::lastmap
struct Map lastmap
Definition: newserver.h:93
socket_struct::host
char * host
Definition: newserver.h:100
socket_struct::account_name
char * account_name
Definition: newserver.h:126
socket_struct::monitor_spells
uint32_t monitor_spells
Definition: newserver.h:110
socket_struct::faceset
uint8_t faceset
Definition: newserver.h:117
init_connection
void init_connection(socket_struct *ns, const char *from_ip)
Definition: init.cpp:85
socket_struct::map_scroll_y
int8_t map_scroll_y
Definition: newserver.h:94
statsinfo::title
char * title
Definition: newserver.h:57
sproto.h
VERSION_SC
#define VERSION_SC
Definition: newserver.h:150
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.cpp:52
image.h
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:580
log_login.ip
ip
Definition: log_login.py:6
MAX_BUF
#define MAX_BUF
Definition: define.h:35
Ns_Add
@ Ns_Add
Definition: newserver.h:66
free_newsocket
void free_newsocket(socket_struct *ns)
Definition: init.cpp:420
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.cpp:62
listen_info::family
int family
Definition: newserver.h:76
cst_tot
CS_Stats cst_tot
socket_struct::sounds_this_tick
int8_t sounds_this_tick
Definition: newserver.h:121
socket_struct::want_pickup
uint32_t want_pickup
Definition: newserver.h:108
FREE_AND_CLEAR
#define FREE_AND_CLEAR(xyz)
Definition: global.h:193
Socket_Info::timeout
struct timeval timeout
Definition: newserver.h:142
newserver.h
socket_struct::status
enum Sock_Status status
Definition: newserver.h:90
SOCKETBUFSIZE
#define SOCKETBUFSIZE
Definition: config.h:464
final_free_player
void final_free_player(player *pl)
Definition: init.cpp:455
statsinfo::god
char * god
Definition: newserver.h:57
socket_struct::faces_sent_len
size_t faces_sent_len
Definition: newserver.h:95
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Definition: lowlevel.cpp:80
socket_struct::anims_sent
uint8_t anims_sent[MAXANIMNUM]
Definition: newserver.h:97
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
VERSION_CS
#define VERSION_CS
Definition: newserver.h:149
socket_struct::fd
int fd
Definition: newserver.h:91
socket_struct::login_method
uint8_t login_method
Definition: newserver.h:128
statsinfo::range
char * range
Definition: newserver.h:57
listen_info::addrlen
socklen_t addrlen
Definition: newserver.h:79
socket_struct::darkness
uint32_t darkness
Definition: newserver.h:103
socket_struct::notifications
uint16_t notifications
Definition: newserver.h:129
socket_struct::password_fails
uint8_t password_fails
Definition: newserver.h:101
get_faces_count
size_t get_faces_count()
Definition: assets.cpp:297
cst_lst
CS_Stats cst_lst
Definition: newclient.h:701
SockList::buf
unsigned char buf[MAXSOCKBUF]
Definition: newclient.h:687
guildbuy.temp
def temp
Definition: guildbuy.py:26
account_char_save
void account_char_save(Account_Chars *chars)
Definition: account_char.cpp:179
CS_Stats
Definition: newclient.h:694
pl::socket
socket_struct * socket
Definition: player.h:107
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.cpp:444
SockList
Definition: newclient.h:681
VERSION_INFO
#define VERSION_INFO
Definition: newserver.h:151
llevDebug
@ llevDebug
Definition: logger.h:13
free_player
void free_player(player *pl)
Definition: player.cpp:68
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.cpp:199
account_logout
void account_logout(const char *account_name)
Definition: account.cpp:353
CS_Stats::max_conn
short max_conn
Definition: newclient.h:697