Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 1
/*
2
Copyright (C) 1996-1997 Id Software, Inc.
3
 
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License
6
as published by the Free Software Foundation; either version 2
7
of the License, or (at your option) any later version.
8
 
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
 
13
See the GNU General Public License for more details.
14
 
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
 
19
*/
20
// net_dgrm.c
21
 
22
// This is enables a simple IP banning mechanism
23
#define BAN_TEST
24
 
25
#ifdef BAN_TEST
26
#if defined(_WIN32)
27
#include 
28
#elif defined (NeXT)
29
#include 
30
#include 
31
#else
32
#define AF_INET 		2	/* internet */
33
struct in_addr
34
{
35
	union
36
	{
37
		struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b;
38
		struct { unsigned short s_w1,s_w2; } S_un_w;
39
		unsigned long S_addr;
40
	} S_un;
41
};
42
#define	s_addr	S_un.S_addr	/* can be used for most tcp & ip code */
43
struct sockaddr_in
44
{
45
    short			sin_family;
46
    unsigned short	sin_port;
47
	struct in_addr	sin_addr;
48
    char			sin_zero[8];
49
};
50
char *inet_ntoa(struct in_addr in);
51
unsigned long inet_addr(const char *cp);
52
#endif
53
#endif	// BAN_TEST
54
 
55
#include "quakedef.h"
56
#include "net_dgrm.h"
57
 
58
// these two macros are to make the code more readable
59
#define sfunc	net_landrivers[sock->landriver]
60
#define dfunc	net_landrivers[net_landriverlevel]
61
 
62
static int net_landriverlevel;
63
 
64
/* statistic counters */
65
int	packetsSent = 0;
66
int	packetsReSent = 0;
67
int packetsReceived = 0;
68
int receivedDuplicateCount = 0;
69
int shortPacketCount = 0;
70
int droppedDatagrams;
71
 
72
static int myDriverLevel;
73
 
74
struct
75
{
76
	unsigned int	length;
77
	unsigned int	sequence;
78
	byte			data[MAX_DATAGRAM];
79
} packetBuffer;
80
 
81
extern int m_return_state;
82
extern int m_state;
83
extern qboolean m_return_onerror;
84
extern char m_return_reason[32];
85
 
86
 
87
#ifdef DEBUG
88
char *StrAddr (struct qsockaddr *addr)
89
{
90
	static char buf[34];
91
	byte *p = (byte *)addr;
92
	int n;
93
 
94
	for (n = 0; n < 16; n++)
95
		sprintf (buf + n * 2, "%02x", *p++);
96
	return buf;
97
}
98
#endif
99
 
100
 
101
#ifdef BAN_TEST
102
unsigned long banAddr = 0x00000000;
103
unsigned long banMask = 0xffffffff;
104
 
105
void NET_Ban_f (void)
106
{
107
	char	addrStr [32];
108
	char	maskStr [32];
109
	void	(*print) (char *fmt, ...);
110
 
111
	if (cmd_source == src_command)
112
	{
113
		if (!sv.active)
114
		{
115
			Cmd_ForwardToServer ();
116
			return;
117
		}
118
		print = Con_Printf;
119
	}
120
	else
121
	{
122
		if (pr_global_struct->deathmatch && !host_client->privileged)
123
			return;
124
		print = SV_ClientPrintf;
125
	}
126
 
127
	switch (Cmd_Argc ())
128
	{
129
		case 1:
130
			if (((struct in_addr *)&banAddr)->s_addr)
131
			{
132
				Q_strcpy(addrStr, inet_ntoa(*(struct in_addr *)&banAddr));
133
				Q_strcpy(maskStr, inet_ntoa(*(struct in_addr *)&banMask));
134
				print("Banning %s [%s]\n", addrStr, maskStr);
135
			}
136
			else
137
				print("Banning not active\n");
138
			break;
139
 
140
		case 2:
141
			if (Q_strcasecmp(Cmd_Argv(1), "off") == 0)
142
				banAddr = 0x00000000;
143
			else
144
				banAddr = inet_addr(Cmd_Argv(1));
145
			banMask = 0xffffffff;
146
			break;
147
 
148
		case 3:
149
			banAddr = inet_addr(Cmd_Argv(1));
150
			banMask = inet_addr(Cmd_Argv(2));
151
			break;
152
 
153
		default:
154
			print("BAN ip_address [mask]\n");
155
			break;
156
	}
157
}
158
#endif
159
 
160
 
161
int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data)
162
{
163
	unsigned int	packetLen;
164
	unsigned int	dataLen;
165
	unsigned int	eom;
166
 
167
#ifdef DEBUG
168
	if (data->cursize == 0)
169
		Sys_Error("Datagram_SendMessage: zero length message\n");
170
 
171
	if (data->cursize > NET_MAXMESSAGE)
172
		Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize);
173
 
174
	if (sock->canSend == false)
175
		Sys_Error("SendMessage: called with canSend == false\n");
176
#endif
177
 
178
	Q_memcpy(sock->sendMessage, data->data, data->cursize);
179
	sock->sendMessageLength = data->cursize;
180
 
181
	if (data->cursize <= MAX_DATAGRAM)
182
	{
183
		dataLen = data->cursize;
184
		eom = NETFLAG_EOM;
185
	}
186
	else
