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 <assert.h>
24 #include <errno.h>
25 
26 #include "script.h"
27 
33 void SockList_Init(SockList *sl, guint8 *buf)
34 {
35  sl->len=0;
36  sl->buf=buf + 2; /* reserve two bytes for total length */
37 }
38 
44 void SockList_AddChar(SockList *sl, char c)
45 {
46  if (sl->len + 1 < MAX_BUF - 2){
47  sl->buf[sl->len++]=c;
48  }
49  else{
50  /*
51  * Cast c to an unsigned short so it displays correctly in the error message.
52  * Otherwise, it prints as a hexadecimal number in a funny box.
53  *
54  * SilverNexus 2014-06-12
55  */
56  LOG(LOG_ERROR,"SockList_AddChar","Could not write %hu to socket: Buffer full.\n", (unsigned short)c);
57  }
58 }
59 
65 void SockList_AddShort(SockList *sl, guint16 data)
66 {
67  if (sl->len + 2 < MAX_BUF - 2){
68  sl->buf[sl->len++] = (data>>8)&0xff;
69  sl->buf[sl->len++] = data & 0xff;
70  }
71  else{
72  LOG(LOG_ERROR,"SockList_AddShort","Could not write %hu to socket: Buffer full.\n", data);
73  }
74 }
75 
81 void SockList_AddInt(SockList *sl, guint32 data)
82 {
83  if (sl->len + 4 < MAX_BUF - 2){
84  sl->buf[sl->len++] = (data>>24)&0xff;
85  sl->buf[sl->len++] = (data>>16)&0xff;
86  sl->buf[sl->len++] = (data>>8)&0xff;
87  sl->buf[sl->len++] = data & 0xff;
88  }
89  else{
90  LOG(LOG_ERROR,"SockList_AddInt","Could not write %u to socket: Buffer full.\n", data);
91  }
92 }
93 
99 void SockList_AddString(SockList *sl, const char *str)
100 {
101  int len = strlen(str);
102 
103  if (sl->len + len > MAX_BUF-2) {
104  len = MAX_BUF-2 - sl->len;
105  }
106  memcpy(sl->buf + sl->len, str, len);
107  sl->len += len;
108 }
109 
113 int SockList_Send(SockList *sl, GSocketConnection* c) {
114  sl->buf[-2] = sl->len / 256;
115  sl->buf[-1] = sl->len % 256;
116  if (c == NULL) {
117  LOG(LOG_WARNING, "SockList_Send", "Sending data while not connected!");
118  return 1;
119  }
120  if (debug_protocol) {
121  char *data_print = printable(sl->buf, sl->len);
122  if (data_print != NULL) {
123  LOG(LOG_INFO, "C->S", "len=%d |%s|", sl->len, data_print);
124  free(data_print);
125  }
126  }
127  GOutputStream* out = g_io_stream_get_output_stream(G_IO_STREAM(c));
128  bool ret = g_output_stream_write_all(out, sl->buf - 2, sl->len + 2, NULL,
129  NULL, NULL);
130  return ret ? 0 : -1;
131 }
132 
138 char GetChar_String(const unsigned char *data)
139 {
140  return (data[0]);
141 }
142 
150 int GetInt_String(const unsigned char *data)
151 {
152  return ((data[0]<<24) + (data[1]<<16) + (data[2]<<8) + data[3]);
153 }
154 
162 gint64 GetInt64_String(const unsigned char *data)
163 {
164 #ifdef WIN32
165  return (((gint64)data[0]<<56) + ((gint64)data[1]<<48) +
166  ((gint64)data[2]<<40) + ((gint64)data[3]<<32) +
167  ((gint64)data[4]<<24) + ((gint64)data[5]<<16) + ((gint64)data[6]<<8) + (gint64)data[7]);
168 #else
169  return (((guint64)data[0]<<56) + ((guint64)data[1]<<48) +
170  ((guint64)data[2]<<40) + ((guint64)data[3]<<32) +
171  ((guint64)data[4]<<24) + (data[5]<<16) + (data[6]<<8) + data[7]);
172 #endif
173 }
174 
180 short GetShort_String(const unsigned char *data)
181 {
182  return ((data[0]<<8)+data[1]);
183 }
184 
198 static guint16 GetUShort_String(const unsigned char data[static 2]) // We want at least two characters.
199 {
200  return ((data[0]<<8)+data[1]);
201 }
202 
214 bool SockList_ReadPacket(GInputStream in[static 1], SockList sl[static 1], size_t len, GError** error) {
215  gsize read;
216  if (!g_input_stream_read_all(in, sl->buf, 2, &read, NULL, error)) {
217  return false;
218  }
219  if (read != 2) {
220  sl->len = 0;
221  return true;
222  }
223  size_t to_read = (size_t)GetUShort_String(sl->buf);
224  if (to_read + 2 > len) {
225  g_set_error(error, CLIENT_ERROR, CLIENT_ERROR_TOOBIG,
226  "Server packet too big");
227  return false;
228  }
229  if (!g_input_stream_read_all(in, sl->buf + 2, to_read, &read, NULL, error)) {
230  return false;
231  }
232  if (read != to_read) {
233  sl->len = 0;
234  return true;
235  }
236  sl->len = to_read + 2;
237 #ifdef CS_LOGSTATS
238  cst_tot.ibytes += sl->len;
239  cst_lst.ibytes += sl->len;
240 #endif
241  return true;
242 }
243 
251 int cs_print_string(GSocketConnection* fd, const char *str, ...)
252 {
253  va_list args;
254  SockList sl;
255  guint8 buf[MAX_BUF];
256 
257  SockList_Init(&sl, buf);
258  va_start(args, str);
259  sl.len += vsnprintf((char*)sl.buf + sl.len, MAX_BUF-sl.len-3, str, args); // need 2 bytes for length, 1 for null termination
260  va_end(args);
261  assert(sl.len <= MAX_BUF - 3);
262 
263  script_monitor_str((char*)sl.buf);
264 
265  return SockList_Send(&sl, fd);
266 }
LOG_INFO
@ LOG_INFO
Minor, non-harmful issues.
Definition: client.h:437
CS_Stats::ibytes
int ibytes
ibytes, obytes are bytes in, out.
Definition: newclient.h:668
GetShort_String
short GetShort_String(const unsigned char *data)
Definition: newsocket.c:180
LOG_WARNING
@ LOG_WARNING
Warning that something might not work.
Definition: client.h:438
CLIENT_ERROR
#define CLIENT_ERROR
Definition: client.h:632
SockList_Init
void SockList_Init(SockList *sl, guint8 *buf)
Definition: newsocket.c:33
SockList_Send
int SockList_Send(SockList *sl, GSocketConnection *c)
Send data from a socklist to the socket.
Definition: newsocket.c:113
SockList_AddShort
void SockList_AddShort(SockList *sl, guint16 data)
Definition: newsocket.c:65
SockList_AddChar
void SockList_AddChar(SockList *sl, char c)
Definition: newsocket.c:44
GetInt_String
int GetInt_String(const unsigned char *data)
The reverse of SockList_AddInt, but on strings instead.
Definition: newsocket.c:150
CLIENT_ERROR_TOOBIG
@ CLIENT_ERROR_TOOBIG
Definition: client.h:639
GetUShort_String
static guint16 GetUShort_String(const unsigned char data[static 2])
Get an unsigned short from the stream.
Definition: newsocket.c:198
SockList_AddInt
void SockList_AddInt(SockList *sl, guint32 data)
Definition: newsocket.c:81
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:65
SockList_AddString
void SockList_AddString(SockList *sl, const char *str)
Definition: newsocket.c:99
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Log messages of a certain importance to stderr.
Definition: misc.c:111
cs_print_string
int cs_print_string(GSocketConnection *fd, const char *str,...)
Send a printf-formatted packet to the socket.
Definition: newsocket.c:251
SockList::len
size_t len
Definition: newclient.h:659
cst_tot
CS_Stats cst_tot
SockList_ReadPacket
bool SockList_ReadPacket(GInputStream in[static 1], SockList sl[static 1], size_t len, GError **error)
Reads from the socket and puts data into a socklist.
Definition: newsocket.c:214
printable
char * printable(void *data, int len)
Replace the non-printable characters in 'data' with a dot ('.
Definition: client.c:186
LOG_ERROR
@ LOG_ERROR
Warning that something definitely didn't work.
Definition: client.h:439
script.h
GetInt64_String
gint64 GetInt64_String(const unsigned char *data)
The reverse of SockList_AddInt, but on strings instead.
Definition: newsocket.c:162
GetChar_String
char GetChar_String(const unsigned char *data)
Definition: newsocket.c:138
cst_lst
CS_Stats cst_lst
Definition: newclient.h:674
SockList::buf
unsigned char buf[MAXSOCKBUF]
Definition: newclient.h:660
SockList
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:654
client.h