1 /*
2 * XPilot NG, a multiplayer space war game.
3 *
4 * Copyright (C) 2000-2002 Uoti Urpala <uau@users.sourceforge.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "xpserver.h"
22
23 /* RECORDING WON'T WORK PROPERLY ON WINDOWS BECAUSE OF
24 * errno = WSAGetLastError();
25 */
26
sock_closeRec(sock_t * sock)27 int sock_closeRec(sock_t *sock)
28 {
29 if (playback)
30 return 0; /* no recording code checks this value */
31 return sock_close(sock);
32 }
33
34
sock_connectRec(sock_t * sock,char * host,int port)35 int sock_connectRec(sock_t *sock, char *host, int port)
36 {
37 int i;
38
39 if (playback) {
40 i = *playback_ints++;
41 if (i < 0)
42 errno = *playback_errnos++;
43 return i;
44 }
45 i = sock_connect(sock, host, port);
46 if (record) {
47 *(playback_ints++) = i;
48 if (i<0)
49 *playback_errnos++ = i;
50 }
51 return i;
52 }
53
54
sock_get_last_portRec(sock_t * sock)55 int sock_get_last_portRec(sock_t *sock)
56 {
57 int i;
58
59 if (playback)
60 return *(playback_ints++);
61 i = sock_get_last_port(sock);
62 if (record)
63 *playback_ints++ = i;
64 return i;
65 }
66
67
sock_receive_anyRec(sock_t * sock,char * rbuf,int size)68 int sock_receive_anyRec(sock_t *sock, char *rbuf, int size)
69 {
70 int i;
71
72 if (playback) {
73 i = *(playback_shorts++);
74 if (i > 0) {
75 memcpy(rbuf, playback_data, (size_t)i);
76 playback_data += i;
77 }
78 else
79 errno = *playback_errnos++;
80 return i;
81 }
82 i = sock_receive_any(sock, rbuf, size);
83 if (record) {
84 *(playback_shorts++) = i;
85 if (i > 0) {
86 memcpy(playback_data, rbuf, (size_t)i);
87 playback_data += i;
88 }
89 else
90 *playback_errnos++ = errno;
91 }
92 return i;
93 }
94
95
sock_readRec(sock_t * sock,char * rbuf,int size)96 int sock_readRec(sock_t *sock, char *rbuf, int size)
97 {
98 int i;
99
100 if (playback) {
101 i = *(playback_shorts++);
102 if (i > 0) {
103 memcpy(rbuf, playback_data, (size_t)i);
104 playback_data += i;
105 }
106 else
107 errno = *playback_errnos++;
108 return i;
109 }
110 i = sock_read(sock, rbuf, size);
111 if (record) {
112 *(playback_shorts++) = i;
113 if (i > 0) {
114 memcpy(playback_data, rbuf, (size_t)i);
115 playback_data += i;
116 }
117 else
118 *playback_errnos++ = errno;
119 }
120 return i;
121 }
122
123
sock_writeRec(sock_t * sock,char * wbuf,int size)124 int sock_writeRec(sock_t *sock, char *wbuf, int size)
125 {
126 int i;
127
128 if (playback) {
129 return size;
130 /*
131 errno = *(playback_ints++);
132 return *(playback_ints++);
133 */
134 }
135 i = sock_write(sock, wbuf, size);
136 if (record) {
137 /*
138 *(playback_ints++) = errno;
139 *(playback_ints++) = i;
140 */
141 }
142 if (record && i < size)
143 error("Warning: DgramWrite failed, recording doesn't handle this");
144 return i;
145 }
146
147
sock_get_errorRec(sock_t * sock)148 int sock_get_errorRec(sock_t *sock)
149 {
150 int i;
151
152 if (playback) {
153 errno = *(playback_errnos++);
154 return *(playback_ints++);
155 }
156 i = sock_get_error(sock);
157 if (record) {
158 *(playback_errnos++) = errno;
159 *(playback_ints++) = i;
160 }
161 return i;
162 }
163
164
Sockbuf_flushRec(sockbuf_t * sbuf)165 int Sockbuf_flushRec(sockbuf_t *sbuf)
166 {
167 int len,
168 i;
169
170 if (BIT(sbuf->state, SOCKBUF_WRITE) == 0) {
171 warn("No flush on non-writable socket buffer");
172 warn("(state=%02x,buf=%08x,ptr=%08x,size=%d,len=%d,sock=%d)",
173 sbuf->state, sbuf->buf, sbuf->ptr, sbuf->size, sbuf->len,
174 sbuf->sock);
175 return -1;
176 }
177 if (BIT(sbuf->state, SOCKBUF_LOCK) != 0) {
178 warn("No flush on locked socket buffer (0x%02x)", sbuf->state);
179 return -1;
180 }
181 if (sbuf->len <= 0) {
182 if (sbuf->len < 0) {
183 warn("Write socket buffer length negative");
184 sbuf->len = 0;
185 sbuf->ptr = sbuf->buf;
186 }
187 return 0;
188 }
189
190 if (BIT(sbuf->state, SOCKBUF_DGRAM) != 0) {
191 errno = 0;
192 i = 0;
193 while ((len = sock_writeRec(&sbuf->sock, sbuf->buf, sbuf->len)) <= 0) {
194 if (len == 0
195 || errno == EWOULDBLOCK
196 || errno == EAGAIN) {
197 Sockbuf_clear(sbuf);
198 return 0;
199 }
200 if (errno == EINTR) {
201 errno = 0;
202 continue;
203 }
204 if (++i > MAX_SOCKBUF_RETRIES) {
205 error("Can't send on socket (%d,%d)", sbuf->sock, sbuf->len);
206 Sockbuf_clear(sbuf);
207 return -1;
208 }
209 { static int send_err;
210 if ((send_err++ & 0x3F) == 0) {
211 error("send (%d)", i);
212 }
213 }
214 if (sock_get_errorRec(&sbuf->sock) == -1) {
215 error("sock_get_error send");
216 return -1;
217 }
218 errno = 0;
219 }
220 if (len != sbuf->len) {
221 errno = 0;
222 error("Can't write complete datagram (%d,%d)", len, sbuf->len);
223 }
224 Sockbuf_clear(sbuf);
225 } else {
226 errno = 0;
227 while ((len = sock_writeRec(&sbuf->sock, sbuf->buf, sbuf->len)) <= 0) {
228 if (errno == EINTR) {
229 errno = 0;
230 continue;
231 }
232 if (errno != EWOULDBLOCK
233 && errno != EAGAIN) {
234 error("Can't write on socket");
235 return -1;
236 }
237 return 0;
238 }
239 Sockbuf_advance(sbuf, len);
240 }
241 return len;
242 }
243
244
Sockbuf_readRec(sockbuf_t * sbuf)245 int Sockbuf_readRec(sockbuf_t *sbuf)
246 {
247 int max,
248 i,
249 len;
250
251 if (BIT(sbuf->state, SOCKBUF_READ) == 0) {
252 warn("No read from non-readable socket buffer (%d)", sbuf->state);
253 return -1;
254 }
255 if (BIT(sbuf->state, SOCKBUF_LOCK) != 0) {
256 return 0;
257 }
258 if (sbuf->ptr > sbuf->buf) {
259 Sockbuf_advance(sbuf, sbuf->ptr - sbuf->buf);
260 }
261 if ((max = sbuf->size - sbuf->len) <= 0) {
262 static int before;
263 if (before++ == 0) {
264 warn("Read socket buffer not big enough (%d,%d)",
265 sbuf->size, sbuf->len);
266 }
267 return -1;
268 }
269 if (BIT(sbuf->state, SOCKBUF_DGRAM) != 0) {
270 errno = 0;
271 i = 0;
272 while ((len = sock_readRec(&sbuf->sock, sbuf->buf + sbuf->len, max)) <= 0) {
273 if (len == 0) {
274 return 0;
275 }
276 #ifdef _WINDOWS
277 errno = WSAGetLastError();
278 #endif
279 if (errno == EINTR) {
280 errno = 0;
281 continue;
282 }
283 if (errno == EWOULDBLOCK
284 || errno == EAGAIN) {
285 return 0;
286 }
287 if (++i > MAX_SOCKBUF_RETRIES) {
288 error("Can't recv on socket");
289 return -1;
290 }
291 { static int recv_err;
292 if ((recv_err++ & 0x3F) == 0) {
293 error("recv (%d)", i);
294 }
295 }
296 if (sock_get_errorRec(&sbuf->sock) == -1) {
297 error("sock_get_error recv");
298 return -1;
299 }
300 errno = 0;
301 }
302 sbuf->len += len;
303 } else {
304 errno = 0;
305 while ((len = sock_readRec(&sbuf->sock, sbuf->buf + sbuf->len, max)) <= 0) {
306 if (len == 0) {
307 return 0;
308 }
309 if (errno == EINTR) {
310 errno = 0;
311 continue;
312 }
313 if (errno != EWOULDBLOCK
314 && errno != EAGAIN) {
315 error("Can't read on socket");
316 return -1;
317 }
318 return 0;
319 }
320 sbuf->len += len;
321 }
322
323 return sbuf->len;
324 }
325
326
Sockbuf_writeRec(sockbuf_t * sbuf,char * buf,int len)327 int Sockbuf_writeRec(sockbuf_t *sbuf, char *buf, int len)
328 {
329 if (BIT(sbuf->state, SOCKBUF_WRITE) == 0) {
330 warn("No write to non-writable socket buffer");
331 return -1;
332 }
333 if (sbuf->size - sbuf->len < len) {
334 if (BIT(sbuf->state, SOCKBUF_LOCK | SOCKBUF_DGRAM) != 0) {
335 warn("No write to locked socket buffer (%d,%d,%d,%d)",
336 sbuf->state, sbuf->size, sbuf->len, len);
337 return -1;
338 }
339 if (Sockbuf_flushRec(sbuf) == -1)
340 return -1;
341 if (sbuf->size - sbuf->len < len)
342 return 0;
343 }
344 memcpy(sbuf->buf + sbuf->len, buf, (size_t)len);
345 sbuf->len += len;
346
347 return len;
348 }
349