187
	{
188
		dataLen = MAX_DATAGRAM;
189
		eom = 0;
190
	}
191
	packetLen = NET_HEADERSIZE + dataLen;
192
 
193
	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
194
	packetBuffer.sequence = BigLong(sock->sendSequence++);
195
	Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);
196
 
197
	sock->canSend = false;
198
 
199
	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
200
		return -1;
201
 
202
	sock->lastSendTime = net_time;
203
	packetsSent++;
204
	return 1;
205
}
206
 
207
 
208
int SendMessageNext (qsocket_t *sock)
209
{
210
	unsigned int	packetLen;
211
	unsigned int	dataLen;
212
	unsigned int	eom;
213
 
214
	if (sock->sendMessageLength <= MAX_DATAGRAM)
215
	{
216
		dataLen = sock->sendMessageLength;
217
		eom = NETFLAG_EOM;
218
	}
219
	else
220
	{
221
		dataLen = MAX_DATAGRAM;
222
		eom = 0;
223
	}
224
	packetLen = NET_HEADERSIZE + dataLen;
225
 
226
	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
227
	packetBuffer.sequence = BigLong(sock->sendSequence++);
228
	Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);
229
 
230
	sock->sendNext = false;
231
 
232
	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
233
		return -1;
234
 
235
	sock->lastSendTime = net_time;
236
	packetsSent++;
237
	return 1;
238
}
239
 
240
 
241
int ReSendMessage (qsocket_t *sock)
242
{
243
	unsigned int	packetLen;
244
	unsigned int	dataLen;
245
	unsigned int	eom;
246
 
247
	if (sock->sendMessageLength <= MAX_DATAGRAM)
248
	{
249
		dataLen = sock->sendMessageLength;
250
		eom = NETFLAG_EOM;
251
	}
252
	else
253
	{
254
		dataLen = MAX_DATAGRAM;
255
		eom = 0;
256
	}
257
	packetLen = NET_HEADERSIZE + dataLen;
258
 
259
	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
260
	packetBuffer.sequence = BigLong(sock->sendSequence - 1);
261
	Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);
262
 
263
	sock->sendNext = false;
264
 
265
	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
266
		return -1;
267
 
268
	sock->lastSendTime = net_time;
269
	packetsReSent++;
270
	return 1;
271
}
272
 
273
 
274
qboolean Datagram_CanSendMessage (qsocket_t *sock)
275
{
276
	if (sock->sendNext)
277
		SendMessageNext (sock);
278
 
279
	return sock->canSend;
280
}
281
 
282
 
283
qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock)
284
{
285
	return true;
286
}
287
 
288
 
289
int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
290
{
291
	int 	packetLen;
292
 
293
#ifdef DEBUG
294
	if (data->cursize == 0)
295
		Sys_Error("Datagram_SendUnreliableMessage: zero length message\n");
296
 
297
	if (data->cursize > MAX_DATAGRAM)
298
		Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize);
299
#endif
300
 
301
	packetLen = NET_HEADERSIZE + data->cursize;
302
 
303
	packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE);
304
	packetBuffer.sequence = BigLong(sock->unreliableSendSequence++);
305
	Q_memcpy (packetBuffer.data, data->data, data->cursize);
306
 
307
	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
308
		return -1;
309
 
310
	packetsSent++;
311
	return 1;
312
}
313
 
314
 
315
int	Datagram_GetMessage (qsocket_t *sock)
316
{
317
	unsigned int	length;
318
	unsigned int	flags;
319
	int				ret = 0;
320
	struct qsockaddr readaddr;
321
	unsigned int	sequence;
322
	unsigned int	count;
323
 
324
	if (!sock->canSend)
325
		if ((net_time - sock->lastSendTime) > 1.0)
326
			ReSendMessage (sock);
327
 
328
	while(1)
329
	{
330
		length = sfunc.Read (sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);
331
 
332
//	if ((rand() & 255) > 220)
333
//		continue;
334
 
335
		if (length == 0)
336
			break;
337
 
338
		if (length == -1)
339
		{
340
			Con_Printf("Read error\n");
341
			return -1;
342
		}
343
 
344
		if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0)
345
		{
346
#ifdef DEBUG
347
			Con_DPrintf("Forged packet received\n");
348
			Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr));
349
			Con_DPrintf("Received: %s\n", StrAddr (&readaddr));
350
#endif
351
			continue;
352
		}
353
 
354
		if (length < NET_HEADERSIZE)
355
		{
356
			shortPacketCount++;
357
			continue;
358
		}
359
 
360
		length = BigLong(packetBuffer.length);
361
		flags = length & (~NETFLAG_LENGTH_MASK);
362
		length &= NETFLAG_LENGTH_MASK;
363
 
364
		if (flags & NETFLAG_CTL)
365
			continue;
366
 
367
		sequence = BigLong(packetBuffer.sequence);
368
		packetsReceived++;
369
 
370
		if (flags & NETFLAG_UNRELIABLE)
