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 <netinet/tcp.h>
40 typedef int ssop_t;
41 #include <netdb.h>
42 #else
43 #include <winsock2.h>
44 typedef char ssop_t;
45 #endif /* win32 */
46 
47 #include "image.h"
48 #include "newserver.h"
49 #include "sproto.h"
50 
53 
67 
68 static void set_output_sock_buf(socket_struct *ns, int bufsize) {
69  int oldbufsize;
70  socklen_t buflen = sizeof(oldbufsize);
71  if (getsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&oldbufsize, &buflen) == -1)
72  oldbufsize = 0;
73  if (oldbufsize < bufsize) {
74 #ifdef ESRV_DEBUG
75  LOG(llevDebug, "Default buffer size was %d bytes, will reset it to %d\n", oldbufsize, bufsize);
76 #endif
77  if (setsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize))) {
78  LOG(llevError, "init_connection: setsockopt unable to set output buf size to %d\n", bufsize);
79  }
80  }
81  buflen = sizeof(oldbufsize);
82  getsockopt(ns->fd, SOL_SOCKET, SO_SNDBUF, (char *)&oldbufsize, &buflen);
83 #ifdef ESRV_DEBUG
84  LOG(llevDebug, "Socket buffer size now %d bytes\n", oldbufsize);
85 #endif
86  ssop_t tmp = 1;
87  if (setsockopt(ns->fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)))
88  LOG(llevError, "Unable to turn on TCP_NODELAY\n");
89 }
90 
96 void init_connection(socket_struct *ns, const char *from_ip) {
97  SockList sl;
98 
99 #ifdef WIN32 /* ***WIN32 SOCKET: init win32 non blocking socket */
100 #ifdef CF_MXE_CROSS_COMPILE
101  u_long temp = 1;
102 #else
103  long temp = 1;
104 #endif
105 
106  if (ioctlsocket(ns->fd, FIONBIO , &temp) == -1)
107  LOG(llevError, "init_connection: Error on ioctlsocket.\n");
108 #else
109  if (fcntl(ns->fd, F_SETFL, O_NONBLOCK) == -1) {
110  LOG(llevError, "init_connection: Error on fcntl.\n");
111  }
112 #endif /* end win32 */
113 
115 
116  ns->faceset = 0;
117  ns->facecache = 0;
118  ns->sound = 0;
119  ns->sounds_this_tick = 0;
120  ns->monitor_spells = 0;
121  ns->darkness = 1;
122  ns->status = Ns_Add;
125  ns->look_position = 0;
126  ns->container_position = 0;
127  ns->update_look = 0;
128  ns->update_inventory = 0;
129  ns->tick = 0;
130  ns->is_bot = 0;
132  ns->want_pickup = 0;
133  ns->extended_stats = 0;
135  if (ns->account_chars) {
137  ns->account_chars = NULL;
138  }
139  ns->login_method = 0;
140  ns->notifications = 0;
141  ns->heartbeat = 0;
142 
143  /* we should really do some checking here - if total clients overflows
144  * we need to do something more intelligent, because client id's will start
145  * duplicating (not likely in normal cases, but malicous attacks that
146  * just open and close connections could get this total up.
147  */
148  SockList_Init(&ns->inbuf);
150  /* Basic initialization. Needed because we do a check in
151  * handle_client for oldsocketmode without checking the
152  * length of data.
153  */
154  memset(ns->inbuf.buf, 0, sizeof(ns->inbuf.buf));
155  memset(&ns->lastmap, 0, sizeof(struct Map));
156  free(ns->faces_sent);
157  ns->faces_sent = static_cast<uint8_t *>(calloc(sizeof(*ns->faces_sent), get_faces_count()));
159 
160  memset(&ns->anims_sent, 0, sizeof(ns->anims_sent));
161  memset(&ns->stats, 0, sizeof(struct statsinfo));
162  ns->map_scroll_x = 0;
163  ns->map_scroll_y = 0;
164  /* Do this so we don't send a face command for the client for
165  * this face. Face 0 is sent to the client to say clear
166  * face information.
167  */
168  ns->faces_sent[0] = NS_FACESENT_FACE;
169 
170  ns->password_fails = 0;
171 
172  free(ns->host);
173  ns->host = strdup_local(from_ip);
174  SockList_Init(&sl);
175  SockList_AddPrintf(&sl, "version %d %d %s\n", VERSION_CS, VERSION_SC, VERSION_INFO);
176  Send_With_Handling(ns, &sl);
177  SockList_Term(&sl);
178 #ifdef CS_LOGSTATS
183 #endif
184 }
185 
193  struct linger linger_opt;
194  char buf1[MAX_BUF], buf2[MAX_BUF];
195 
196  if (ns == NULL || ns->listen == NULL) {
197  LOG(llevError, "init_listening_socket: missing listen info in socket_struct?!\n");
199  }
200 
201  ns->status = Ns_Dead;
202 
203  ns->fd = socket(ns->listen->family, ns->listen->socktype, ns->listen->protocol);
204  if (ns->fd == -1) {
205  LOG(llevError, "Cannot create socket: %s\n", strerror(errno));
206  return;
207  }
208 
209  linger_opt.l_onoff = 0;
210  linger_opt.l_linger = 0;
211  if (setsockopt(ns->fd, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, sizeof(struct linger))) {
212  LOG(llevError, "Cannot setsockopt(SO_LINGER): %s\n", strerror(errno));
213  }
214 /* Would be nice to have an autoconf check for this. It appears that
215  * these functions are both using the same calling syntax, just one
216  * of them needs extra valus passed.
217  */
218 #if defined(__osf__) || defined(hpux) || defined(sgi) || defined(NeXT) || \
219  defined(__sun__) || defined(__linux__) || defined(SVR4) || \
220  defined(__FreeBSD__) || defined(__OpenBSD__) || \
221  defined(WIN32) /* ---win32 add this here */ || \
222  defined(__GNU__) /* HURD */
223  {
224 #ifdef WIN32
225  char tmp = 1;
226 #else
227  int tmp = 1;
228 #endif
229 
230  if (setsockopt(ns->fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp))) {
231  LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
232  }
233 #ifdef HAVE_GETADDRINFO
234  if ((ns->listen->family == AF_INET6) && setsockopt(ns->fd, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp))) {
235  LOG(llevError, "Cannot setsockopt(IPV6_V6ONLY): %s\n", strerror(errno));
236  }
237 #endif
238  }
239 #else
240  if (setsockopt(ns->fd, SOL_SOCKET, SO_REUSEADDR, (char *)NULL, 0)) {
241  LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
242  }
243 #endif
244 
245  if (bind(ns->fd, ns->listen->addr, ns->listen->addrlen) == (-1)) {
246 #ifdef HAVE_GETNAMEINFO
247  getnameinfo(ns->listen->addr, ns->listen->addrlen, buf1, sizeof(buf1), buf2, sizeof(buf2), NI_NUMERICHOST|NI_NUMERICSERV);
248 #else
249  short port;
250  long ip;
251 
252  ip = ntohl(((struct sockaddr_in *)ns->listen->addr)->sin_addr.s_addr);
253  port = ntohs(((struct sockaddr_in *)ns->listen->addr)->sin_port);
254  snprintf(buf1, sizeof(buf1), "%ld.%ld.%ld.%ld", (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, ip&255);
255  snprintf(buf2, sizeof(buf2), "%d", port&65535);
256 #endif
257  LOG(llevError, "Cannot bind socket to [%s]:%s: %s\n", buf1, buf2, 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  if (listen(ns->fd, 5) == (-1)) {
268  LOG(llevError, "Cannot listen on socket: %s\n", strerror(errno));
269 #ifdef WIN32 /* ***win32: close() -> closesocket() */
270  shutdown(ns->fd, SD_BOTH);
271  closesocket(ns->fd);
272 #else
273  close(ns->fd);
274 #endif /* win32 */
275  ns->fd = -1;
276  return;
277  }
278  ns->status = Ns_Add;
279 }
280 
283 void init_server(void) {
284  int i, e, listen_socket_count;
285 #ifdef HAVE_GETADDRINFO
286  struct addrinfo *ai, *ai_p;
287  struct addrinfo hints;
288  char buf[MAX_BUF];
289 #else
290  struct sockaddr_in *insock;
291  struct protoent *protox;
292 #endif
293 
294 #ifdef WIN32 /* ***win32 - we init a windows socket */
295  WSADATA w;
296 
297  socket_info.max_filedescriptor = 1; /* used in select, ignored in winsockets */
298  WSAStartup(0x0101, &w); /* this setup all socket stuff */
299  /* ill include no error tests here, winsocket 1.1 should always work */
300  /* except some old win95 versions without tcp/ip stack */
301 #else /* non windows */
302 
303 #ifdef HAVE_SYSCONF
304  socket_info.max_filedescriptor = sysconf(_SC_OPEN_MAX);
305 #else
306 # ifdef HAVE_GETDTABLESIZE
307  socket_info.max_filedescriptor = getdtablesize();
308 # else
309 #error "Unable to find usable function to get max filedescriptors"
310 # endif
311 #endif
312 #endif /* win32 */
313 
314  // Modern operating systems support more file descriptors than select() can handle.
316 
317  socket_info.timeout.tv_sec = 0;
318  socket_info.timeout.tv_usec = 0;
319 
320 #ifdef CS_LOGSTATS
323 #endif
324 
325 #ifdef HAVE_GETADDRINFO
326  memset(&hints, '\0', sizeof(hints));
327  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
328  hints.ai_socktype = SOCK_STREAM;
329  snprintf(buf, sizeof(buf), "%d", settings.csport);
330  e = getaddrinfo(NULL, buf, &hints, &ai);
331  if (e != 0) {
332  LOG(llevError, "init_server: getaddrinfo: %s\n", gai_strerror(e));
334  }
335 
336  listen_socket_count = 0;
337  for (ai_p = ai; ai_p != NULL; ai_p = ai_p->ai_next) {
338  listen_socket_count++;
339  }
340 
341  assert(listen_socket_count > 0);
342 #else
343  listen_socket_count = 1;
344 #endif
345 
346  LOG(llevDebug, "Initialize new client/server data\n");
347  init_sockets = static_cast<socket_struct *>(malloc(sizeof(socket_struct) * listen_socket_count));
348  socket_info.allocated_sockets = listen_socket_count;
349  for (i = 0; i < listen_socket_count; i++) {
350  init_sockets[i].listen = static_cast<listen_info *>(calloc(sizeof(struct listen_info), 1));
351  init_sockets[i].faces_sent = NULL; /* unused */
352  init_sockets[i].account_name = NULL; /* Must be set to avoid undef behaviour elsewhere. */
353  }
354 
355 #ifdef HAVE_GETADDRINFO
356  for (i = 0, ai_p = ai; i < listen_socket_count && ai_p != NULL; i++, ai_p = ai_p->ai_next) {
357  init_sockets[i].listen->family = ai_p->ai_family;
358  init_sockets[i].listen->socktype = ai_p->ai_socktype;
359  init_sockets[i].listen->protocol = ai_p->ai_protocol;
360  init_sockets[i].listen->addrlen = ai_p->ai_addrlen;
361  init_sockets[i].listen->addr = static_cast<sockaddr *>(malloc(ai_p->ai_addrlen));
362  memcpy(init_sockets[i].listen->addr, ai_p->ai_addr, ai_p->ai_addrlen);
363  }
364  freeaddrinfo(ai);
365 #else
366  protox = getprotobyname("tcp");
367  if (protox == NULL) {
368  LOG(llevError, "init_server: Error getting protox\n");
370  }
371  init_sockets[0].listen->family = PF_INET;
372  init_sockets[0].listen->socktype = SOCK_STREAM;
373  init_sockets[0].listen->protocol = protox->p_proto;
374  insock = static_cast<struct sockaddr_in *>(calloc(sizeof(struct sockaddr_in), 1));
375  insock->sin_family = AF_INET;
376  insock->sin_port = htons(settings.csport);
377  insock->sin_addr.s_addr = htonl(INADDR_ANY);
378  init_sockets[0].listen->addr = (struct sockaddr *) insock;
379  init_sockets[0].listen->addrlen = sizeof(struct sockaddr_in);
380 #endif
381 
382  e = 1;
383  for (i = 0; i < listen_socket_count; i++) {
385  if (init_sockets[i].fd != -1)
386  e = 0;
387  }
388  if (e != 0) {
389  LOG(llevError, "init_server: can't open any listening socket\n");
391  }
392 }
393 
394 /*******************************************************************************
395  *
396  * Start of functions dealing with freeing of the data.
397  *
398  ******************************************************************************/
399 
401 void free_all_newserver(void) {
402  int i;
403  LOG(llevDebug, "Freeing all new client/server information.\n");
404  for (i = 0; i < socket_info.allocated_sockets && init_sockets[i].listen; i++) {
405  free(init_sockets[i].listen->addr);
406  free(init_sockets[i].listen);
407  }
408  free(init_sockets);
409 }
410 
419 #ifdef WIN32 /* ***win32: closesocket in windows style */
420  shutdown(ns->fd, SD_BOTH);
421  if (closesocket(ns->fd)) {
422 #else
423  if (close(ns->fd)) {
424 #endif /* win32 */
425 
426 #ifdef ESRV_DEBUG
427  LOG(llevDebug, "Error closing socket %d\n", ns->fd);
428 #endif
429  }
430  ns->fd = -1;
432  if (ns->stats.range)
434  if (ns->stats.title)
437  FREE_AND_CLEAR(ns->stats.god);
438  if (ns->host)
439  FREE_AND_CLEAR(ns->host);
440  if (ns->account_name) {
443  }
444  if (ns->account_chars) {
447  ns->account_chars = NULL;
448  }
449  SockList_Term(&ns->inbuf);
450 }
451 
454  SockList sl;
455 
456  SockList_Init(&sl);
457  SockList_AddString(&sl, "goodbye");
458  Send_With_Handling(pl->socket, &sl);
459  SockList_Term(&sl);
460  // If the player wasn't saved (new for instance), then pl->ob isn't removed,
461  // and the socket is needed for updating inventory. So keep it and free after.
462  socket_struct *socket = pl->socket;
463  free_player(pl);
464  free_newsocket(socket);
465  free(socket);
466 }
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:58
Map
Definition: newserver.h:48
socket_info
Socket_Info socket_info
Definition: init.cpp:52
socket_struct::container_position
uint16_t container_position
Definition: newserver.h:115
player
Definition: player.h:105
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:401
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:157
ssop_t
int ssop_t
Definition: init.cpp:40
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:192
socket_struct::update_inventory
uint32_t update_inventory
Definition: newserver.h:105
MIN
#define MIN(x, y)
Definition: compat.h:21
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:68
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:1565
init_server
void init_server(void)
Definition: init.cpp:283
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
init_sockets
socket_struct * init_sockets
Definition: init.cpp:66
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:345
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:96
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:55
image.h
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:590
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:418
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.cpp:65
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:472
final_free_player
void final_free_player(player *pl)
Definition: init.cpp:453
statsinfo::god
char * god
Definition: newserver.h:57
reset_stats
void reset_stats(struct CS_Stats *stats)
socket_struct::faces_sent_len
size_t faces_sent_len
Definition: newserver.h:95
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Definition: lowlevel.cpp:83
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
MAP_CLIENT_Y_DEFAULT
#define MAP_CLIENT_Y_DEFAULT
Definition: config.h:242
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:293
cst_lst
CS_Stats cst_lst
Definition: newclient.h:712
SockList::buf
unsigned char buf[MAXSOCKBUF]
Definition: newclient.h:690
guildbuy.temp
def temp
Definition: guildbuy.py:26
account_char_save
void account_char_save(Account_Chars *chars)
Definition: account_char.cpp:158
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
MAP_CLIENT_X_DEFAULT
#define MAP_CLIENT_X_DEFAULT
Definition: config.h:241
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.cpp:447
SockList
Definition: newclient.h:684
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:202
account_logout
void account_logout(const char *account_name)
Definition: account.cpp:338
CS_Stats::max_conn
short max_conn
Definition: newclient.h:700