Crossfire Client, Branches  R11627
newsocket.c
Go to the documentation of this file.
1 const char * const rcsid_common_newsocket_c =
2  "$Id: newsocket.c 9428 2008-07-08 06:31:53Z mwedel $";
3 /*
4  Crossfire client, a client program for the crossfire program.
5 
6  Copyright (C) 2001 Mark Wedel & Crossfire Development Team
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22  The author can be reached via e-mail to crossfire-devel@real-time.com
23 */
24 
25 /* Made this either client or server specific for 0.95.2 release - getting
26  * too complicated to keep them the same, and the common code is pretty much
27  * frozen now.
28  */
29 
30 
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <errno.h>
34 
35 #include <client.h>
36 #include <newclient.h>
37 #include <script.h>
38 
39 /* The LOG function is normally part of the libcross. If client compile,
40  * we need to supply something since some of the common code calls this.
41  */
42 /*void LOG (int logLevel, char *format, ...)
43 {
44 #ifdef DEBUG
45  va_list ap;
46  va_start(ap, format);
47  vfprintf(stderr, format, ap);
48  va_end(ap);
49 #endif
50 }*/
51 
52 
53 #define llevDebug LOG_DEBUG
54 #define llevError LOG_ERROR
55 
56 
57 /*
58  * This writes data to the socket.
59  */
60 static int write_socket(int fd, const unsigned char *buf, int len)
61 {
62  int amt=0;
63  const unsigned char *pos=buf;
64 
65  /* If we manage to write more than we wanted, take it as a bonus */
66  while (len>0) {
67  do {
68 #ifndef WIN32
69  amt=write(fd, pos, len);
70  } while ((amt<0) && ((errno==EINTR) || (errno=EAGAIN)));
71 #else
72  amt=send(fd, pos, len, 0);
73  } while ((amt<0) && (WSAGetLastError()==EINTR));
74 #endif
75 
76  if (amt < 0) { /* We got an error */
77  LOG(llevError,"write_socket","New socket (fd=%d) write failed: %s.\n", fd, strerror(errno));
78  return -1;
79  }
80  if (amt==0) {
81  LOG(llevError,"write_socket","Write_To_Socket: No data written out.\n");
82  }
83  len -= amt;
84  pos += amt;
85  }
86  return 0;
87 }
88 
89 
90 
91 void SockList_Init(SockList *sl, uint8 *buf)
92 {
93  sl->len=0;
94  sl->buf=buf + 2; /* reserve two bytes for total length */
95 }
96 
97 void SockList_AddChar(SockList *sl, char c)
98 {
99  sl->buf[sl->len++]=c;
100 }
101 
103 {
104  sl->buf[sl->len++] = (data>>8)&0xff;
105  sl->buf[sl->len++] = data & 0xff;
106 }
107 
108 
110 {
111  sl->buf[sl->len++] = (data>>24)&0xff;
112  sl->buf[sl->len++] = (data>>16)&0xff;
113  sl->buf[sl->len++] = (data>>8)&0xff;
114  sl->buf[sl->len++] = data & 0xff;
115 }
116 
117 void SockList_AddString(SockList *sl, const char *str)
118 {
119  int len = strlen(str);
120 
121  if (sl->len + len > MAX_BUF-2)
122  len = MAX_BUF-2 - sl->len;
123  memcpy(sl->buf + sl->len, str, len);
124  sl->len += len;
125 }
126 
127 int SockList_Send(SockList *sl, int fd)
128 {
129  sl->buf[-2] = sl->len / 256;
130  sl->buf[-1] = sl->len % 256;
131 
132  return write_socket(fd, sl->buf-2, sl->len+2);
133 }
134 
135 
136 char GetChar_String(const unsigned char *data)
137 {
138  return (data[0]);
139 }
140 /* Basically does the reverse of SockList_AddInt, but on
141  * strings instead. Same for the GetShort, but for 16 bits.
142  */
143 int GetInt_String(const unsigned char *data)
144 {
145  return ((data[0]<<24) + (data[1]<<16) + (data[2]<<8) + data[3]);
146 }
147 
148 /* 64 bit version of the above */
149 sint64 GetInt64_String(const unsigned char *data)
150 {
151 #ifdef WIN32
152  return (((sint64)data[0]<<56) + ((sint64)data[1]<<48) +
153  ((sint64)data[2]<<40) + ((sint64)data[3]<<32) +
154  ((sint64)data[4]<<24) + ((sint64)data[5]<<16) + ((sint64)data[6]<<8) + (sint64)data[7]);
155 #else
156  return (((uint64)data[0]<<56) + ((uint64)data[1]<<48) +
157  ((uint64)data[2]<<40) + ((uint64)data[3]<<32) +
158  ((uint64)data[4]<<24) + (data[5]<<16) + (data[6]<<8) + data[7]);
159 #endif
160 }
161 
162 short GetShort_String(const unsigned char *data) {
163  return ((data[0]<<8)+data[1]);
164 }
165 
166 /* This reads from fd and puts the data in sl. We return true if we think we
167  * have a full packet, 0 if we have a partial packet, or -1 if an error
168  * occurred. The only processing we do is remove the initial size value. len
169  * (As passed) is the size of the buffer allocated in the socklist. We make
170  * the assumption the buffer is at least 2 bytes long.
171  */
172 
173 int SockList_ReadPacket(int fd, SockList *sl, int len)
174 {
175  int stat,toread,readsome=0;
176 
177  /* We already have a partial packet */
178  if (sl->len<2) {
179  do {
180 #ifndef WIN32
181  stat=read(fd, sl->buf + sl->len, 2-sl->len);
182  } while ((stat==-1) && (errno==EINTR));
183 #else
184  stat=recv(fd, sl->buf + sl->len, 2-sl->len, 0);
185  } while ((stat==-1) && (WSAGetLastError()==EINTR));
186 #endif
187  if (stat<0) {
188  /* In non blocking mode, EAGAIN is set when there is no
189  * data available.
190  */
191 #ifndef WIN32
192  if (errno!=EAGAIN && errno!=EWOULDBLOCK) {
193 #else
194  if (WSAGetLastError()!=EAGAIN && WSAGetLastError()!=WSAEWOULDBLOCK) {
195 #endif
196  perror("ReadPacket got an error.");
197  LOG(llevDebug,"SockList_ReadPacket","ReadPacket got error %d, returning -1",errno);
198  return -1;
199  }
200  return 0; /*Error */
201  }
202  if (stat==0) return -1;
203  sl->len += stat;
204 #ifdef CS_LOGSTATS
205  cst_tot.ibytes += stat;
206  cst_lst.ibytes += stat;
207 #endif
208  if (stat<2) return 0; /* Still don't have a full packet */
209  readsome=1;
210  }
211  /* Figure out how much more data we need to read. Add 2 from the
212  * end of this - size header information is not included.
213  */
214  toread = 2+(sl->buf[0] << 8) + sl->buf[1] - sl->len;
215  if ((toread + sl->len) > len) {
216  LOG(llevError,"SockList_ReadPacket","Want to read more bytes than will fit in buffer.\n");
217  /* return error so the socket is closed */
218  return -1;
219  }
220  do {
221  do {
222 #ifndef WIN32
223  stat = read(fd, sl->buf+ sl->len, toread);
224  } while ((stat<0) && (errno==EINTR));
225 #else
226  stat = recv(fd, sl->buf+ sl->len, toread, 0);
227  } while ((stat<0) && (WSAGetLastError()==EINTR));
228 #endif
229  if (stat<0) {
230 #ifndef WIN32
231  if (errno!=EAGAIN && errno!=EWOULDBLOCK) {
232 #else
233  if (WSAGetLastError()!=EAGAIN && WSAGetLastError()!=WSAEWOULDBLOCK) {
234 #endif
235  perror("ReadPacket got an error.");
236  LOG(llevDebug,"SockList_ReadPacket","ReadPacket got error %d, returning 0",errno);
237  }
238  return 0; /*Error */
239  }
240  if (stat==0) return -1;
241  sl->len += stat;
242 #ifdef CS_LOGSTATS
243  cst_tot.ibytes += stat;
244  cst_lst.ibytes += stat;
245 #endif
246  toread -= stat;
247  if (toread==0) return 1;
248  if (toread < 0) {
249  LOG(llevError,"SockList_ReadPacket","SockList_ReadPacket: Read more bytes than desired.");
250  return 1;
251  }
252  } while (toread>0);
253  return 0;
254 }
255 
256 /*
257  * Send a printf-formatted packet to the socket.
258  */
259 int cs_print_string(int fd, const char *str, ...)
260 {
261  va_list args;
262  SockList sl;
263  uint8 buf[MAX_BUF];
264 
265  SockList_Init(&sl, buf);
266  va_start(args, str);
267  sl.len += vsprintf((char*)sl.buf + sl.len, str, args);
268  va_end(args);
269 
270  script_monitor_str((char*)sl.buf);
271 
272  return SockList_Send(&sl, fd);
273 }
void SockList_Init(SockList *sl, uint8 *buf)
Definition: newsocket.c:91
static int write_socket(int fd, const unsigned char *buf, int len)
Definition: newsocket.c:60
void script_monitor_str(const char *command)
Definition: script.c:872
short GetShort_String(const unsigned char *data)
Definition: newsocket.c:162
char GetChar_String(const unsigned char *data)
Definition: newsocket.c:136
int SockList_Send(SockList *sl, int fd)
Definition: newsocket.c:127
void SockList_AddInt(SockList *sl, uint32 data)
Definition: newsocket.c:109
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:178
#define llevError
Definition: newsocket.c:54
int SockList_ReadPacket(int fd, SockList *sl, int len)
Definition: newsocket.c:173
CS_Stats cst_lst
int cs_print_string(int fd, const char *str,...)
Definition: newsocket.c:259
int ibytes
Definition: newclient.h:577
void SockList_AddString(SockList *sl, const char *str)
Definition: newsocket.c:117
unsigned short uint16
Definition: client-types.h:79
#define llevDebug
Definition: newsocket.c:53
#define MAX_BUF
Definition: client-types.h:128
void SockList_AddChar(SockList *sl, char c)
Definition: newsocket.c:97
unsigned int uint32
Definition: client-types.h:77
unsigned char * buf
Definition: newclient.h:573
int len
Definition: newclient.h:572
CS_Stats cst_tot
void SockList_AddShort(SockList *sl, uint16 data)
Definition: newsocket.c:102
const char *const rcsid_common_newsocket_c
Definition: newsocket.c:1
unsigned char uint8
Definition: client-types.h:81
sint64 GetInt64_String(const unsigned char *data)
Definition: newsocket.c:149
int GetInt_String(const unsigned char *data)
Definition: newsocket.c:143