371
		{
372
			if (sequence < sock->unreliableReceiveSequence)
373
			{
374
				Con_DPrintf("Got a stale datagram\n");
375
				ret = 0;
376
				break;
377
			}
378
			if (sequence != sock->unreliableReceiveSequence)
379
			{
380
				count = sequence - sock->unreliableReceiveSequence;
381
				droppedDatagrams += count;
382
				Con_DPrintf("Dropped %u datagram(s)\n", count);
383
			}
384
			sock->unreliableReceiveSequence = sequence + 1;
385
 
386
			length -= NET_HEADERSIZE;
387
 
388
			SZ_Clear (&net_message);
389
			SZ_Write (&net_message, packetBuffer.data, length);
390
 
391
			ret = 2;
392
			break;
393
		}
394
 
395
		if (flags & NETFLAG_ACK)
396
		{
397
			if (sequence != (sock->sendSequence - 1))
398
			{
399
				Con_DPrintf("Stale ACK received\n");
400
				continue;
401
			}
402
			if (sequence == sock->ackSequence)
403
			{
404
				sock->ackSequence++;
405
				if (sock->ackSequence != sock->sendSequence)
406
					Con_DPrintf("ack sequencing error\n");
407
			}
408
			else
409
			{
410
				Con_DPrintf("Duplicate ACK received\n");
411
				continue;
412
			}
413
			sock->sendMessageLength -= MAX_DATAGRAM;
414
			if (sock->sendMessageLength > 0)
415
			{
416
				Q_memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);
417
				sock->sendNext = true;
418
			}
419
			else
420
			{
421
				sock->sendMessageLength = 0;
422
				sock->canSend = true;
423
			}
424
			continue;
425
		}
426
 
427
		if (flags & NETFLAG_DATA)
428
		{
429
			packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);
430
			packetBuffer.sequence = BigLong(sequence);
431
			sfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr);
432
 
433
			if (sequence != sock->receiveSequence)
434
			{
435
				receivedDuplicateCount++;
436
				continue;
437
			}
438
			sock->receiveSequence++;
439
 
440
			length -= NET_HEADERSIZE;
441
 
442
			if (flags & NETFLAG_EOM)
443
			{
444
				SZ_Clear(&net_message);
445
				SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);
446
				SZ_Write(&net_message, packetBuffer.data, length);
447
				sock->receiveMessageLength = 0;
448
 
449
				ret = 1;
450
				break;
451
			}
452
 
453
			Q_memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);
454
			sock->receiveMessageLength += length;
455
			continue;
456
		}
457
	}
458
 
459
	if (sock->sendNext)
460
		SendMessageNext (sock);
461
 
462
	return ret;
463
}
464
 
465
 
466
void PrintStats(qsocket_t *s)
467
{
468
	Con_Printf("canSend = %4u   \n", s->canSend);
469
	Con_Printf("sendSeq = %4u   ", s->sendSequence);
470
	Con_Printf("recvSeq = %4u   \n", s->receiveSequence);
471
	Con_Printf("\n");
472
}
473
 
474
void NET_Stats_f (void)
475
{
476
	qsocket_t	*s;
477
 
478
	if (Cmd_Argc () == 1)
479
	{
480
		Con_Printf("unreliable messages sent   = %i\n", unreliableMessagesSent);
481
		Con_Printf("unreliable messages recv   = %i\n", unreliableMessagesReceived);
482
		Con_Printf("reliable messages sent     = %i\n", messagesSent);
483
		Con_Printf("reliable messages received = %i\n", messagesReceived);
484
		Con_Printf("packetsSent                = %i\n", packetsSent);
485
		Con_Printf("packetsReSent              = %i\n", packetsReSent);
486
		Con_Printf("packetsReceived            = %i\n", packetsReceived);
487
		Con_Printf("receivedDuplicateCount     = %i\n", receivedDuplicateCount);
488
		Con_Printf("shortPacketCount           = %i\n", shortPacketCount);
489
		Con_Printf("droppedDatagrams           = %i\n", droppedDatagrams);
490
	}
491
	else if (Q_strcmp(Cmd_Argv(1), "*") == 0)
492
	{
493
		for (s = net_activeSockets; s; s = s->next)
494
			PrintStats(s);
495
		for (s = net_freeSockets; s; s = s->next)
496
			PrintStats(s);
497
	}
498
	else
499
	{
500
		for (s = net_activeSockets; s; s = s->next)
501
			if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0)
502
				break;
503
		if (s == NULL)
504
			for (s = net_freeSockets; s; s = s->next)
505
				if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0)
506
					break;
507
		if (s == NULL)
508
			return;
509
		PrintStats(s);
510
	}
511
}
512
 
513
 
514
static qboolean testInProgress = false;
515
static int		testPollCount;
516
static int		testDriver;
517
static int		testSocket;
518
 
519
static void Test_Poll(void);
520
PollProcedure	testPollProcedure = {NULL, 0.0, Test_Poll};
521
 
