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_ser.c
21
 
22
#include "quakedef.h"
23
#include "net_ser.h"
24
#include "dosisms.h"
25
#include "crc.h"
26
 
27
#include "net_comx.c"
28
 
29
// serial protocol
30
 
31
#define SERIAL_PROTOCOL_VERSION 3
32
 
33
// The serial protocol is message oriented.  The high level message format is
34
// a one byte message type (MTYPE_xxx), data, and a 16-bit checksum.  All
35
// multi-byte fields are sent in network byte order.  There are currently 4
36
// MTYPEs defined.  Their formats are as follows:
37
//
38
// MTYPE_RELIABLE     sequence      data_length   data       checksum   eom
39
// MTYPE_UNRELIABLE   sequence      data_length   data       checksum   eom
40
// MTYPE_ACK          sequence      checksum      eom
41
// MTYPE_CONTROL      data_length   data          checksum   eom
42
//
43
// sequence is an 8-bit unsigned value starting from 0
44
// data_length is a 16-bit unsigned value; it is the length of the data only
45
// the checksum is a 16-bit value.  the CRC formula used is defined in crc.h.
46
//              the checksum covers the entire messages, excluding itself
47
// eom is a special 2 byte sequence used to mark the End Of Message.  This is
48
//              needed for error recovery.
49
//
50
// A lot of behavior is based on knowledge of the upper level Quake network
51
// layer.  For example, only one reliable message can be outstanding (pending
52
// reception of an MTYPE_ACK) at a time.
53
//
54
// The low level routines used to communicate with the modem are not part of
55
// this protocol.
56
//
57
// The CONTROL messages are only used for session establishment.  They are
58
// not reliable or sequenced.
59
 
60
#define MTYPE_RELIABLE			0x01
61
#define MTYPE_UNRELIABLE		0x02
62
#define MTYPE_CONTROL			0x03
63
#define MTYPE_ACK				0x04
64
#define MTYPE_CLIENT			0x80
65
 
66
#define ESCAPE_COMMAND			0xe0
67
#define ESCAPE_EOM				0x19
68
 
69
static qboolean listening = false;
70
 
71
 
72
typedef struct SerialLine_s
73
{
74
	struct SerialLine_s	*next;
75
	qsocket_t			*sock;
76
	int					lengthStated;
77
	int					lengthFound;
78
	int					tty;
79
	qboolean			connected;
80
	qboolean			connecting;
81
	qboolean			client;
82
	double				connect_time;
83
	unsigned short		crcStated;
84
	unsigned short		crcValue;
85
	byte				currState;
86
	byte				prevState;
87
	byte				mtype;
88
	byte				sequence;
89
} SerialLine;
90
 
91
#define STATE_READY		0
92
#define STATE_SEQUENCE	1
93
#define STATE_LENGTH1	2
94
#define STATE_LENGTH2	3
95
#define STATE_DATA		4
96
#define STATE_CRC1		5
97
#define STATE_CRC2		6
98
#define STATE_EOM		7
99
#define STATE_ESCAPE	8
100
#define STATE_ABORT		9
101
 
102
SerialLine serialLine[NUM_COM_PORTS];
103
 
104
int myDriverLevel;
105
 
106
static void Serial_SendACK (SerialLine *p, byte sequence);
107
 
108
 
109
static void ResetSerialLineProtocol (SerialLine *p)
110
{
111
	p->connected = false;
112
	p->connecting = false;
113
	p->currState = STATE_READY;
114
	p->prevState = STATE_READY;
115
	p->lengthFound = 0;
116
}
117
 
118
 
