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