Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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. }
  952.