522
static void Test_Poll(void)
523
{
524
	struct qsockaddr clientaddr;
525
	int		control;
526
	int		len;
527
	char	name[32];
528
	char	address[64];
529
	int		colors;
530
	int		frags;
531
	int		connectTime;
532
	byte	playerNumber;
533
 
534
	net_landriverlevel = testDriver;
535
 
536
	while (1)
537
	{
538
		len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr);
539
		if (len < sizeof(int))
540
			break;
541
 
542
		net_message.cursize = len;
543
 
544
		MSG_BeginReading ();
545
		control = BigLong(*((int *)net_message.data));
546
		MSG_ReadLong();
547
		if (control == -1)
548
			break;
549
		if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
550
			break;
551
		if ((control & NETFLAG_LENGTH_MASK) != len)
552
			break;
553
 
554
		if (MSG_ReadByte() != CCREP_PLAYER_INFO)
555
			Sys_Error("Unexpected repsonse to Player Info request\n");
556
 
557
		playerNumber = MSG_ReadByte();
558
		Q_strcpy(name, MSG_ReadString());
559
		colors = MSG_ReadLong();
560
		frags = MSG_ReadLong();
561
		connectTime = MSG_ReadLong();
562
		Q_strcpy(address, MSG_ReadString());
563
 
564
		Con_Printf("%s\n  frags:%3i  colors:%u %u  time:%u\n  %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address);
565
	}
566
 
567
	testPollCount--;
568
	if (testPollCount)
569
	{
570
		SchedulePollProcedure(&testPollProcedure, 0.1);
571
	}
572
	else
573
	{
574
		dfunc.CloseSocket(testSocket);
575
		testInProgress = false;
576
	}
577
}
578
 
579
static void Test_f (void)
580
{
581
	char	*host;
582
	int		n;
583
	int		max = MAX_SCOREBOARD;
584
	struct qsockaddr sendaddr;
585
 
586
	if (testInProgress)
587
		return;
588
 
589
	host = Cmd_Argv (1);
590
 
591
	if (host && hostCacheCount)
592
	{
593
		for (n = 0; n < hostCacheCount; n++)
594
			if (Q_strcasecmp (host, hostcache[n].name) == 0)
595
			{
596
				if (hostcache[n].driver != myDriverLevel)
597
					continue;
598
				net_landriverlevel = hostcache[n].ldriver;
599
				max = hostcache[n].maxusers;
600
				Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
601
				break;
602
			}
603
		if (n < hostCacheCount)
604
			goto JustDoIt;
605
	}
606
 
607
	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
608
	{
609
		if (!net_landrivers[net_landriverlevel].initialized)
610
			continue;
611
 
612
		// see if we can resolve the host name
613
		if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
614
			break;
615
	}
616
	if (net_landriverlevel == net_numlandrivers)
617
		return;
618
 
619
JustDoIt:
620
	testSocket = dfunc.OpenSocket(0);
621
	if (testSocket == -1)
622
		return;
623
 
624
	testInProgress = true;
625
	testPollCount = 20;
626
	testDriver = net_landriverlevel;
627
 
628
	for (n = 0; n < max; n++)
629
	{
630
		SZ_Clear(&net_message);
631
		// save space for the header, filled in later
632
		MSG_WriteLong(&net_message, 0);
633
		MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO);
634
		MSG_WriteByte(&net_message, n);
635
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | 	(net_message.cursize & NETFLAG_LENGTH_MASK));
636
		dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr);
637
	}
638
	SZ_Clear(&net_message);
639
	SchedulePollProcedure(&testPollProcedure, 0.1);
640
}
641
 
642
 
643
static qboolean test2InProgress = false;
644
static int		test2Driver;
645
static int		test2Socket;
646
 
647
static void Test2_Poll(void);
648
PollProcedure	test2PollProcedure = {NULL, 0.0, Test2_Poll};
649
 
650
static void Test2_Poll(void)
651
{
652
	struct qsockaddr clientaddr;
653
	int		control;
654
	int		len;
655
	char	name[256];
656
	char	value[256];
657
 
658
	net_landriverlevel = test2Driver;
659
	name[0] = 0;
660
 
661
	len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr);
662
	if (len < sizeof(int))
663
		goto Reschedule;
664
 
665
	net_message.cursize = len;
666
 
667
	MSG_BeginReading ();
668
	control = BigLong(*((int *)net_message.data));
669
	MSG_ReadLong();
670
	if (control == -1)
671
		goto Error;
672
	if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
673
		goto Error;
674
	if ((control & NETFLAG_LENGTH_MASK) != len)
675
		goto Error;
676
 
677
	if (MSG_ReadByte() != CCREP_RULE_INFO)
678
		goto Error;
679
 
680
	Q_strcpy(name, MSG_ReadString());
681
	if (name[0] == 0)
682
		goto Done;
683
	Q_strcpy(value, MSG_ReadString());
684
 
685
	Con_Printf("%-16.16s  %-16.16s\n", name, value);
686
 
687
	SZ_Clear(&net_message);
688
	// save space for the header, filled in later
689
	MSG_WriteLong(&net_message, 0);
690
	MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
691
	MSG_WriteString(&net_message, name);
692
	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
693
	dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr);
694
	SZ_Clear(&net_message);
695
 
696
Reschedule:
697
	SchedulePollProcedure(&test2PollProcedure, 0.05);
698
	return;
699
 
700
Error:
701
	Con_Printf("Unexpected repsonse to Rule Info request\n");
702
Done:
703
	dfunc.CloseSocket(test2Socket);
704
	test2InProgress = false;
705
	return;
706
}
707
 