119
static int ProcessInQueue(SerialLine *p)
120
{
121
	int	b;
122
 
123
	while (1)
124
	{
125
		b = TTY_ReadByte(p->tty);
126
		if (b == ERR_TTY_NODATA)
127
			break;
128
 
129
		if (b == ERR_TTY_LINE_STATUS)
130
		{
131
			p->currState = STATE_ABORT;
132
			continue;
133
		}
134
		if (b == ERR_TTY_MODEM_STATUS)
135
		{
136
			p->currState = STATE_ABORT;
137
			return -1;
138
		}
139
 
140
		if (b == ESCAPE_COMMAND)
141
			if (p->currState != STATE_ESCAPE)
142
			{
143
				p->prevState = p->currState;
144
				p->currState = STATE_ESCAPE;
145
				continue;
146
			}
147
 
148
		if (p->currState == STATE_ESCAPE)
149
		{
150
			if (b == ESCAPE_EOM)
151
			{
152
				if (p->prevState == STATE_ABORT)
153
				{
154
					p->currState = STATE_READY;
155
					p->lengthFound = 0;
156
					continue;
157
				}
158
 
159
				if (p->prevState != STATE_EOM)
160
				{
161
					p->currState = STATE_READY;
162
					p->lengthFound = 0;
163
					Con_DPrintf("Serial: premature EOM\n");
164
					continue;
165
				}
166
 
167
				switch (p->mtype)
168
				{
169
					case MTYPE_RELIABLE:
170
						Con_DPrintf("Serial: sending ack %u\n", p->sequence);
171
						Serial_SendACK (p, p->sequence);
172
						if (p->sequence == p->sock->receiveSequence)
173
						{
174
							p->sock->receiveSequence = (p->sequence + 1) & 0xff;
175
							p->sock->receiveMessageLength += p->lengthFound;
176
						}
177
						else
178
							Con_DPrintf("Serial: reliable out of order; got %u wanted %u\n", p->sequence, p->sock->receiveSequence);
179
						break;
180
 
181
					case MTYPE_UNRELIABLE:
182
						p->sock->unreliableReceiveSequence = (p->sequence + 1) & 0xff;
183
						p->sock->receiveMessageLength += p->lengthFound;
184
						break;
185
 
186
					case MTYPE_ACK:
187
						Con_DPrintf("Serial: got ack %u\n", p->sequence);
188
						if (p->sequence == p->sock->sendSequence)
189
						{
190
							p->sock->sendSequence = (p->sock->sendSequence + 1) & 0xff;
191
							p->sock->canSend = true;
192
						}
193
						else
194
							Con_DPrintf("Serial: ack out of order; got %u wanted %u\n",p->sequence, p->sock->sendSequence);
195
						break;
196
 
197
					case MTYPE_CONTROL:
198
						p->sock->receiveMessageLength += p->lengthFound;
199
						break;
200
					}
201
 
202
				p->currState = STATE_READY;
203
				p->lengthFound = 0;
204
				continue;
205
			}
206
 
207
 
208
			if (b != ESCAPE_COMMAND)
209
			{
210
				p->currState = STATE_ABORT;
211
				Con_DPrintf("Serial: Bad escape sequence\n");
212
				continue;
213
			}
214
 
215
			// b == ESCAPE_COMMAND
216
			p->currState = p->prevState;
217
		}
218
 
219
		p->prevState = p->currState;
220
 
221
//DEBUG
222
		if (p->sock->receiveMessageLength + p->lengthFound > NET_MAXMESSAGE)
223
		{
224
			Con_DPrintf("Serial blew out receive buffer: %u\n", p->sock->receiveMessageLength + p->lengthFound);
225
			p->currState = STATE_ABORT;
226
		}
227
		if (p->sock->receiveMessageLength + p->lengthFound == NET_MAXMESSAGE)
228
		{
229
			Con_DPrintf("Serial hit receive buffer limit: %u\n", p->sock->receiveMessageLength + p->lengthFound);
230
			p->currState = STATE_ABORT;
231
		}
232
//end DEBUG
233
 
234
		switch (p->currState)
235
		{
236
			case STATE_READY:
237
				CRC_Init(&p->crcValue);
238
				CRC_ProcessByte(&p->crcValue, b);
239
				if (p->client)
240
				{
241
					if ((b & MTYPE_CLIENT) != 0)
242
					{
243
						p->currState = STATE_ABORT;
244
						Con_DPrintf("Serial: client got own message\n");
245
						break;
246
					}
247
				}
248
				else
249
				{
250
					if ((b & MTYPE_CLIENT) == 0)
251
					{
252
						p->currState = STATE_ABORT;
253
						Con_DPrintf("Serial: server got own message\n");
254
						break;
255
					}
256
					b &= 0x7f;
257
				}
258
				p->mtype = b;
259
				if (b != MTYPE_CONTROL)
260
					p->currState = STATE_SEQUENCE;
261
				else
262
					p->currState = STATE_LENGTH1;
263
				if (p->mtype < MTYPE_ACK)
264
				{
265
					p->sock->receiveMessage[p->sock->receiveMessageLength] = b;
266
					p->lengthFound++;
267
				}
268
				break;
269
 
270
			case STATE_SEQUENCE:
271
				p->sequence = b;
272
				CRC_ProcessByte(&p->crcValue, b);
273
				if (p->mtype != MTYPE_ACK)
274
					p->currState = STATE_LENGTH1;
275
				else
276
					p->currState = STATE_CRC1;
277
				break;
278
 
279
			case STATE_LENGTH1:
280
				p->lengthStated = b * 256;
281
				CRC_ProcessByte(&p->crcValue, b);
282
				p->currState = STATE_LENGTH2;
283
				break;
284
 
285
			case STATE_LENGTH2:
286
				p->lengthStated += b;
287
				CRC_ProcessByte(&p->crcValue, b);
288
				if (p->mtype == MTYPE_RELIABLE && p->lengthStated > MAX_MSGLEN)
289
				{
290
					p->currState = STATE_ABORT;
291
					Con_DPrintf("Serial: bad reliable message length %u\n", p->lengthStated);
292
				}
293
				else if (p->mtype == MTYPE_UNRELIABLE && p->lengthStated > MAX_DATAGRAM)
294
				{
295
					p->currState = STATE_ABORT;
296
					Con_DPrintf("Serial: bad unreliable message length %u\n", p->lengthStated);
297
				}
298
				else
299
				{
300
					p->currState = STATE_DATA;
301
					if (p->mtype < MTYPE_ACK)
302
					{
303
						*(short *)&p->sock->receiveMessage [p->sock->receiveMessageLength + 1] = p->lengthStated;
304
						p->lengthFound += 2;
305
					}
306
				}
307
				break;
308
 
309
			case STATE_DATA:
310
				p->sock->receiveMessage[p->sock->receiveMessageLength + p->lengthFound] = b;
311
				p->lengthFound++;
312
				CRC_ProcessByte(&p->crcValue, b);
313
				if (p->lengthFound == p->lengthStated + 3)
314
					p->currState = STATE_CRC1;
315
				break;
316
 
317
			case STATE_CRC1:
318
				p->crcStated = b * 256;
319
				p->currState = STATE_CRC2;
320
				break;
321
 
322
			case STATE_CRC2:
323
				p->crcStated += b;
324
				if (p->crcStated == CRC_Value(p->crcValue))
325
				{
326
					p->currState = STATE_EOM;
327
				}
328
				else
329
				{
330
					p->currState = STATE_ABORT;
331
					Con_DPrintf("Serial: Bad crc\n");
332
				}
333
				break;
334
 
335
			case STATE_EOM:
336
				p->currState = STATE_ABORT;
337
				Con_DPrintf("Serial: Bad message format\n");
338
				break;
339
 
340
			case STATE_ABORT:
341
				break;
342
		}
343
	}
344
	return 0;
345
}
346
 
