1 // net_wins.c
2
3 #include "../qcommon/qcommon.h"
4
5 #include <unistd.h>
6 #include <sys/socket.h>
7 #include <sys/time.h>
8 #include <netinet/in.h>
9 #include <arpa/inet.h>
10 #include <netdb.h>
11 #include <sys/param.h>
12 #include <sys/ioctl.h>
13 #include <sys/uio.h>
14 #include <errno.h>
15
16 #ifdef __linux__
17 #include <linux/types.h>
18 #include <linux/errqueue.h>
19 #else
20 #include <sys/types.h>
21 #endif
22
23 #ifdef NeXT
24 #include <libc.h>
25 #endif
26
27 static unsigned int net_inittime;
28
29 static unsigned long long net_total_in;
30 static unsigned long long net_total_out;
31 static unsigned long long net_packets_in;
32 static unsigned long long net_packets_out;
33
34 int server_port;
35 //netadr_t net_local_adr;
36
37 static int ip_sockets[2];
38
39 char *NET_ErrorString (void);
40
41 cvar_t *net_no_recverr;
42
43 //Aiee...
44 #include "../qcommon/net_common.c"
45
46 /*
47 =============
48 NET_StringToAdr
49
50 localhost
51 idnewt
52 idnewt:28000
53 192.246.40.70
54 192.246.40.70:28000
55 =============
56 */
57 /*qboolean NET_StringToSockaddr (char *s, struct sockaddr *sadr)
58 {
59 int isip = 0;
60 char *p;
61 struct hostent *h;
62 char *colon;
63 char copy[128];
64
65 memset (sadr, 0, sizeof(*sadr));
66
67 //r1: better than just the first digit for ip validity :)
68 p = s;
69 while (*p) {
70 if (*p == '.') {
71 isip++;
72 } else if (*p == ':') {
73 break;
74 } else if (!isdigit(*p)) {
75 isip = 0;
76 break;
77 }
78 p++;
79 }
80
81 ((struct sockaddr_in *)sadr)->sin_family = AF_INET;
82 ((struct sockaddr_in *)sadr)->sin_port = 0;
83
84 strncpy (copy, s, sizeof(copy)-1);
85
86 // strip off a trailing :port if present
87 for (colon = copy ; *colon ; colon++)
88 if (*colon == ':')
89 {
90 *colon = 0;
91 ((struct sockaddr_in *)sadr)->sin_port = htons((int16)atoi(colon+1));
92 }
93
94 if (isip)
95 {
96 *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
97 }
98 else
99 {
100 if (! (h = gethostbyname(copy)) )
101 return 0;
102 *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
103 }
104
105 return true;
106 }*/
107
108 /*
109 =============
110 NET_StringToAdr
111
112 localhost
113 idnewt
114 idnewt:28000
115 192.246.40.70
116 192.246.40.70:28000
117 =============
118 */
119 /*qboolean NET_StringToAdr (char *s, netadr_t *a)
120 {
121 struct sockaddr_in sadr;
122
123 if (!strcmp (s, "localhost"))
124 {
125 memset (a, 0, sizeof(*a));
126 a->type = NA_LOOPBACK;
127 return true;
128 }
129
130 if (!NET_StringToSockaddr (s, (struct sockaddr *)&sadr))
131 return false;
132
133 SockadrToNetadr (&sadr, a);
134
135 return true;
136 }*/
137
Net_Stats_f(void)138 void Net_Stats_f (void)
139 {
140 int now = time(0);
141 int diff = now - net_inittime;
142
143 Com_Printf ("Network up for %i seconds.\n"
144 "%llu bytes in %llu packets received (av: %i kbps)\n"
145 "%llu bytes in %llu packets sent (av: %i kbps)\n", LOG_NET,
146
147 diff,
148 net_total_in, net_packets_in, (int)(((net_total_in * 8) / 1024) / diff),
149 net_total_out, net_packets_out, (int)((net_total_out * 8) / 1024) / diff);
150 }
151
152 /*
153 =============================================================================
154
155 LOOPBACK BUFFERS FOR LOCAL PLAYER
156
157 =============================================================================
158 */
159
160
161 //=============================================================================
162
163 struct probehdr
164 {
165 uint32_t ttl;
166 struct timeval tv;
167 };
168
NET_GetPacket(netsrc_t sock,netadr_t * net_from,sizebuf_t * net_message)169 int NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
170 {
171 int ret;
172 struct sockaddr_in from;
173 uint32 fromlen;
174 int net_socket;
175 int err;
176
177 #ifndef DEDICATED_ONLY
178 if (NET_GetLoopPacket (sock, net_from, net_message))
179 return 1;
180 #endif
181
182 net_socket = ip_sockets[sock];
183
184 if (!net_socket)
185 return 0;
186
187 fromlen = sizeof(from);
188
189 ret = recvfrom (net_socket, net_message->data, net_message->maxsize
190 , 0, (struct sockaddr *)&from, &fromlen);
191
192 if (ret == -1)
193 {
194 #ifdef __linux__
195 //linux makes this needlessly complex, couldn't just return the source of the error in from, oh no...
196 struct probehdr rcvbuf;
197 struct iovec iov;
198 struct msghdr msg;
199 struct cmsghdr *cmsg;
200
201 char cbuf[1024];
202
203 struct sock_extended_err *e;
204
205 err = errno;
206
207 memset (&rcvbuf, 0, sizeof(rcvbuf));
208
209 iov.iov_base = &rcvbuf;
210 iov.iov_len = sizeof (rcvbuf);
211
212 memset (&from, 0, sizeof(from));
213
214 msg.msg_name = (void *)&from;
215 msg.msg_namelen = sizeof (from);
216 msg.msg_iov = &iov;
217 msg.msg_iovlen = 1;
218 msg.msg_flags = 0;
219 msg.msg_control = cbuf;
220 msg.msg_controllen = sizeof (cbuf);
221
222 for (;;)
223 {
224 ret = recvmsg (net_socket, &msg, MSG_ERRQUEUE);
225 if (ret == -1)
226 {
227 if (errno == EWOULDBLOCK || errno == EAGAIN)
228 {
229 if (err == EWOULDBLOCK || err == EAGAIN)
230 {
231 return 0;
232 }
233 else
234 {
235 errno = err;
236 Com_Printf ("NET_GetPacket: %s\n", LOG_NET, NET_ErrorString());
237 return 0;
238 }
239 }
240 else
241 {
242 Com_DPrintf ("NET_GetPacket: recvmsg(): %s\n", NET_ErrorString());
243 return 0;
244 }
245 }
246 else if (!ret)
247 {
248 Com_DPrintf ("NET_GetPacket: recvmsg(): EOF\n");
249 return 0;
250 }
251
252 errno = err;
253 Com_DPrintf ("NET_GetPacket: Called recvmsg() for extended error details for %s\n", NET_ErrorString());
254
255 //linux 2.2 (maybe others) fails to properly fill in the msg_name structure.
256 Com_DPrintf ("(msgname) family %d, host: %s, port: %d, flags: %d\n", from.sin_family, inet_ntoa (from.sin_addr), from.sin_port, msg.msg_flags);
257
258 e = NULL;
259
260 for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg))
261 {
262 if (cmsg->cmsg_level == SOL_IP)
263 {
264 if (cmsg->cmsg_type == IP_RECVERR)
265 {
266 e = (struct sock_extended_err *) CMSG_DATA (cmsg);
267 }
268 else
269 Com_DPrintf ("cmsg type = %d\n", cmsg->cmsg_type);
270 }
271 }
272
273 if (!e)
274 {
275 Com_DPrintf ("NET_GetPacket: recvmsg(): no extended info available\n");
276 continue;
277 }
278
279 if (e->ee_origin == SO_EE_ORIGIN_ICMP)
280 {
281 //for some unknown reason, the kernel zeroes out the port in SO_EE_OFFENDER, so this is pretty much useless
282 struct sockaddr_in *sin = (struct sockaddr_in *)SO_EE_OFFENDER(e);
283 Com_DPrintf ("(ICMP) family %d, host: %s, port: %d\n", sin->sin_family, inet_ntoa (sin->sin_addr), sin->sin_port);
284
285 //but better than nothing if using buggy kernel?
286 if (from.sin_family == AF_UNSPEC)
287 {
288 memcpy (&from, sin, sizeof(from));
289 //can't trust port, may be buggy kernel (again)
290 from.sin_port = 0;
291 }
292 }
293 else
294 {
295 Com_DPrintf ("NET_GetPacket: recvmsg(): error origin is %d\n", e->ee_origin);
296 continue;
297 }
298
299 SockadrToNetadr (&from, net_from);
300
301 switch (e->ee_errno)
302 {
303 case ECONNREFUSED:
304 case EHOSTUNREACH:
305 case ENETUNREACH:
306 Com_Printf ("NET_GetPacket: %s from %s\n", LOG_NET, strerror(e->ee_errno), NET_AdrToString (net_from));
307 if (net_ignore_icmp->intvalue)
308 return 0;
309 else
310 return -1;
311 default:
312 Com_Printf ("NET_GetPacket: %s from %s\n", LOG_NET, strerror(e->ee_errno), NET_AdrToString (net_from));
313 continue;
314 }
315 }
316 #else
317 err = errno;
318
319 if (err == EWOULDBLOCK)
320 return 0;
321 if (err == ECONNREFUSED)
322 {
323 SockadrToNetadr (&from, net_from);
324 Com_Printf ("NET_GetPacket: %s from %s\n", LOG_NET, NET_ErrorString(), NET_AdrToString (net_from));
325 return -1;
326 }
327 Com_Printf ("NET_GetPacket: %s\n", LOG_NET, NET_ErrorString());
328 #endif
329 return 0;
330 }
331
332 net_packets_in++;
333 net_total_in += ret;
334
335 SockadrToNetadr (&from, net_from);
336
337 if (ret == net_message->maxsize)
338 {
339 Com_Printf ("Oversize packet from %s\n", LOG_NET, NET_AdrToString (net_from));
340 return 0;
341 }
342
343 net_message->cursize = ret;
344
345 return 1;
346 }
347
348
349 //=============================================================================
350
NET_SendPacket(netsrc_t sock,int length,const void * data,netadr_t * to)351 int NET_SendPacket (netsrc_t sock, int length, const void *data, netadr_t *to)
352 {
353 int ret;
354 struct sockaddr_in addr;
355 int net_socket;
356
357 if (to->type == NA_IP)
358 {
359 net_socket = ip_sockets[sock];
360 if (!net_socket)
361 return 0;
362 }
363 #ifndef DEDICATED_ONLY
364 else if ( to->type == NA_LOOPBACK )
365 {
366 NET_SendLoopPacket (sock, length, data);
367 return 1;
368 }
369 #endif
370 else if (to->type == NA_BROADCAST)
371 {
372 net_socket = ip_sockets[sock];
373 if (!net_socket)
374 return 0;
375 }
376 else
377 {
378 Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
379 return 0;
380 }
381
382 NetadrToSockadr (to, &addr);
383
384 ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) );
385 if (ret == -1)
386 {
387 Com_Printf ("NET_SendPacket to %s: ERROR: %s\n", LOG_NET, NET_AdrToString(to), NET_ErrorString());
388 return 0;
389 }
390
391 net_packets_out++;
392 net_total_out += ret;
393 return 1;
394 }
395
396 //=============================================================================
397
398 /*
399 ====================
400 NET_Init
401 ====================
402 */
NET_Init(void)403 void NET_Init (void)
404 {
405 NET_Common_Init ();
406 net_no_recverr = Cvar_Get ("net_no_recverr", "0", 0);
407 }
408
409
410 /*
411 ====================
412 NET_Socket
413 ====================
414 */
NET_IPSocket(char * net_interface,int port)415 int NET_IPSocket (char *net_interface, int port)
416 {
417 int newsocket;
418 struct sockaddr_in address;
419 qboolean _true = true;
420 int i = 1;
421
422 if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
423 {
424 Com_Printf ("UDP_OpenSocket: Couldn't make socket: %s\n", LOG_NET, NET_ErrorString());
425 return 0;
426 }
427
428 if (newsocket >= FD_SETSIZE)
429 Com_Error (ERR_FATAL, "NET_IPSocket: socket is higher than FD_SETSIZE");
430
431 // make it non-blocking
432 if (ioctl (newsocket, FIONBIO, &_true) == -1)
433 {
434 Com_Printf ("UDP_OpenSocket: Couldn't make non-blocking: %s\n", LOG_NET, NET_ErrorString());
435 return 0;
436 }
437
438 // make it broadcast capable
439 if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
440 {
441 Com_Printf ("UDP_OpenSocket: Couldn't set SO_BROADCAST: %s\n", LOG_NET, NET_ErrorString());
442 return 0;
443 }
444
445 #ifdef __linux__
446 // r1: accept icmp unreachables for quick disconnects
447 if (!net_no_recverr->intvalue)
448 {
449 if (setsockopt (newsocket, IPPROTO_IP, IP_RECVERR, (char *)&i, sizeof(i)) == -1)
450 {
451 Com_Printf ("UDP_OpenSocket: Couldn't set IP_RECVERR: %s\n", LOG_NET, NET_ErrorString());
452 }
453 }
454 #endif
455
456 if (!net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost"))
457 address.sin_addr.s_addr = INADDR_ANY;
458 else
459 NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
460
461 if (port == PORT_ANY)
462 address.sin_port = 0;
463 else
464 address.sin_port = htons((uint16)port);
465
466 address.sin_family = AF_INET;
467
468 if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
469 {
470 close (newsocket);
471 Com_Printf ("UDP_OpenSocket: Couldn't bind to UDP port %d: %s\n", LOG_NET, port, NET_ErrorString());
472 return 0;
473 }
474
475 return newsocket;
476 }
477
478
479 /*
480 ====================
481 NET_Shutdown
482 ====================
483 */
NET_Shutdown(void)484 void NET_Shutdown (void)
485 {
486 NET_Config (NET_NONE); // close sockets
487 }
488
489
490 /*
491 ====================
492 NET_ErrorString
493 ====================
494 */
NET_ErrorString(void)495 char *NET_ErrorString (void)
496 {
497 int code;
498
499 code = errno;
500 return strerror (code);
501 }
502
503
504