708
static void Test2_f (void)
709
{
710
	char	*host;
711
	int		n;
712
	struct qsockaddr sendaddr;
713
 
714
	if (test2InProgress)
715
		return;
716
 
717
	host = Cmd_Argv (1);
718
 
719
	if (host && hostCacheCount)
720
	{
721
		for (n = 0; n < hostCacheCount; n++)
722
			if (Q_strcasecmp (host, hostcache[n].name) == 0)
723
			{
724
				if (hostcache[n].driver != myDriverLevel)
725
					continue;
726
				net_landriverlevel = hostcache[n].ldriver;
727
				Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
728
				break;
729
			}
730
		if (n < hostCacheCount)
731
			goto JustDoIt;
732
	}
733
 
734
	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
735
	{
736
		if (!net_landrivers[net_landriverlevel].initialized)
737
			continue;
738
 
739
		// see if we can resolve the host name
740
		if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
741
			break;
742
	}
743
	if (net_landriverlevel == net_numlandrivers)
744
		return;
745
 
746
JustDoIt:
747
	test2Socket = dfunc.OpenSocket(0);
748
	if (test2Socket == -1)
749
		return;
750
 
751
	test2InProgress = true;
752
	test2Driver = net_landriverlevel;
753
 
754
	SZ_Clear(&net_message);
755
	// save space for the header, filled in later
756
	MSG_WriteLong(&net_message, 0);
757
	MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
758
	MSG_WriteString(&net_message, "");
759
	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
760
	dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr);
761
	SZ_Clear(&net_message);
762
	SchedulePollProcedure(&test2PollProcedure, 0.05);
763
}
764
 
765
 
766
int Datagram_Init (void)
767
{
768
	int i;
769
	int csock;
770
 
771
	myDriverLevel = net_driverlevel;
772
	Cmd_AddCommand ("net_stats", NET_Stats_f);
773
 
774
	if (COM_CheckParm("-nolan"))
775
		return -1;
776
 
777
	for (i = 0; i < net_numlandrivers; i++)
778
		{
779
		csock = net_landrivers[i].Init ();
780
		if (csock == -1)
781
			continue;
782
		net_landrivers[i].initialized = true;
783
		net_landrivers[i].controlSock = csock;
784
		}
785
 
786
#ifdef BAN_TEST
787
	Cmd_AddCommand ("ban", NET_Ban_f);
788
#endif
789
	Cmd_AddCommand ("test", Test_f);
790
	Cmd_AddCommand ("test2", Test2_f);
791
 
792
	return 0;
793
}
794
 
795
 
796
void Datagram_Shutdown (void)
797
{
798
	int i;
799
 
800
//
801
// shutdown the lan drivers
802
//
803
	for (i = 0; i < net_numlandrivers; i++)
804
	{
805
		if (net_landrivers[i].initialized)
806
		{
807
			net_landrivers[i].Shutdown ();
808
			net_landrivers[i].initialized = false;
809
		}
810
	}
811
}
812
 
813
 
814
void Datagram_Close (qsocket_t *sock)
815
{
816
	sfunc.CloseSocket(sock->socket);
817
}
818
 
819
 
820
void Datagram_Listen (qboolean state)
821
{
822
	int i;
823
 
824
	for (i = 0; i < net_numlandrivers; i++)
825
		if (net_landrivers[i].initialized)
826
			net_landrivers[i].Listen (state);
827
}
828
 
829
 
830
static qsocket_t *_Datagram_CheckNewConnections (void)
831
{
832
	struct qsockaddr clientaddr;
833
	struct qsockaddr newaddr;
834
	int			newsock;
835
	int			acceptsock;
836
	qsocket_t	*sock;
837
	qsocket_t	*s;
838
	int			len;
839
	int			command;
840
	int			control;
841
	int			ret;
842
 
843
	acceptsock = dfunc.CheckNewConnections();
844
	if (acceptsock == -1)
845
		return NULL;
846
 
847
	SZ_Clear(&net_message);
848
 
849
	len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);
850
	if (len < sizeof(int))
851
		return NULL;
852
	net_message.cursize = len;
853
 
854
	MSG_BeginReading ();
855
	control = BigLong(*((int *)net_message.data));
856
	MSG_ReadLong();
857
	if (control == -1)
858
		return NULL;
859
	if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
860
		return NULL;
861
	if ((control & NETFLAG_LENGTH_MASK) != len)
862
		return NULL;
863
 
864
	command = MSG_ReadByte();
865
	if (command == CCREQ_SERVER_INFO)
866
	{
867
		if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
868
			return NULL;
869
 
870
		SZ_Clear(&net_message);
871
		// save space for the header, filled in later
872
		MSG_WriteLong(&net_message, 0);
873
		MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
874
		dfunc.GetSocketAddr(acceptsock, &newaddr);
875
		MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
876
		MSG_WriteString(&net_message, hostname.string);
877
		MSG_WriteString(&net_message, sv.name);
878
		MSG_WriteByte(&net_message, net_activeconnections);
879
		MSG_WriteByte(&net_message, svs.maxclients);
880
		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
881
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
882
		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
883
		SZ_Clear(&net_message);
884
		return NULL;
885
	}
886
 
887
	if (command == CCREQ_PLAYER_INFO)
888
	{
889
		int			playerNumber;
890
		int			activeNumber;
891
		int			clientNumber;
892
		client_t	*client;
893
 
894
		playerNumber = MSG_ReadByte();
895
		activeNumber = -1;
896
		for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)
897
		{
898
			if (client->active)
899
			{
900
				activeNumber++;
901
				if (activeNumber == playerNumber)
902
					break;
903
			}
904
		}
905
		if (clientNumber == svs.maxclients)
