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  if (!ns->faces_sent)
139  ns->faces_sent = calloc(sizeof(*ns->faces_sent), get_faces_count());
141 
142  memset(&ns->anims_sent, 0, sizeof(ns->anims_sent));
143  memset(&ns->stats, 0, sizeof(struct statsinfo));
144  ns->map_scroll_x = 0;
145  ns->map_scroll_y = 0;
146  /* Do this so we don't send a face command for the client for
147  * this face. Face 0 is sent to the client to say clear
148  * face information.
149  */
150  ns->faces_sent[0] = NS_FACESENT_FACE;
151 
152  ns->password_fails = 0;
153 
154  ns->host = strdup_local(from_ip);
155  SockList_Init(&sl);
156  SockList_AddPrintf(&sl, "version %d %d %s\n", VERSION_CS, VERSION_SC, VERSION_INFO);
157  Send_With_Handling(ns, &sl);
158  SockList_Term(&sl);
159 #ifdef CS_LOGSTATS
164 #endif
165 }
166 
174  struct linger linger_opt;
175  char buf1[MAX_BUF], buf2[MAX_BUF];
176 
177  if (ns == NULL || ns->listen == NULL) {
178  LOG(llevError, "init_listening_socket: missing listen info in socket_struct?!\n");
180  }
181 
182  ns->status = Ns_Dead;
183 
184  ns->fd = socket(ns->listen->family, ns->listen->socktype, ns->listen->protocol);
185  if (ns->fd == -1) {
186  LOG(llevError, "Cannot create socket: %s\n", strerror(errno));
187  return;
188  }
189 
190  linger_opt.l_onoff = 0;
191  linger_opt.l_linger = 0;
192  if (setsockopt(ns->fd, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, sizeof(struct linger))) {
193  LOG(llevError, "Cannot setsockopt(SO_LINGER): %s\n", strerror(errno));
194  }
195 /* Would be nice to have an autoconf check for this. It appears that
196  * these functions are both using the same calling syntax, just one
197  * of them needs extra valus passed.
198  */
199 #if defined(__osf__) || defined(hpux) || defined(sgi) || defined(NeXT) || \
200  defined(__sun__) || defined(__linux__) || defined(SVR4) || \
201  defined(__FreeBSD__) || defined(__OpenBSD__) || \
202  defined(WIN32) /* ---win32 add this here */ || \
203  defined(__GNU__) /* HURD */
204  {
205 #ifdef WIN32
206  char tmp = 1;
207 #else
208  int tmp = 1;
209 #endif
210 
211  if (setsockopt(ns->fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp))) {
212  LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
213  }
214 #ifdef HAVE_GETADDRINFO
215  if ((ns->listen->family == AF_INET6) && setsockopt(ns->fd, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp))) {
216  LOG(llevError, "Cannot setsockopt(IPV6_V6ONLY): %s\n", strerror(errno));
217  }
218 #endif
219  }
220 #else
221  if (setsockopt(ns->fd, SOL_SOCKET, SO_REUSEADDR, (char *)NULL, 0)) {
222  LOG(llevError, "Cannot setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
223  }
224 #endif
225 
226  if (bind(ns->fd, ns->listen->addr, ns->listen->addrlen) == (-1)) {
227 #ifdef HAVE_GETNAMEINFO
228  getnameinfo(ns->listen->addr, ns->listen->addrlen, buf1, sizeof(buf1), buf2, sizeof(buf2), NI_NUMERICHOST|NI_NUMERICSERV);
229 #else
230  short port;
231  long ip;
232 
233  ip = ntohl(((struct sockaddr_in *)ns->listen->addr)->sin_addr.s_addr);
234  port = ntohs(((struct sockaddr_in *)ns->listen->addr)->sin_port);
235  snprintf(buf1, sizeof(buf1), "%ld.%ld.%ld.%ld", (ip>>24)&255, (ip>>16)&255, (ip>>8)&255, ip&255);
236  snprintf(buf2, sizeof(buf2), "%d", port&65535);
237 #endif
238  LOG(llevError, "Cannot bind socket to [%s]:%s: %s\n", buf1, buf2, strerror(errno));
239 #ifdef WIN32 /* ***win32: close() -> closesocket() */
240  shutdown(ns->fd, SD_BOTH);
241  closesocket(ns->fd);
242 #else
243  close(ns->fd);
244 #endif /* win32 */
245  ns->fd = -1;
246  return;
247  }
248  if (listen(ns->fd, 5) == (-1)) {
249  LOG(llevError, "Cannot listen on socket: %s\n", strerror(errno));
250 #ifdef WIN32 /* ***win32: close() -> closesocket() */
251  shutdown(ns->fd, SD_BOTH);
252  closesocket(ns->fd);
253 #else
254  close(ns->fd);
255 #endif /* win32 */
256  ns->fd = -1;
257  return;
258  }
259  ns->status = Ns_Add;
260 }
261 
264 void init_server(void) {
265  int i, e, listen_socket_count;
266 #ifdef HAVE_GETADDRINFO
267  struct addrinfo *ai, *ai_p;
268  struct addrinfo hints;
269  char buf[MAX_BUF];
270 #else
271  struct sockaddr_in *insock;
272  struct protoent *protox;
273 #endif
274 
275 #ifdef WIN32 /* ***win32 - we init a windows socket */
276  WSADATA w;
277 
278  socket_info.max_filedescriptor = 1; /* used in select, ignored in winsockets */
279  WSAStartup(0x0101, &w); /* this setup all socket stuff */
280  /* ill include no error tests here, winsocket 1.1 should always work */
281  /* except some old win95 versions without tcp/ip stack */
282 #else /* non windows */
283 
284 #ifdef HAVE_SYSCONF
285  socket_info.max_filedescriptor = sysconf(_SC_OPEN_MAX);
286 #else
287 # ifdef HAVE_GETDTABLESIZE
288  socket_info.max_filedescriptor = getdtablesize();
289 # else
290  "Unable to find usable function to get max filedescriptors";
291 # endif
292 #endif
293 #endif /* win32 */
294 
295  /*
296  * There is a bug on FreeBSD 9 in that the value we get here is over 1024,
297  * which is the limit FD_ZERO and friends will use.
298  * So later on file descriptors are not correctly cleared, and select() fails.
299  * Therefore here's a hack to prevent that, but the real solution would be
300  * to figure why this happens and how to fix it.
301  * Nicolas W, 2012 feb 07.
302  */
303  if (socket_info.max_filedescriptor > 1024) {
304  LOG(llevDebug, "warning, socket_info.max_filedescriptor is %d, setting to 1024.\n", socket_info.max_filedescriptor);
306  }
307  /* end of hack */
308 
309  socket_info.timeout.tv_sec = 0;
310  socket_info.timeout.tv_usec = 0;
311 
312 #ifdef CS_LOGSTATS
313  memset(&cst_tot, 0, sizeof(CS_Stats));
314  memset(&cst_lst, 0, sizeof(CS_Stats));
315  cst_tot.time_start = time(NULL);
316  cst_lst.time_start = time(NULL);
317 #endif
318 
319 #ifdef HAVE_GETADDRINFO
320  memset(&hints, '\0', sizeof(hints));
321  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
322  hints.ai_socktype = SOCK_STREAM;
323  snprintf(buf, sizeof(buf), "%d", settings.csport);
324  e = getaddrinfo(NULL, buf, &hints, &ai);
325  if (e != 0) {
326  LOG(llevError, "init_server: getaddrinfo: %s\n", gai_strerror(e));
328  }
329 
330  listen_socket_count = 0;
331  for (ai_p = ai; ai_p != NULL; ai_p = ai_p->ai_next) {
332  listen_socket_count++;
333  }
334 
335  assert(listen_socket_count > 0);
336 #else
337  listen_socket_count = 1;
338 #endif
339 
340  LOG(llevDebug, "Initialize new client/server data\n");
341  init_sockets = malloc(sizeof(socket_struct) * listen_socket_count);
342  socket_info.allocated_sockets = listen_socket_count;
343  for (i = 0; i < listen_socket_count; i++) {
344  init_sockets[i].listen = calloc(sizeof(struct listen_info), 1);
345  init_sockets[i].faces_sent = NULL; /* unused */
346  init_sockets[i].account_name = NULL; /* Must be set to avoid undef behaviour elsewhere. */
347  }
348 
349 #ifdef HAVE_GETADDRINFO
350  for (i = 0, ai_p = ai; i < listen_socket_count && ai_p != NULL; i++, ai_p = ai_p->ai_next) {
351  init_sockets[i].listen->family = ai_p->ai_family;
352  init_sockets[i].listen->socktype = ai_p->ai_socktype;
353  init_sockets[i].listen->protocol = ai_p->ai_protocol;
354  init_sockets[i].listen->addrlen = ai_p->ai_addrlen;
355  init_sockets[i].listen->addr = malloc(ai_p->ai_addrlen);
356  memcpy(init_sockets[i].listen->addr, ai_p->ai_addr, ai_p->ai_addrlen);
357  }
358  freeaddrinfo(ai);
359 #else
360  protox = getprotobyname("tcp");
361  if (protox == NULL) {
362  LOG(llevError, "init_server: Error getting protox\n");
364  }
365  init_sockets[0].listen->family = PF_INET;
366  init_sockets[0].listen->socktype = SOCK_STREAM;
367  init_sockets[0].listen->protocol = protox->p_proto;
368  insock = calloc(sizeof(struct sockaddr_in), 1);
369  insock->sin_family = AF_INET;
370  insock->sin_port = htons(settings.csport);
371  insock->sin_addr.s_addr = htonl(INADDR_ANY);
372  init_sockets[0].listen->addr = (struct sockaddr *) insock;
373  init_sockets[0].listen->addrlen = sizeof(struct sockaddr_in);
374 #endif
375 
376  e = 1;
377  for (i = 0; i < listen_socket_count; i++) {
379  if (init_sockets[i].fd != -1)
380  e = 0;
381  }
382  if (e != 0) {
383  LOG(llevError, "init_server: can't open any listening socket\n");
385  }
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");
398  for (i = 0; i < socket_info.allocated_sockets && init_sockets[i].listen; i++) {
399  free(init_sockets[i].listen->addr);
400  free(init_sockets[i].listen);
401  }
402  free(init_sockets);
403 }
404 
413 #ifdef WIN32 /* ***win32: closesocket in windows style */
414  shutdown(ns->fd, SD_BOTH);
415  if (closesocket(ns->fd)) {
416 #else
417  if (close(ns->fd)) {
418 #endif /* win32 */
419 
420 #ifdef ESRV_DEBUG
421  LOG(llevDebug, "Error closing socket %d\n", ns->fd);
422 #endif
423  }
424  ns->fd = -1;
425  if (ns->stats.range)
427  if (ns->stats.title)
429  FREE_AND_CLEAR(ns->stats.god);
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);
452  free_player(pl);
453 }
socket_struct::account_chars
Account_Char * account_chars
Definition: newserver.h:127
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:94
pl
Definition: player.h:92
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:239
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:412
CS_Stats::time_start
time_t time_start
Definition: newclient.h:698
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:395
socket_struct::facecache
uint32_t facecache
Definition: newserver.h:102
statsinfo
Definition: newserver.h:56
fatal
void fatal(enum fatal_error err)
Definition: utils.c:597
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:264
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:173
account_char_save
void account_char_save(const char *account, Account_Char *chars)
Definition: account_char.c:146
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
account_char_free
void account_char_free(Account_Char *chars)
Definition: account_char.c:334
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:191
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:1606
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:313
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
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:444
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