Crossfire Server, Trunk  R21024
lowlevel.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 
26 #include "global.h"
27 
28 #include <assert.h>
29 #include <errno.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "shared/newclient.h"
35 #include "sproto.h"
36 
37 /***********************************************************************
38  *
39  * SockList functions/utilities
40  *
41  **********************************************************************/
42 
49  SockList_Reset(sl);
50 }
51 
59 }
60 
67  sl->len = 2;
68 }
69 
76  sl->len = 0;
77 }
78 
87 static void SockList_Ensure(const SockList *sl, size_t size) {
88  if (sl->len+size > sizeof(sl->buf)) {
90  }
91 }
92 
98 void SockList_AddChar(SockList *sl, char data) {
99  SockList_Ensure(sl, 1);
100  sl->buf[sl->len++] = data;
101 }
102 
109  SockList_Ensure(sl, 2);
110  sl->buf[sl->len++] = (data>>8)&0xff;
111  sl->buf[sl->len++] = data&0xff;
112 }
113 
120  SockList_Ensure(sl, 4);
121  sl->buf[sl->len++] = (data>>24)&0xff;
122  sl->buf[sl->len++] = (data>>16)&0xff;
123  sl->buf[sl->len++] = (data>>8)&0xff;
124  sl->buf[sl->len++] = data&0xff;
125 }
126 
133  SockList_Ensure(sl, 8);
134  sl->buf[sl->len++] = (char)((data>>56)&0xff);
135  sl->buf[sl->len++] = (char)((data>>48)&0xff);
136  sl->buf[sl->len++] = (char)((data>>40)&0xff);
137  sl->buf[sl->len++] = (char)((data>>32)&0xff);
138  sl->buf[sl->len++] = (char)((data>>24)&0xff);
139  sl->buf[sl->len++] = (char)((data>>16)&0xff);
140  sl->buf[sl->len++] = (char)((data>>8)&0xff);
141  sl->buf[sl->len++] = (char)(data&0xff);
142 }
143 
149 void SockList_AddString(SockList *sl, const char *data) {
150  SockList_AddData(sl, data, strlen(data));
151 }
152 
159 void SockList_AddData(SockList *sl, const void *data, size_t len) {
160  SockList_Ensure(sl, len);
161  memcpy(sl->buf+sl->len, data, len);
162  sl->len += len;
163 }
164 
171 void SockList_AddLen8Data(SockList *sl, const void *data, size_t len) {
172  assert(len <= 255);
173  SockList_AddChar(sl, len);
174  SockList_AddData(sl, data, len);
175 }
176 
183 void SockList_AddLen16Data(SockList *sl, const void *data, size_t len) {
184  assert(len <= 65535);
185  SockList_AddShort(sl, len);
186  SockList_AddData(sl, data, len);
187 }
188 
194 void SockList_AddPrintf(SockList *sl, const char *format, ...) {
195  size_t size;
196  int n;
197  va_list arg;
198 
199  size = sizeof(sl->buf)-sl->len;
200 
201  va_start(arg, format);
202  n = vsnprintf((char *)sl->buf+sl->len, size, format, arg);
203  va_end(arg);
204 
205  if (n <= -1 || (size_t)n >= size) {
207  }
208  sl->len += (size_t)n;
209 }
210 
218  char *p;
219 
220  p = stringbuffer_finish(sb);
221  SockList_AddString(sl, p);
222  free(p);
223 }
224 
230  SockList_Ensure(sl, 1);
231  sl->buf[sl->len] = '\0';
232 }
233 
238 size_t SockList_Avail(const SockList *sl) {
239  return sizeof(sl->buf)-sl->len;
240 }
241 
246 int GetInt_String(const unsigned char *data) {
247  return ((data[0]<<24)+(data[1]<<16)+(data[2]<<8)+data[3]);
248 }
249 
250 short GetShort_String(const unsigned char *data) {
251  return ((data[0]<<8)+data[1]);
252 }
253 
254 /******************************************************************************
255  *
256  * Start of read routines.
257  *
258  ******************************************************************************/
259 
267 int SockList_ReadPacket(int fd, SockList *sl, int len) {
268  int stat, toread;
269 
270  /* We already have a partial packet */
271  if (sl->len < 2) {
272 #ifdef WIN32 /* ***WIN32 SockList_ReadPacket: change read() to recv() */
273 
274  stat = recv(fd, sl->buf+sl->len, 2-sl->len, 0);
275 
276 #else
277  do {
278  stat = read(fd, sl->buf+sl->len, 2-sl->len);
279  } while ((stat == -1) && (errno == EINTR));
280 #endif
281  if (stat < 0) {
282  /* In non blocking mode, EAGAIN is set when there is no
283  * data available.
284  */
285 #ifdef WIN32 /* ***WIN32 SockList_ReadPacket: error handling for win32 */
286  if ((stat == -1) && WSAGetLastError() != WSAEWOULDBLOCK) {
287  if (WSAGetLastError() == WSAECONNRESET)
288  LOG(llevDebug, "Connection closed by client\n");
289  else {
290  LOG(llevDebug, "ReadPacket got error %d, returning -1\n", WSAGetLastError());
291  }
292  return -1; /* kick this user! */
293  }
294 #else
295  if (errno == ECONNRESET) {
296  LOG(llevDebug, "ReadPacket got error %s, returning -1\n", strerror(errno));
297  return -1;
298  }
299  if (errno != EAGAIN && errno != EWOULDBLOCK) {
300  LOG(llevDebug, "ReadPacket got error %s, returning 0\n", strerror(errno));
301  }
302 #endif
303  return 0; /*Error */
304  }
305  if (stat == 0)
306  return -1;
307  sl->len += stat;
308 #ifdef CS_LOGSTATS
309  cst_tot.ibytes += stat;
310  cst_lst.ibytes += stat;
311 #endif
312  if (stat < 2)
313  return 0; /* Still don't have a full packet */
314  }
315  /* Figure out how much more data we need to read. Add 2 from the
316  * end of this - size header information is not included.
317  */
318  toread = 2+(sl->buf[0]<<8)+sl->buf[1]-sl->len;
319  if ((toread+(int)sl->len) >= len) {
320  LOG(llevError, "SockList_ReadPacket: Want to read more bytes than will fit in buffer (%lu>=%lu).\n", (unsigned long)toread+sl->len, (unsigned long)len);
321  /* Quick hack in case for 'oldsocketmode' input. If we are
322  * closing the socket anyways, then reading this extra 100 bytes
323  * shouldn't hurt.
324  */
325 #ifdef WIN32 /* ***win32 SockList_ReadPacket: change read() to recv() */
326  recv(fd, sl->buf+2, 100, 0);
327 #else
328  read(fd, sl->buf+2, 100);
329 #endif /* end win32 */
330 
331  /* return error so the socket is closed */
332  return -1;
333  }
334  do {
335 #ifdef WIN32 /* ***win32 SockList_ReadPacket: change read() to recv() */
336  stat = recv(fd, sl->buf+sl->len, toread, 0);
337 #else
338  do {
339  stat = read(fd, sl->buf+sl->len, toread);
340  } while ((stat < 0) && (errno == EINTR));
341 #endif
342  if (stat < 0) {
343 #ifdef WIN32 /* ***win32 SockList_ReadPacket: change error handling for win32 */
344  if ((stat == -1) && WSAGetLastError() != WSAEWOULDBLOCK) {
345  if (WSAGetLastError() == WSAECONNRESET)
346  LOG(llevDebug, "Connection closed by client\n");
347  else {
348  LOG(llevDebug, "ReadPacket got error %d, returning -1\n", WSAGetLastError());
349  }
350  return -1; /* kick this user! */
351  }
352 #else
353  if (errno != EAGAIN && errno != EWOULDBLOCK) {
354  LOG(llevDebug, "ReadPacket got error %s, returning 0\n", strerror(errno));
355  }
356 #endif
357  return 0; /*Error */
358  }
359  if (stat == 0)
360  return -1;
361  sl->len += stat;
362 #ifdef CS_LOGSTATS
363  cst_tot.ibytes += stat;
364  cst_lst.ibytes += stat;
365 #endif
366  toread -= stat;
367  if (toread == 0)
368  return 1;
369  if (toread < 0) {
370  LOG(llevError, "SockList_ReadPacket: Read more bytes than desired.\n");
371  return 1;
372  }
373  } while (toread > 0);
374  return 0;
375 }
376 
377 /*******************************************************************************
378  *
379  * Start of write related routines.
380  *
381  ******************************************************************************/
382 
390 static void Write_To_Socket(socket_struct* ns, const unsigned char* buf, const int len) {
391  if (ns->status == Ns_Dead || !buf) {
392  LOG(llevDebug, "Write_To_Socket called with dead socket\n");
393  return;
394  }
395 
396  const int amt = send(ns->fd, buf, len, 0);
397  if (amt < 0) { /* We got an error */
398 #ifdef WIN32 /* ***win32 Write_To_Socket: change error handling */
399  if (amt == -1 && WSAGetLastError() != WSAEWOULDBLOCK) {
400  LOG(llevError, "New socket write failed WTS (%d).\n",
401  WSAGetLastError());
402 #else
403  if (errno != EWOULDBLOCK) {
404  LOG(llevError, "New socket write failed WTS: %s\n",
405  strerror(errno));
406 #endif
407  ns->status = Ns_Dead;
408  return;
409  } else { /* EWOULDBLOCK */
410  LOG(llevError,
411  "Write_To_Socket: write would block; disconnecting. Try "
412  "increasing SOCKETBUFSIZE.\n");
413  ns->status = Ns_Dead;
414  return;
415  }
416  } else if (amt != len) {
417  LOG(llevError, "Write_To_Socket: write wrote less than requested; "
418  "disconnecting. Try increasing SOCKETBUFSIZE.\n");
419  ns->status = Ns_Dead;
420  return;
421  }
422 #ifdef CS_LOGSTATS
423  cst_tot.obytes += amt;
424  cst_lst.obytes += amt;
425 #endif
426 }
427 
435  if (ns->status == Ns_Dead || sl == NULL)
436  return;
437 
438  sl->buf[0] = ((sl->len-2)>>8)&0xFF;
439  sl->buf[1] = (sl->len-2)&0xFF;
440  Write_To_Socket(ns, sl->buf, sl->len);
441 }
442 
443 /******************************************************************************
444  *
445  * statistics logging functions.
446  *
447  ******************************************************************************/
448 
449 #ifdef CS_LOGSTATS
450 /* cst_tot is for the life of the server, cst_last is for the last series of
451  * stats
452  */
454 
458 void write_cs_stats(void) {
459  time_t now = time(NULL);
460 
461  /* If no connections recently, don't bother to log anything */
462  if (cst_lst.ibytes == 0 && cst_lst.obytes == 0)
463  return;
464 
465  /* CSSTAT is put in so scripts can easily find the line */
466  LOG(llevInfo, "CSSTAT: %.16s tot %d %d %d %ld inc %d %d %d %ld\n",
467  ctime(&now), cst_tot.ibytes, cst_tot.obytes, cst_tot.max_conn,
468  (long)(now-cst_tot.time_start), cst_lst.ibytes, cst_lst.obytes,
469  cst_lst.max_conn, (long)(now-cst_lst.time_start));
470  cst_lst.ibytes = 0;
471  cst_lst.obytes = 0;
473  cst_lst.time_start = now;
474 }
475 #endif
476 
void SockList_AddData(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:159
void SockList_AddChar(SockList *sl, char data)
Definition: lowlevel.c:98
size_t len
Definition: newclient.h:685
unsigned char buf[MAXSOCKBUF]
Definition: newclient.h:686
int obytes
Definition: newclient.h:695
void fatal(enum fatal_error err)
Definition: utils.c:597
short GetShort_String(const unsigned char *data)
Definition: lowlevel.c:250
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.c:238
void SockList_Init(SockList *sl)
Definition: lowlevel.c:48
void SockList_AddStringBuffer(SockList *sl, StringBuffer *sb)
Definition: lowlevel.c:217
enum Sock_Status status
Definition: newserver.h:90
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:171
Socket_Info socket_info
Definition: init.c:47
CS_Stats cst_lst
short max_conn
Definition: newclient.h:696
int ibytes
Definition: newclient.h:694
static void SockList_Ensure(const SockList *sl, size_t size)
Definition: lowlevel.c:87
void SockList_NullTerminate(SockList *sl)
Definition: lowlevel.c:229
static void Write_To_Socket(socket_struct *ns, const unsigned char *buf, const int len)
Definition: lowlevel.c:390
int GetInt_String(const unsigned char *data)
Definition: lowlevel.c:246
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.c:194
unsigned __int64 uint64_t
Definition: win32.h:167
int allocated_sockets
Definition: newserver.h:144
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:149
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.c:119
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:434
unsigned short uint16_t
Definition: win32.h:163
unsigned int uint32_t
Definition: win32.h:162
#define vsnprintf
Definition: win32.h:61
void write_cs_stats(void)
CS_Stats cst_tot
void SockList_Term(SockList *sl)
Definition: lowlevel.c:58
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.c:108
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:183
time_t time_start
Definition: newclient.h:697
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
int SockList_ReadPacket(int fd, SockList *sl, int len)
Definition: lowlevel.c:267
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:66
void SockList_ResetRead(SockList *sl)
Definition: lowlevel.c:75
void SockList_AddInt64(SockList *sl, uint64_t data)
Definition: lowlevel.c:132
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76