347
 
348
int Serial_Init (void)
349
{
350
	int     n;
351
 
352
// LATER do Win32 serial support
353
#ifdef	_WIN32
354
	return -1;
355
#endif
356
 
357
	if (COM_CheckParm("-nolan"))
358
		return -1;
359
	if (COM_CheckParm ("-noserial"))
360
		return -1;
361
 
362
	myDriverLevel = net_driverlevel;
363
 
364
	if (TTY_Init())
365
		return -1;
366
 
367
	for (n = 0; n < NUM_COM_PORTS; n++)
368
	{
369
		serialLine[n].tty = TTY_Open(n);
370
		ResetSerialLineProtocol (&serialLine[n]);
371
	}
372
 
373
	Con_Printf("Serial driver initialized\n");
374
	serialAvailable = true;
375
 
376
	return 0;
377
}
378
 
379
 
380
void Serial_Shutdown (void)
381
{
382
	int     n;
383
 
384
	for (n = 0; n < NUM_COM_PORTS; n++)
385
	{
386
		if (serialLine[n].connected)
387
			Serial_Close(serialLine[n].sock);
388
	}
389
 
390
	TTY_Shutdown();
391
}
392
 
393
 
394
void Serial_Listen (qboolean state)
395
{
396
	listening = state;
397
}
398
 