906
			return NULL;
907
 
908
		SZ_Clear(&net_message);
909
		// save space for the header, filled in later
910
		MSG_WriteLong(&net_message, 0);
911
		MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);
912
		MSG_WriteByte(&net_message, playerNumber);
913
		MSG_WriteString(&net_message, client->name);
914
		MSG_WriteLong(&net_message, client->colors);
915
		MSG_WriteLong(&net_message, (int)client->edict->v.frags);
916
		MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
917
		MSG_WriteString(&net_message, client->netconnection->address);
918
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
919
		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
920
		SZ_Clear(&net_message);
921
 
922
		return NULL;
923
	}
924
 
925
	if (command == CCREQ_RULE_INFO)
926
	{
927
		char	*prevCvarName;
928
		cvar_t	*var;
929
 
930
		// find the search start location
931
		prevCvarName = MSG_ReadString();
932
		if (*prevCvarName)
933
		{
934
			var = Cvar_FindVar (prevCvarName);
935
			if (!var)
936
				return NULL;
937
			var = var->next;
938
		}
939
		else
940
			var = cvar_vars;
941
 
942
		// search for the next server cvar
943
		while (var)
944
		{
945
			if (var->server)
946
				break;
947
			var = var->next;
948
		}
949
 
950
		// send the response
951
 
952
		SZ_Clear(&net_message);
953
		// save space for the header, filled in later
954
		MSG_WriteLong(&net_message, 0);
955
		MSG_WriteByte(&net_message, CCREP_RULE_INFO);
956
		if (var)
957
		{
958
			MSG_WriteString(&net_message, var->name);
959
			MSG_WriteString(&net_message, var->string);
960
		}
961
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
962
		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
963
		SZ_Clear(&net_message);
964
 
965
		return NULL;
966
	}
967
 
968
	if (command != CCREQ_CONNECT)
969
		return NULL;
970
 
971
	if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
972
		return NULL;
973
 
974
	if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
975
	{
976
		SZ_Clear(&net_message);
977
		// save space for the header, filled in later
978
		MSG_WriteLong(&net_message, 0);
979
		MSG_WriteByte(&net_message, CCREP_REJECT);
980
		MSG_WriteString(&net_message, "Incompatible version.\n");
981
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
982
		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
983
		SZ_Clear(&net_message);
984
		return NULL;
985
	}
986
 
987
#ifdef BAN_TEST
988
	// check for a ban
989
	if (clientaddr.sa_family == AF_INET)
990
	{
991
		unsigned long testAddr;
992
		testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr;
993
		if ((testAddr & banMask) == banAddr)
994
		{
995
			SZ_Clear(&net_message);
996
			// save space for the header, filled in later
997
			MSG_WriteLong(&net_message, 0);
998
			MSG_WriteByte(&net_message, CCREP_REJECT);
999
			MSG_WriteString(&net_message, "You have been banned.\n");
1000
			*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1001
			dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1002
			SZ_Clear(&net_message);
1003
			return NULL;
1004
		}
1005
	}
1006
#endif
1007
 
1008
	// see if this guy is already connected
1009
	for (s = net_activeSockets; s; s = s->next)
1010
	{
1011
		if (s->driver != net_driverlevel)
1012
			continue;
1013
		ret = dfunc.AddrCompare(&clientaddr, &s->addr);
1014
		if (ret >= 0)
1015
		{
1016
			// is this a duplicate connection reqeust?
1017
			if (ret == 0 && net_time - s->connecttime < 2.0)
1018
			{
1019
				// yes, so send a duplicate reply
1020
				SZ_Clear(&net_message);
1021
				// save space for the header, filled in later
1022
				MSG_WriteLong(&net_message, 0);
1023
				MSG_WriteByte(&net_message, CCREP_ACCEPT);
1024
				dfunc.GetSocketAddr(s->socket, &newaddr);
1025
				MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
1026
				*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1027
				dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1028
				SZ_Clear(&net_message);
1029
				return NULL;
1030
			}
1031
			// it's somebody coming back in from a crash/disconnect
1032
			// so close the old qsocket and let their retry get them back in
1033
			NET_Close(s);
1034
			return NULL;
1035
		}
1036
	}
1037
 
1038
	// allocate a QSocket
1039
	sock = NET_NewQSocket ();
1040
	if (sock == NULL)
1041
	{
1042
		// no room; try to let him know
1043
		SZ_Clear(&net_message);
1044
		// save space for the header, filled in later
1045
		MSG_WriteLong(&net_message, 0);
1046
		MSG_WriteByte(&net_message, CCREP_REJECT);
1047
		MSG_WriteString(&net_message, "Server is full.\n");
1048
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1049
		dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1050
		SZ_Clear(&net_message);
1051
		return NULL;
1052
	}
1053
 
1054
	// allocate a network socket
1055
	newsock = dfunc.OpenSocket(0);
1056
	if (newsock == -1)
1057
	{
1058
		NET_FreeQSocket(sock);
1059
		return NULL;
1060
	}
1061
 
1062
	// connect to the client
1063
	if (dfunc.Connect (newsock, &clientaddr) == -1)
1064
	{
1065
		dfunc.CloseSocket(newsock);
1066
		NET_FreeQSocket(sock);
1067
		return NULL;
1068
	}
1069
 
