home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 035 / pmics.zip / tcp.cc < prev    next >
C/C++ Source or Header  |  1994-12-13  |  9KB  |  347 lines

  1. /*
  2.     PMICS -- PM interface for playing chess on internet chess server
  3.     Copyright (C) 1994  Kevin Nomura
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     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., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     Author can be reached at email: chow@netcom.com
  20. */
  21. #ifdef TCP_SESSION
  22. #include <strstrea.h>
  23. #include "pmics.hh"
  24. #include "session.hh"
  25. #include "wcomm.hh"
  26. #define INCL_DOSPROCESS
  27. #define INCL_DOSFILEMGR
  28. #define INCL_DOSDEVIOCTL
  29. #define INCL_DOSDEVICES
  30. #define INCL_DOSDATETIME
  31. #define INCL_DOSQUEUES
  32. #define INCL_DOSEXCEPTIONS
  33. #include <os2.h>
  34. #include <stdio.h>
  35. #include <fcntl.h>
  36. #include <signal.h>
  37. #include <types.h>
  38. #include <sys/socket.h>
  39. #include <netinet/in.h>
  40. #include <netdb.h>
  41. #include <istring.hpp>
  42. #include <iexcbase.hpp>
  43.  
  44. #define ICS_PORT_DEFAULT 5000
  45. #define ICS_HOST_DEFAULT "chess.lm.com"
  46. #define SE 240
  47. #define SB 250
  48. #define WILL 251
  49. #define WONT 252
  50. #define DO 253
  51. #define DONT 254
  52. #define IAC 255
  53.  
  54. #define ECHO 1
  55. #define SUPPRESS_GO_AHEAD 3
  56. #define TTYPE 24
  57. #define NAWS 31
  58. #define LINEMODE 34
  59. #define ENV_VARS 36
  60.  
  61. #define CMDX(b1,b2) { char ch[4]; \
  62.                      ch[0]=IAC; ch[1]=b1; ch[2]=b2; aSession->write(ch,3); }
  63. #define CMD(b1,b2) { char ch[4]; \
  64.                      ch[0]=IAC; ch[1]=b1; ch[2]=b2; write(ch,3); }
  65.  
  66. extern IString getStringOption(IString s, IString def);
  67. extern int getIntOption(IString s, int def);
  68.  
  69. /**************************************************************************
  70.  *
  71.  *      Global Variables
  72.  *
  73.  *************************************************************************/
  74. extern strstream commStream;
  75. extern ASession *aSession;
  76. static char     theAppName[] = "pmics";
  77. static VOID _System TcpListen(ULONG sock);
  78.  
  79. /**************************************************************************
  80.  **************************************************************************
  81.  *
  82.  *      Routines
  83.  *
  84.  **************************************************************************
  85.  *************************************************************************/
  86.  
  87. ATcpSession::ATcpSession()
  88. {
  89.   EtherInit ();    // defines sock
  90.   listenThread = new IThread(&TcpListen, (ULONG)sock);
  91.  
  92.   CMD(WILL, NAWS);
  93.   CMD(DO, ECHO);
  94.   CMD(DO, SUPPRESS_GO_AHEAD);
  95. }
  96.  
  97.  
  98. /**************************************************************************
  99.  *
  100.  *      EtherClose ( )
  101.  *
  102.  *      Close the currently open ethernet port
  103.  *
  104.  *************************************************************************/
  105.  
  106. ATcpSession::~ATcpSession ( )
  107. {
  108.   soclose(sock);
  109.   sock = 0;
  110. }
  111.  
  112. /**************************************************************************
  113.  *
  114.  *      EtherInit ( )
  115.  *
  116.  *************************************************************************/
  117.  
  118. void ATcpSession::EtherInit ()
  119. {
  120.   struct sockaddr_in    serveri;
  121.   IString               tcphost;
  122.   int                   tcpport;
  123.   unsigned long         icsaddr;
  124.   struct in_addr        inaddr;
  125.  
  126.   tcphost = getStringOption("tcphost", ICS_HOST_DEFAULT);
  127.   tcpport = getIntOption("tcpport", ICS_PORT_DEFAULT);
  128.  
  129.   if (tcphost.subString(1,1).isDigits()) {
  130.     icsaddr = inet_addr(tcphost);
  131.   }
  132.   else {
  133.     struct hostent *hp;
  134.     if ((hp = gethostbyname(tcphost)) == NULL) {
  135.       throw IException(IString("Hostname cannot be resolved: ") + tcphost);
  136.     }
  137.     icsaddr = (hp->h_addr[3]<<24) |
  138.               (hp->h_addr[2]<<16) |
  139.               (hp->h_addr[1]<<8) |
  140.               (hp->h_addr[0]);
  141.   }
  142.   inaddr.s_addr = icsaddr;
  143.   ITRACE_DEVELOP("tcphost="+tcphost+
  144.          " icsaddr="+IString(inet_ntoa(inaddr))+
  145.          " tcpport="+IString(tcpport));
  146.  
  147.   bzero((char *)&serveri, sizeof (serveri));
  148.   serveri.sin_family = AF_INET;
  149.   serveri.sin_port = htons(tcpport);
  150.   serveri.sin_addr.s_addr = icsaddr;
  151.  
  152.   sock = socket ( AF_INET, SOCK_STREAM, 0 );
  153.   if ( sock < 0 ) {
  154.     perror("");
  155.     throw IException(IString(theAppName) + "unable to create socket.");
  156.   }
  157.  
  158.   if (connect(sock,(struct sockaddr *)&serveri, sizeof(serveri)) < 0) {
  159.     perror("");
  160.     throw IException(IString(theAppName) + "unable to open connection.");
  161.   }
  162. }
  163.  
  164.  
  165.  
  166. /**************************************************************************
  167.  *
  168.  *      write ( value )
  169.  *
  170.  *      Send *value* out the specified serial port
  171.  *
  172.  *************************************************************************/
  173.  
  174. int ATcpSession::write (char *data)
  175. {
  176.   return write(data, strlen(data));
  177. }
  178.  
  179.  
  180. int ATcpSession::write (char *data, int len)
  181. {
  182.   int   status;
  183.  
  184.   status = send ( sock , data, len, 0 );
  185.   return status;
  186. }
  187.  
  188.  
  189. /**************************************************************************
  190.  *
  191.  *      EtherInt ()
  192.  *
  193.  *      4.2 interrupt routine
  194.  *
  195.  *************************************************************************/
  196.  
  197. typedef enum STATE_ {
  198.   S_START = 0,
  199.   S_IAC,
  200.   S_IAC_DO,
  201.   S_IAC_DONT,
  202.   S_IAC_WILL,
  203.   S_IAC_WONT,
  204.   S_IAC_SB,
  205.   S_IAC_SB_TTYPE,
  206.   S_IAC_SB_TTYPE_SEND,
  207.   S_IAC_SB_TTYPE_SEND_IAC
  208.   } STATE;
  209.  
  210. /*****************************************************************************/
  211. /* thread does blocking reads against COM: and send data via window */
  212. /* messages to the parent window as data arrives */
  213. /*****************************************************************************/
  214. static VOID _System TcpListen(ULONG sock_)
  215. {
  216.   int           sock = sock_;
  217.   int           bytesRead;
  218.   char          ch[32], *s;
  219.   int           tok;
  220.   static STATE  state = S_START;
  221.   static char   buf[2049], cooked[2049], *putp;
  222.  
  223.   IFUNCTRACE_DEVELOP();
  224.   ITRACE_DEVELOP(IString("listening to com port"));
  225.   if (! IThread::current().isPMInitialized())
  226.     IThread::current().initializePM();
  227.  
  228.   while (1) {
  229.     bytesRead = recv(sock, buf, 2048, 0);
  230.     if (bytesRead <= 0) continue;
  231.     buf[bytesRead] = 0;         // for debug print
  232.  
  233.     ITRACE_DEVELOP(IString(bytesRead) + " bytes received from socket");
  234.  
  235.     putp = cooked;
  236.     for (int i=0; i < bytesRead; i++) {
  237.       tok = (int) buf[i];
  238. //      ITRACE_DEVELOP(IString(tok));
  239.  
  240.       switch(state) {
  241.       case S_START:
  242.         if (tok == IAC) state = S_IAC;
  243.         else if (tok) *putp++ = tok;
  244.         break;
  245.  
  246.       case S_IAC:               // IAC seen
  247.         switch(tok) {
  248.         case DO: state = S_IAC_DO; break;
  249.                case DONT: state = S_IAC_DONT; break;
  250.                case WILL: state = S_IAC_WILL; break;
  251.                case WONT: state = S_IAC_WONT; break;
  252.                case SB: state = S_IAC_SB; break;
  253.  
  254.                default: state=S_START;
  255.                }
  256.         break;
  257.  
  258.       case S_IAC_DO:
  259.         if (tok == TTYPE) {
  260.           ITRACE_DEVELOP("RCVD do TTYPE");
  261.           CMDX(WILL, TTYPE);
  262.           ITRACE_DEVELOP("SEND will TTYPE");
  263.         }
  264.         else if (tok == NAWS) {
  265.           ITRACE_DEVELOP("RCVD do NAWS");
  266.           s = ch;
  267.           *s++ = IAC;
  268.           *s++ = SB;
  269.           *s++ = NAWS;
  270.           *s++ = 0;
  271.           *s++ = 80;
  272.           *s++ = 0;
  273.           *s++ = 24;
  274.           *s++ = IAC;
  275.           *s++ = SE;
  276.           aSession->write(ch, 9);
  277.           ITRACE_DEVELOP("SEND suboption NAWS 80x24");
  278.         }
  279.         state = S_START;
  280.         break;
  281.  
  282.       case S_IAC_SB:
  283.         if (tok == TTYPE) state = S_IAC_SB_TTYPE;
  284.         else state = S_START;
  285.         break;
  286.  
  287.       case S_IAC_SB_TTYPE:
  288.         if (tok == 1) state = S_IAC_SB_TTYPE_SEND;
  289.         else state = S_START;
  290.         break;
  291.  
  292.       case S_IAC_SB_TTYPE_SEND:
  293.         if (tok == IAC) state = S_IAC_SB_TTYPE_SEND_IAC;
  294.         else state = S_START;
  295.         break;
  296.  
  297.       case S_IAC_SB_TTYPE_SEND_IAC:
  298.         if (tok == SE) {
  299.           ITRACE_DEVELOP("RCVD suboption TELOPT_TTYPE SEND");
  300.           // send terminal type
  301.           s = ch;
  302.           *s++ = IAC;
  303.           *s++ = SB;
  304.           *s++ = TTYPE;
  305.           *s++ = 0;
  306.           *s++ = 'v';
  307.           *s++ = 't';
  308.           *s++ = '1';
  309.           *s++ = '0';
  310.           *s++ = '0';
  311.           *s++ = IAC;
  312.           *s++ = SE;
  313.           aSession->write(ch, 11);
  314.           ITRACE_DEVELOP("SEND suboption TELOPT_TTYPE xterm");
  315.         }
  316.         state = S_START;
  317.         break;
  318.  
  319.       default:
  320.         state = S_START;
  321.         break;
  322.       }
  323.     }
  324.  
  325.     if (putp - cooked == 0)
  326.       continue;
  327.     commStream.clear();
  328.     commStream.write(cooked, putp - cooked);
  329.  
  330.     while(1) {
  331.       try {
  332.         hComm.postEvent(MSG_COM_IN);
  333.         break;
  334.       }
  335.       catch (IInvalidParameter) {
  336.         ITRACE_DEVELOP("ComListen: exception caught, sleeping 250");
  337. //      IThread::current().sleep(250);
  338.       }
  339.     }
  340.  
  341.     if (bytesRead < 16)         // avoid flooding queue
  342. //      IThread::current().sleep(100);
  343. ;
  344.   }
  345. }
  346. #endif
  347.