399
 
400
qboolean Serial_CanSendMessage (qsocket_t *sock)
401
{
402
	return sock->canSend;
403
}
404
 
405
 
406
qboolean Serial_CanSendUnreliableMessage (qsocket_t *sock)
407
{
408
	return TTY_OutputQueueIsEmpty(((SerialLine *)sock->driverdata)->tty);
409
}
410
 
411
 
412
int Serial_SendMessage (qsocket_t *sock, sizebuf_t *message)
413
{
414
	SerialLine *p;
415
	int n;
416
	unsigned short crc;
417
	byte b;
418
 
419
	p = (SerialLine *)sock->driverdata;
420
	CRC_Init (&crc);
421
 
422
	// message type
423
	b = MTYPE_RELIABLE;
424
	if (p->client)
425
		b |= MTYPE_CLIENT;
426
	TTY_WriteByte(p->tty, b);
427
	CRC_ProcessByte (&crc, b);
428
 
429
	// sequence
430
	b = p->sock->sendSequence;
431
	TTY_WriteByte(p->tty, b);
432
	if (b == ESCAPE_COMMAND)
433
		TTY_WriteByte(p->tty, b);
434
	CRC_ProcessByte (&crc, b);
435
 
436
	// data length
437
	b = message->cursize >> 8;
438
	TTY_WriteByte(p->tty, b);
439
	if (b == ESCAPE_COMMAND)
440
		TTY_WriteByte(p->tty, b);
441
	CRC_ProcessByte (&crc, b);
442
	b = message->cursize & 0xff;
443
	TTY_WriteByte(p->tty, b);
444
	if (b == ESCAPE_COMMAND)
445
		TTY_WriteByte(p->tty, b);
446
	CRC_ProcessByte (&crc, b);
447
 
448
	// data
449
	for (n = 0; n < message->cursize; n++)
450
	{
451
		b = message->data[n];
452
		TTY_WriteByte(p->tty, b);
453
		if (b == ESCAPE_COMMAND)
454
			TTY_WriteByte(p->tty, b);
455
		CRC_ProcessByte (&crc, b);
456
	}
457
 
458
	// checksum
459
	b = CRC_Value (crc) >> 8;
460
	TTY_WriteByte(p->tty, b);
461
	if (b == ESCAPE_COMMAND)
462
		TTY_WriteByte(p->tty, b);
463
	b = CRC_Value (crc) & 0xff;
464
	TTY_WriteByte(p->tty, b);
465
	if (b == ESCAPE_COMMAND)
466
		TTY_WriteByte(p->tty, b);
467
 
468
	// end of message
469
	TTY_WriteByte(p->tty, ESCAPE_COMMAND);
470
	TTY_WriteByte(p->tty, ESCAPE_EOM);
471
 
472
	TTY_Flush(p->tty);
473
 
474
	// mark sock as busy and save the message for possible retransmit
475
	sock->canSend = false;
476
	Q_memcpy(sock->sendMessage, message->data, message->cursize);
477
	sock->sendMessageLength = message->cursize;
478
	sock->lastSendTime = net_time;
479
 
480
	return 1;
481
}
482
 