1070
	// everything is allocated, just fill in the details
1071
	sock->socket = newsock;
1072
	sock->landriver = net_landriverlevel;
1073
	sock->addr = clientaddr;
1074
	Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr));
1075
 
1076
	// send him back the info about the server connection he has been allocated
1077
	SZ_Clear(&net_message);
1078
	// save space for the header, filled in later
1079
	MSG_WriteLong(&net_message, 0);
1080
	MSG_WriteByte(&net_message, CCREP_ACCEPT);
1081
	dfunc.GetSocketAddr(newsock, &newaddr);
1082
	MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
1083
//	MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
1084
	*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1085
	dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1086
	SZ_Clear(&net_message);
1087
 
1088
	return sock;
1089
}
1090
 
1091
qsocket_t *Datagram_CheckNewConnections (void)
1092
{
1093
	qsocket_t *ret = NULL;
1094
 
1095
	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1096
		if (net_landrivers[net_landriverlevel].initialized)
1097
			if ((ret = _Datagram_CheckNewConnections ()) != NULL)
1098
				break;
1099
	return ret;
1100
}
1101
 
1102
 
1103
static void _Datagram_SearchForHosts (qboolean xmit)
1104
{
1105
	int		ret;
1106
	int		n;
1107
	int		i;
1108
	struct qsockaddr readaddr;
1109
	struct qsockaddr myaddr;
1110
	int		control;
1111
 
1112
	dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
1113
	if (xmit)
1114
	{
1115
		SZ_Clear(&net_message);
1116
		// save space for the header, filled in later
1117
		MSG_WriteLong(&net_message, 0);
1118
		MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
1119
		MSG_WriteString(&net_message, "QUAKE");
1120
		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
1121
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1122
		dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);
1123
		SZ_Clear(&net_message);
1124
	}
1125
 
1126
	while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
1127
	{
1128
		if (ret < sizeof(int))
1129
			continue;
1130
		net_message.cursize = ret;
1131
 
1132
		// don't answer our own query
1133
		if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0)
1134
			continue;
1135
 
1136
		// is the cache full?
1137
		if (hostCacheCount == HOSTCACHESIZE)
1138
			continue;
1139
 
1140
		MSG_BeginReading ();
1141
		control = BigLong(*((int *)net_message.data));
1142
		MSG_ReadLong();
1143
		if (control == -1)
1144
			continue;
1145
		if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
1146
			continue;
1147
		if ((control & NETFLAG_LENGTH_MASK) != ret)
1148
			continue;
1149
 
1150
		if (MSG_ReadByte() != CCREP_SERVER_INFO)
1151
			continue;
1152
 
1153
		dfunc.GetAddrFromName(MSG_ReadString(), &readaddr);
1154
		// search the cache for this server
1155
		for (n = 0; n < hostCacheCount; n++)
1156
			if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0)
1157
				break;
1158
 
1159
		// is it already there?
1160
		if (n < hostCacheCount)
1161
			continue;
1162
 
1163
		// add it
1164
		hostCacheCount++;
1165
		Q_strcpy(hostcache[n].name, MSG_ReadString());
1166
		Q_strcpy(hostcache[n].map, MSG_ReadString());
1167
		hostcache[n].users = MSG_ReadByte();
1168
		hostcache[n].maxusers = MSG_ReadByte();
1169
		if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
1170
		{
1171
			Q_strcpy(hostcache[n].cname, hostcache[n].name);
1172
			hostcache[n].cname[14] = 0;
1173
			Q_strcpy(hostcache[n].name, "*");
1174
			Q_strcat(hostcache[n].name, hostcache[n].cname);
1175
		}
1176
		Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr));
1177
		hostcache[n].driver = net_driverlevel;
1178
		hostcache[n].ldriver = net_landriverlevel;
1179
		Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr));
1180
 
1181
		// check for a name conflict
1182
		for (i = 0; i < hostCacheCount; i++)
1183
		{
1184
			if (i == n)
1185
				continue;
1186
			if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
1187
			{
1188
				i = Q_strlen(hostcache[n].name);
1189
				if (i < 15 && hostcache[n].name[i-1] > '8')
1190
				{
1191
					hostcache[n].name[i] = '0';
1192
					hostcache[n].name[i+1] = 0;
1193
				}
1194
				else
1195
					hostcache[n].name[i-1]++;
1196
				i = -1;
1197
			}
1198
		}
1199
	}
1200
}
1201
 
1202
void Datagram_SearchForHosts (qboolean xmit)
1203
{
1204
	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1205
	{
1206
		if (hostCacheCount == HOSTCACHESIZE)
1207
			break;
1208
		if (net_landrivers[net_landriverlevel].initialized)
1209
			_Datagram_SearchForHosts (xmit);
1210
	}
1211
}
1212
 
1213
 
