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