483
 
484
static void ReSendMessage (qsocket_t *sock)
485
{
486
	sizebuf_t       temp;
487
 
488
	Con_DPrintf("Serial: re-sending reliable\n");
489
	temp.data = sock->sendMessage;
490
	temp.maxsize = sock->sendMessageLength;
491
	temp.cursize = sock->sendMessageLength;
492
	Serial_SendMessage (sock, &temp);
493
}
494
 
495
 
496
int Serial_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *message)
497
{
498
	SerialLine *p;
499
	int n;
500
	unsigned short crc;
501
	byte b;
502
 
503
	p = (SerialLine *)sock->driverdata;
504
 
505
	if (!TTY_OutputQueueIsEmpty(p->tty))
506
	{
507
		TTY_Flush(p->tty);
508
		return 1;
509
	}
510
 
511
	CRC_Init (&crc);
512
 
513
	// message type
514
	b = MTYPE_UNRELIABLE;
515
	if (p->client)
516
		b |= MTYPE_CLIENT;
517
	TTY_WriteByte(p->tty, b);
518
	CRC_ProcessByte (&crc, b);
519
 
520
	// sequence
521
	b = p->sock->unreliableSendSequence;
522
	p->sock->unreliableSendSequence = (b + 1) & 0xff;
523
	TTY_WriteByte(p->tty, b);
524
	if (b == ESCAPE_COMMAND)
525
		TTY_WriteByte(p->tty, b);
526
	CRC_ProcessByte (&crc, b);
527
 
528
	// data length
529
	b = message->cursize >> 8;
530
	TTY_WriteByte(p->tty, b);
531
	if (b == ESCAPE_COMMAND)
532
		TTY_WriteByte(p->tty, b);
533
	CRC_ProcessByte (&crc, b);
534
	b = message->cursize & 0xff;
535
	TTY_WriteByte(p->tty, b);
536
	if (b == ESCAPE_COMMAND)
537
		TTY_WriteByte(p->tty, b);
538
	CRC_ProcessByte (&crc, b);
539
 
540
	// data
541
	for (n = 0; n < message->cursize; n++)
542
	{
543
		b = message->data[n];
544
		TTY_WriteByte(p->tty, b);
545
		if (b == ESCAPE_COMMAND)
546
			TTY_WriteByte(p->tty, b);
547
		CRC_ProcessByte (&crc, b);
548
	}
549
 
550
	// checksum
551
	b = CRC_Value (crc) >> 8;
552
	TTY_WriteByte(p->tty, b);
553
	if (b == ESCAPE_COMMAND)
554
		TTY_WriteByte(p->tty, b);
555
	b = CRC_Value (crc) & 0xff;
556
	TTY_WriteByte(p->tty, b);
557
	if (b == ESCAPE_COMMAND)
558
		TTY_WriteByte(p->tty, b);
559
 
560
	// end of message
561
	TTY_WriteByte(p->tty, ESCAPE_COMMAND);
562
	TTY_WriteByte(p->tty, ESCAPE_EOM);
563
 
564
	TTY_Flush(p->tty);
565
 
566
	return 1;
567
}
568
 
569
 
570
static void Serial_SendACK (SerialLine *p, byte sequence)
571
{
572
	unsigned short crc;
573
	byte b;
574
 
575
	CRC_Init (&crc);
576
 
577
	// message type
578
	b = MTYPE_ACK;
579
	if (p->client)
580
		b |= MTYPE_CLIENT;
581
	TTY_WriteByte(p->tty, b);
582
	CRC_ProcessByte (&crc, b);
583
 
584
	// sequence
585
	b = sequence;
586
	TTY_WriteByte(p->tty, b);
587
	if (b == ESCAPE_COMMAND)
588
		TTY_WriteByte(p->tty, b);
589
	CRC_ProcessByte (&crc, b);
590
 
591
	// checksum
592
	b = CRC_Value (crc) >> 8;
593
	TTY_WriteByte(p->tty, b);
594
	if (b == ESCAPE_COMMAND)
595
		TTY_WriteByte(p->tty, b);
596
	b = CRC_Value (crc) & 0xff;
597
	TTY_WriteByte(p->tty, b);
598
	if (b == ESCAPE_COMMAND)
599
		TTY_WriteByte(p->tty, b);
600
 
601
	// end of message
602
	TTY_WriteByte(p->tty, ESCAPE_COMMAND);
603
	TTY_WriteByte(p->tty, ESCAPE_EOM);
604
 
605
	TTY_Flush(p->tty);
606
}
607
 