1214
static qsocket_t *_Datagram_Connect (char *host)
1215
{
1216
	struct qsockaddr sendaddr;
1217
	struct qsockaddr readaddr;
1218
	qsocket_t	*sock;
1219
	int			newsock;
1220
	int			ret;
1221
	int			reps;
1222
	double		start_time;
1223
	int			control;
1224
	char		*reason;
1225
 
1226
	// see if we can resolve the host name
1227
	if (dfunc.GetAddrFromName(host, &sendaddr) == -1)
1228
		return NULL;
1229
 
1230
	newsock = dfunc.OpenSocket (0);
1231
	if (newsock == -1)
1232
		return NULL;
1233
 
1234
	sock = NET_NewQSocket ();
1235
	if (sock == NULL)
1236
		goto ErrorReturn2;
1237
	sock->socket = newsock;
1238
	sock->landriver = net_landriverlevel;
1239
 
1240
	// connect to the host
1241
	if (dfunc.Connect (newsock, &sendaddr) == -1)
1242
		goto ErrorReturn;
1243
 
1244
	// send the connection request
1245
	Con_Printf("trying...\n"); SCR_UpdateScreen ();
1246
	start_time = net_time;
1247
 
1248
	for (reps = 0; reps < 3; reps++)
1249
	{
1250
		SZ_Clear(&net_message);
1251
		// save space for the header, filled in later
1252
		MSG_WriteLong(&net_message, 0);
1253
		MSG_WriteByte(&net_message, CCREQ_CONNECT);
1254
		MSG_WriteString(&net_message, "QUAKE");
1255
		MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
1256
		*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1257
		dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr);
1258
		SZ_Clear(&net_message);
1259
		do
1260
		{
1261
			ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr);
1262
			// if we got something, validate it
1263
			if (ret > 0)
1264
			{
1265
				// is it from the right place?
1266
				if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0)
1267
				{
1268
#ifdef DEBUG
1269
					Con_Printf("wrong reply address\n");
1270
					Con_Printf("Expected: %s\n", StrAddr (&sendaddr));
1271
					Con_Printf("Received: %s\n", StrAddr (&readaddr));
1272
					SCR_UpdateScreen ();
1273
#endif
1274
					ret = 0;
1275
					continue;
1276
				}
1277
 
1278
				if (ret < sizeof(int))
1279
				{
1280
					ret = 0;
1281
					continue;
1282
				}
1283
 
1284
				net_message.cursize = ret;
1285
				MSG_BeginReading ();
1286
 
1287
				control = BigLong(*((int *)net_message.data));
1288
				MSG_ReadLong();
1289
				if (control == -1)
1290
				{
1291
					ret = 0;
1292
					continue;
1293
				}
1294
				if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
1295
				{
1296
					ret = 0;
1297
					continue;
1298
				}
1299
				if ((control & NETFLAG_LENGTH_MASK) != ret)
1300
				{
1301
					ret = 0;
1302
					continue;
1303
				}
1304
			}
1305
		}
1306
		while (ret == 0 && (SetNetTime() - start_time) < 2.5);
1307
		if (ret)
1308
			break;
1309
		Con_Printf("still trying...\n"); SCR_UpdateScreen ();
1310
		start_time = SetNetTime();
1311
	}
1312
 
1313
	if (ret == 0)
1314
	{
1315
		reason = "No Response";
1316
		Con_Printf("%s\n", reason);
1317
		Q_strcpy(m_return_reason, reason);
1318
		goto ErrorReturn;
1319
	}
1320
 
1321
	if (ret == -1)
1322
	{
1323
		reason = "Network Error";
1324
		Con_Printf("%s\n", reason);
1325
		Q_strcpy(m_return_reason, reason);
1326
		goto ErrorReturn;
1327
	}
1328
 
1329
	ret = MSG_ReadByte();
1330
	if (ret == CCREP_REJECT)
1331
	{
1332
		reason = MSG_ReadString();
1333
		Con_Printf(reason);
1334
		Q_strncpy(m_return_reason, reason, 31);
1335
		goto ErrorReturn;
1336
	}
1337
 
1338
	if (ret == CCREP_ACCEPT)
1339
	{
1340
		Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr));
1341
		dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());
1342
	}
1343
	else
1344
	{
1345
		reason = "Bad Response";
1346
		Con_Printf("%s\n", reason);
1347
		Q_strcpy(m_return_reason, reason);
1348
		goto ErrorReturn;
1349
	}
1350
 
1351
	dfunc.GetNameFromAddr (&sendaddr, sock->address);
1352
 
1353
	Con_Printf ("Connection accepted\n");
1354
	sock->lastMessageTime = SetNetTime();
1355
 
1356
	// switch the connection to the specified address
1357
	if (dfunc.Connect (newsock, &sock->addr) == -1)
1358
	{
1359
		reason = "Connect to Game failed";
1360
		Con_Printf("%s\n", reason);
1361
		Q_strcpy(m_return_reason, reason);
1362
		goto ErrorReturn;
1363
	}
1364
 
1365
	m_return_onerror = false;
1366
	return sock;
1367
 
1368
ErrorReturn:
1369
	NET_FreeQSocket(sock);
1370
ErrorReturn2:
1371
	dfunc.CloseSocket(newsock);
1372
	if (m_return_onerror)
1373
	{
1374
		key_dest = key_menu;
1375
		m_state = m_return_state;
1376
		m_return_onerror = false;
1377
	}
1378
	return NULL;
1379
}
1380
 
1381
qsocket_t *Datagram_Connect (char *host)
1382
{
1383
	qsocket_t *ret = NULL;
1384
 
1385
	for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1386
		if (net_landrivers[net_landriverlevel].initialized)
1387
			if ((ret = _Datagram_Connect (host)) != NULL)
1388
				break;
1389
	return ret;
1390
}