Crossfire Client, Trunk
newsocket.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 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 
21 #include "client.h"
22 
23 #include <errno.h>
24 
25 #include "script.h"
26 
32 void SockList_Init(SockList *sl, guint8 *buf)
33 {
34  sl->len=0;
35  sl->buf=buf + 2; /* reserve two bytes for total length */
36 }
37 
43 void SockList_AddChar(SockList *sl, char c)
44 {
45  if (sl->len + 1 < MAX_BUF - 2){
46  sl->buf[sl->len++]=c;
47  }
48  else{
49  /*
50  * Cast c to an unsigned short so it displays correctly in the error message.
51  * Otherwise, it prints as a hexadecimal number in a funny box.
52  *
53  * SilverNexus 2014-06-12
54  */
55  LOG(LOG_ERROR,"SockList_AddChar","Could not write %hu to socket: Buffer full.\n", (unsigned short)c);
56  }
57 }
58 
64 void SockList_AddShort(SockList *sl, guint16 data)
65 {
66  if (sl->len + 2 < MAX_BUF - 2){
67  sl->buf[sl->len++] = (data>>8)&0xff;
68  sl->buf[sl->len++] = data & 0xff;
69  }
70  else{
71  LOG(LOG_ERROR,"SockList_AddShort","Could not write %hu to socket: Buffer full.\n", data);
72  }
73 }
74 
80 void SockList_AddInt(SockList *sl, guint32 data)
81 {
82  if (sl->len + 4 < MAX_BUF - 2){
83  sl->buf[sl->len++] = (data>>24)&0xff;
84  sl->buf[sl->len++] = (data>>16)&0xff;
85  sl->buf[sl->len++] = (data>>8)&0xff;
86  sl->buf[sl->len++] = data & 0xff;
87  }
88  else{
89  LOG(LOG_ERROR,"SockList_AddInt","Could not write %u to socket: Buffer full.\n", data);
90  }
91 }
92 
98 void SockList_AddString(SockList *sl, const char *str)
99 {
100  int len = strlen(str);
101 
102  if (sl->len + len > MAX_BUF-2) {
103  len = MAX_BUF-2 - sl->len;
104  }
105  memcpy(sl->buf + sl->len, str, len);
106  sl->len += len;
107 }
108 
112 int SockList_Send(SockList *sl, GSocketConnection* c) {
113  sl->buf[-2] = sl->len / 256;
114  sl->buf[-1] = sl->len % 256;
115  if (c == NULL) {
116  LOG(LOG_WARNING, "SockList_Send", "Sending data while not connected!");
117  return 1;
118  }
119  if (debug_protocol) {
120  char *data_print = printable(sl->buf, sl->len);
121  if (data_print != NULL) {
122  LOG(LOG_INFO, "C->S", "len=%d |%s|", sl->len, data_print);
123  free(data_print);
124  }
125  }
126  GOutputStream* out = g_io_stream_get_output_stream(G_IO_STREAM(c));
127  bool ret = g_output_stream_write_all(out, sl->buf - 2, sl->len + 2, NULL,
128  NULL, NULL);
129  return ret ? 0 : -1;
130 }
131 
137 char GetChar_String(const unsigned char *data)
138 {
139  return (data[0]);
140 }
141 
149 int GetInt_String(const unsigned char *data)
150 {
151  return ((data[0]<<24) + (data[1]<<16) + (data[2]<<8) + data[3]);
152 }
153 
161 gint64 GetInt64_String(const unsigned char *data)
162 {
163 #ifdef WIN32
164  return (((gint64)data[0]<<56) + ((gint64)data[1]<<48) +
165  ((gint64)data[2]<<40) + ((gint64)data[3]<<32) +
166  ((gint64)data[4]<<24) + ((gint64)data[5]<<16) + ((gint64)data[6]<<8) + (gint64)data[7]);
167 #else
168  return (((guint64)data[0]<<56) + ((guint64)data[1]<<48) +
169  ((guint64)data[2]<<40) + ((guint64)data[3]<<32) +
170  ((guint64)data[4]<<24) + (data[5]<<16) + (data[6]<<8) + data[7]);
171 #endif
172 }
173 
179 short GetShort_String(const unsigned char *data)
180 {
181  return ((data[0]<<8)+data[1]);
182 }
183 
197 static guint16 GetUShort_String(const unsigned char data[static 2]) // We want at least two characters.
198 {
199  return ((data[0]<<8)+data[1]);
200 }
201 
213 bool SockList_ReadPacket(GSocketConnection c[static 1], SockList sl[static 1],
214  size_t len, GError** error) {
215  GInputStream* in = g_io_stream_get_input_stream(G_IO_STREAM(csocket.fd));
216  gsize read;
217  if (!g_input_stream_read_all(in, sl->buf, 2, &read, NULL, error)) {
218  return false;
219  }
220  if (read != 2) {
221  sl->len = 0;
222  return true;
223  }
224  size_t to_read = (size_t)GetUShort_String(sl->buf);
225  if (to_read + 2 > len) {
226  g_set_error(error, CLIENT_ERROR, CLIENT_ERROR_TOOBIG,
227  "Server packet too big");
228  return false;
229  }
230  if (!g_input_stream_read_all(in, sl->buf + 2, to_read, &read, NULL, error)) {
231  return false;
232  }
233  if (read != to_read) {
234  sl->len = 0;
235  return true;
236  }
237  sl->len = to_read + 2;
238 #ifdef CS_LOGSTATS
239  cst_tot.ibytes += sl->len;
240  cst_lst.ibytes += sl->len;
241 #endif
242  return true;
243 }
244 
252 int cs_print_string(GSocketConnection* fd, const char *str, ...)
253 {
254  va_list args;
255  SockList sl;
256  guint8 buf[MAX_BUF];
257 
258  SockList_Init(&sl, buf);
259  va_start(args, str);
260  sl.len += vsnprintf((char*)sl.buf + sl.len, MAX_BUF-sl.len, str, args);
261  va_end(args);
262  // Adjust sl.len to account for when we overflow the buffer.
263  if (sl.len > MAX_BUF - 3) {
264  sl.len = MAX_BUF - 3;
265  }
266 
267  script_monitor_str((char*)sl.buf);
268 
269  return SockList_Send(&sl, fd);
270 }
SockList_ReadPacket
bool SockList_ReadPacket(GSocketConnection c[static 1], SockList sl[static 1], size_t len, GError **error)
Definition: newsocket.c:213
LOG_INFO
@ LOG_INFO
Minor, non-harmful issues.
Definition: client.h:434
CS_Stats::ibytes
int ibytes
Definition: newclient.h:665
GetShort_String
short GetShort_String(const unsigned char *data)
Definition: newsocket.c:179
LOG_WARNING
@ LOG_WARNING
Warning that something might not work.
Definition: client.h:435
CLIENT_ERROR
#define CLIENT_ERROR
Definition: client.h:629
SockList_Init
void SockList_Init(SockList *sl, guint8 *buf)
Definition: newsocket.c:32
ClientSocket::fd
GSocketConnection * fd
Definition: client.h:124
SockList_Send
int SockList_Send(SockList *sl, GSocketConnection *c)
Definition: newsocket.c:112
SockList_AddShort
void SockList_AddShort(SockList *sl, guint16 data)
Definition: newsocket.c:64
SockList_AddChar
void SockList_AddChar(SockList *sl, char c)
Definition: newsocket.c:43
GetInt_String
int GetInt_String(const unsigned char *data)
Definition: newsocket.c:149
CLIENT_ERROR_TOOBIG
@ CLIENT_ERROR_TOOBIG
Definition: client.h:636
GetUShort_String
static guint16 GetUShort_String(const unsigned char data[static 2])
Definition: newsocket.c:197
SockList_AddInt
void SockList_AddInt(SockList *sl, guint32 data)
Definition: newsocket.c:80
in
static GInputStream * in
Definition: client.c:71
script_monitor_str
void script_monitor_str(const char *command)
Definition: script.c:943
MAX_BUF
#define MAX_BUF
Definition: client.h:40
debug_protocol
bool debug_protocol
Definition: main.c:61
SockList_AddString
void SockList_AddString(SockList *sl, const char *str)
Definition: newsocket.c:98
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:111
cs_print_string
int cs_print_string(GSocketConnection *fd, const char *str,...)
Definition: newsocket.c:252
csocket
ClientSocket csocket
Definition: client.c:70
SockList::len
size_t len
Definition: newclient.h:656
cst_tot
CS_Stats cst_tot
printable
char * printable(void *data, int len)
Definition: client.c:186
LOG_ERROR
@ LOG_ERROR
Warning that something definitely didn't work.
Definition: client.h:436
script.h
GetInt64_String
gint64 GetInt64_String(const unsigned char *data)
Definition: newsocket.c:161
GetChar_String
char GetChar_String(const unsigned char *data)
Definition: newsocket.c:137
cst_lst
CS_Stats cst_lst
Definition: newclient.h:671
SockList::buf
unsigned char buf[MAXSOCKBUF]
Definition: newclient.h:657
SockList
Definition: newclient.h:651
client.h