608
 
609
static void Serial_SendControlMessage (SerialLine *p, sizebuf_t *message)
610
{
611
	unsigned short crc;
612
	int n;
613
	byte b;
614
 
615
	CRC_Init (&crc);
616
 
617
	// message type
618
	b = MTYPE_CONTROL;
619
	if (p->client)
620
		b |= MTYPE_CLIENT;
621
	TTY_WriteByte(p->tty, b);
622
	CRC_ProcessByte (&crc, b);
623
 
624
	// data length
625
	b = message->cursize >> 8;
626
	TTY_WriteByte(p->tty, b);
627
	if (b == ESCAPE_COMMAND)
628
		TTY_WriteByte(p->tty, b);
629
	CRC_ProcessByte (&crc, b);
630
	b = message->cursize & 0xff;
631
	TTY_WriteByte(p->tty, b);
632
	if (b == ESCAPE_COMMAND)
633
		TTY_WriteByte(p->tty, b);
634
	CRC_ProcessByte (&crc, b);
635
 
636
	// data
637
	for (n = 0; n < message->cursize; n++)
638
	{
639
		b = message->data[n];
640
		TTY_WriteByte(p->tty, b);
641
		if (b == ESCAPE_COMMAND)
642
			TTY_WriteByte(p->tty, b);
643
		CRC_ProcessByte (&crc, b);
644
	}
645
 
646
	// checksum
647
	b = CRC_Value (crc) >> 8;
648
	TTY_WriteByte(p->tty, b);
649
	if (b == ESCAPE_COMMAND)
650
		TTY_WriteByte(p->tty, b);
651
	b = CRC_Value (crc) & 0xff;
652
	TTY_WriteByte(p->tty, b);
653
	if (b == ESCAPE_COMMAND)
654
		TTY_WriteByte(p->tty, b);
655
 
656
	// end of message
657
	TTY_WriteByte(p->tty, ESCAPE_COMMAND);
658
	TTY_WriteByte(p->tty, ESCAPE_EOM);
659
 
660
	TTY_Flush(p->tty);
661
}
662
 
663
 
664
static int _Serial_GetMessage (SerialLine *p)
665
{
666
	byte	ret;
667
	short	length;
668
 
669
	if (ProcessInQueue(p))
670
		return -1;
671
 
672
	if (p->sock->receiveMessageLength == 0)
673
		return 0;
674
 
675
	ret = p->sock->receiveMessage[0];
676
	length = *(short *)&p->sock->receiveMessage[1];
677
	if (ret == MTYPE_CONTROL)
678
		ret = 1;
679
 
680
	SZ_Clear (&net_message);
681
	SZ_Write (&net_message, &p->sock->receiveMessage[3], length);
682
 
683
	length += 3;
684
	p->sock->receiveMessageLength -= length;
685
 
686
	if (p->sock->receiveMessageLength + p->lengthFound)
687
		Q_memcpy(p->sock->receiveMessage, &p->sock->receiveMessage[length], p->sock->receiveMessageLength + p->lengthFound);
688
 
689
	return ret;
690
}
691
 
692
int Serial_GetMessage (qsocket_t *sock)
693
{
694
	SerialLine *p;
695
	int		ret;
696
 
697
	p = (SerialLine *)sock->driverdata;
698
 
699
	ret = _Serial_GetMessage (p);
700
 
701
	if (ret == 1)
702
		messagesReceived++;
703
 
704
	if (!sock->canSend)
705
		if ((net_time - sock->lastSendTime) > 1.0)
706
		{
707
			ReSendMessage (sock);
708
			sock->lastSendTime = net_time;
709
		}
710
 
711
	return ret;
712
}
713
 
714
 
715
void Serial_Close (qsocket_t *sock)
716
{
717
	SerialLine *p = (SerialLine *)sock->driverdata;
718
	TTY_Close(p->tty);
719
	ResetSerialLineProtocol (p);
720
}
721
 
722
 
723
char *com_types[] = {"direct", "modem"};
724
unsigned com_bauds[] = {9600, 14400, 19200, 28800, 57600};
725
 
726
void Serial_SearchForHosts (qboolean xmit)
727
{
728
	int		n;
729
	SerialLine *p;
730
 
731
	if (sv.active)
732
		return;
733
 
734
	if (hostCacheCount == HOSTCACHESIZE)
735
		return;
736
 
737
	// see if we've already answered
738
	for (n = 0; n < hostCacheCount; n++)
739
		if (Q_strcmp (hostcache[n].cname, "#") == 0)
740
			return;
741
 
742
	for (n = 0; n < NUM_COM_PORTS; n++)
743
		if (TTY_IsEnabled(n))
744
			break;
745
	if (n == NUM_COM_PORTS)
746
		return;
747
	p = &serialLine[n];
748
 
749
	if (TTY_IsModem(p->tty))
750
		return;
751
 
752
	sprintf(hostcache[hostCacheCount].name, "COM%u", n+1);
753
	Q_strcpy(hostcache[hostCacheCount].map, "");
754
	hostcache[hostCacheCount].users = 0;
755
	hostcache[hostCacheCount].maxusers = 0;
756
	hostcache[hostCacheCount].driver = net_driverlevel;
757
	Q_strcpy(hostcache[hostCacheCount].cname, "#");
758
	hostCacheCount++;
759
 
760
	return;
761
}
762
 
763
 
764
static qsocket_t *_Serial_Connect (char *host, SerialLine *p)
765
{
766
	int		ret;
767
	double	start_time;
768
	double	last_time;
769
 
770
	p->client = true;
771
	if (TTY_Connect(p->tty, host))
772
		return NULL;
773
 
774
	p->sock = NET_NewQSocket ();
775
	p->sock->driver = myDriverLevel;
776
	if (p->sock == NULL)
777
	{
778
		Con_Printf("No sockets available\n");
779
		return NULL;
780
	}
781
	p->sock->driverdata = p;
782
 
783
	// send the connection request
784
	start_time = SetNetTime();
785
	last_time = 0.0;
786
 
787
	SZ_Clear(&net_message);
788
	MSG_WriteByte(&net_message, CCREQ_CONNECT);
789
	MSG_WriteString(&net_message, "QUAKE");
790
	do
791
	{
792
		SetNetTime();
793
		if ((net_time - last_time) >= 1.0)
794
		{
795
			Serial_SendControlMessage (p, &net_message);
796
			last_time = net_time;
797
			Con_Printf("trying...\n"); SCR_UpdateScreen ();
798
		}
799
		ret = _Serial_GetMessage (p);
800
	}
801
	while (ret == 0 && (net_time - start_time) < 5.0);
802
 
803
	if (ret == 0)
804
	{
805
		Con_Printf("Unable to connect, no response\n");
806
		goto ErrorReturn;
807
	}
808
 
809
	if (ret == -1)
810
	{
811
		Con_Printf("Connection request error\n");
812
		goto ErrorReturn;
813
	}
814
 
815
	MSG_BeginReading ();
816
	ret = MSG_ReadByte();
817
	if (ret == CCREP_REJECT)
818
	{
819
		Con_Printf(MSG_ReadString());
820
		goto ErrorReturn;
821
	}
822
	if (ret != CCREP_ACCEPT)
823
	{
824
		Con_Printf("Unknown connection response\n");
825
		goto ErrorReturn;
826
	}
827
 
828
	p->connected = true;
829
	p->sock->lastMessageTime = net_time;
830
 
831
	Con_Printf ("Connection accepted\n");
832
 
833
	return p->sock;
834
 
835
ErrorReturn:
836
	TTY_Disconnect(p->tty);
837
	return NULL;
838
}
839
 
840
qsocket_t *Serial_Connect (char *host)
841
{
842
	int			n;
843
	qsocket_t	*ret = NULL;
844
 
845
	// see if this looks like a phone number
846
	if (*host == '#')
847
		host++;
848
	for (n = 0; n < Q_strlen(host); n++)
849
		if (host[n] == '.' || host[n] == ':')
850
			return NULL;
851
 
852
	for (n = 0; n < NUM_COM_PORTS; n++)
853
		if (TTY_IsEnabled(n) && !serialLine[n].connected)
854
			if ((ret = _Serial_Connect (host, &serialLine[n])))
855
				break;
856
	return ret;
857
}
858
 
859
 
860
static qsocket_t *_Serial_CheckNewConnections (SerialLine *p)
861
{
862
	int	command;
863
 
864
	p->client = false;
865
	if (!TTY_CheckForConnection(p->tty))
866
		return NULL;
867
 
868
	if (TTY_IsModem(p->tty))
869
	{
870
		if (!p->connecting)
871
		{
872
			p->connecting = true;
873
			p->connect_time = net_time;
874
		}
875
		else if ((net_time - p->connect_time) > 15.0)
876
		{
877
			p->connecting = false;
878
			TTY_Disconnect(p->tty);
879
			return NULL;
880
		}
881
	}
882
 
883
	p->sock = NET_NewQSocket ();
884
	p->sock->driver = myDriverLevel;
885
	if (p->sock == NULL)
886
	{
887
		Con_Printf("No sockets available\n");
888
		return NULL;
889
	}
890
	p->sock->driverdata = p;
891
 
892
	SZ_Clear(&net_message);
893
	if (_Serial_GetMessage(p) != 1)
894
	{
895
		NET_FreeQSocket(p->sock);
896
		return NULL;
897
	}
898
 
899
	MSG_BeginReading ();
900
	command = MSG_ReadByte();
901
 
902
	if (command == CCREQ_SERVER_INFO)
903
	{
904
		if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
905
			return NULL;
906
 
907
		if (MSG_ReadByte() != SERIAL_PROTOCOL_VERSION)
908
			return NULL;
909
 
910
		SZ_Clear(&net_message);
911
		MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
912
		MSG_WriteString(&net_message, hostname.string);
913
		MSG_WriteString(&net_message, sv.name);
914
		MSG_WriteByte(&net_message, net_activeconnections);
915
		MSG_WriteByte(&net_message, svs.maxclients);
916
		Serial_SendControlMessage (p, &net_message);
917
		SZ_Clear(&net_message);
918
		return NULL;
919
	}
920
 
921
	if (command != CCREQ_CONNECT)
922
		return NULL;
923
 
924
	if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
925
		return NULL;
926
 
927
	// send him back the info about the server connection he has been allocated
928
	SZ_Clear(&net_message);
929
	MSG_WriteByte(&net_message, CCREP_ACCEPT);
930
	Serial_SendControlMessage (p, &net_message);
931
	SZ_Clear(&net_message);
932
 
933
	p->connected = true;
934
	p->connecting = false;
935
	p->sock->lastMessageTime = net_time;
936
	sprintf(p->sock->address, "COM%u", (int)((p - serialLine) + 1));
937
 
938
	return p->sock;
939
}
940
 
941
qsocket_t *Serial_CheckNewConnections (void)
942
{
943
	int			n;
944
	qsocket_t	*ret = NULL;
945
 
946
	for (n = 0; n < NUM_COM_PORTS; n++)
947
		if (TTY_IsEnabled(n) && !serialLine[n].connected)
948
			if ((ret = _Serial_CheckNewConnections (&serialLine[n])))
949
				break;
950
	return ret;
951
}