home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / rxtelnet.zip / nvt / nvt.c < prev    next >
C/C++ Source or Header  |  1997-08-19  |  17KB  |  804 lines

  1. #define INCL_DOS
  2. #define INCL_DOSERRORS
  3. #include <os2.h>
  4.  
  5. // #include <ctype.h>
  6. #include <memory.h>
  7. #include <stddef.h>
  8. #include <stdlib.h>
  9.  
  10. #include <netdb.h>
  11. #include <sys\socket.h>
  12.  
  13. #include "telnet.h"
  14.  
  15. #include "nvt.h"
  16. #include "ascii.h"
  17.  
  18.  
  19.  
  20.  /* structure definitions */
  21.  
  22.  #pragma pack(2)
  23.  
  24.  typedef
  25.    struct _linkitem                     /* linked list items         */
  26.    {
  27.      struct _linkitem  *next;           /* next in list              */
  28.      short              length;         /* length of item            */
  29.      char               data[2];        /* start of item data        */
  30.    }
  31.      linkitem;
  32.  
  33.  typedef linkitem *linked;
  34.  
  35.  #pragma pack()
  36.  
  37.  
  38.  typedef
  39.    struct _NVT                          /* NVT control area          */
  40.    {
  41.      PVOID              pool;           /* common storage pool       */
  42.      HEV                available;      /* storage available event   */
  43.      HMTX               lock;           /* mutex lock semaphore      */
  44.      HMTX               sending;        /* send() lock               */
  45.      HEV                ready;          /* inbound data event        */
  46.      linked             pending;        /* ready data queue          */
  47.      short              ind;            /* operational indicators    */
  48.      short              echoing;        /* echoes pending            */
  49.      TID                device;         /* receiver thread id        */
  50.      int                sockit;         /* socket handle             */
  51.      unsigned long      host;           /* host address              */
  52.      unsigned long      port;           /* port address              */
  53.    }
  54.      NVT;
  55.  
  56.  
  57.  /* function prototypes */
  58.  
  59. #define intern static
  60.  
  61. intern            int  cmdkey( char *c );
  62. intern          char*  cmdstr( int i );
  63.  
  64. intern  unsigned long  hostaddress( char *cp );
  65.  
  66. intern            int  pop( HMTX lock, linked *list, linked *item );
  67. intern            int  push( HMTX lock, linked *list, linked item );
  68. intern            int  queue( HMTX lock, linked *list, linked item );
  69.  
  70. intern            int  wait( HEV event, int timeout );
  71. intern            int  post( HEV event );
  72.  
  73. intern          void*  allocpool( void );
  74. intern          void*  relsepool( void* pool );
  75. intern          void*  alloc( void* pool, int bufsize );
  76. intern          void*  relse( void* pool, void* buf, int bufsize );
  77.  
  78. intern            int  nvtransmit( NVT *vt, char *buf, int bufsize, int crlf );
  79. intern  VOID APIENTRY  nvtprotocol( ULONG parm );
  80.  
  81. intern            int  nvtenq( NVT *vt, char *buf, int bufsize );
  82. intern            int  nvtdeq( NVT *vt, char *buf, int bufsize );
  83.  
  84. #define                nvtptr(handle)   (NVT*)((handle))
  85.  
  86.  
  87. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  88.  
  89. HNVT nvtopen( char *hostname, int port )
  90. {
  91.   int   rc = ERROR_NOT_ENOUGH_MEMORY;
  92.  
  93.   NVT    *vt = NULL;
  94.   PVOID pool = allocpool();
  95.  
  96.   if ( pool )
  97.   {
  98.     vt = alloc( pool, sizeof(*vt) );
  99.  
  100.     if ( vt )
  101.     {
  102.       memset( vt, 0, sizeof(*vt) );
  103.  
  104.       vt->pool = pool;
  105.  
  106.       rc = ( DosCreateEventSem( NULL, &(vt->available), 0, FALSE ) ||
  107.              DosCreateEventSem( NULL, &(vt->ready), 0, FALSE ) ||
  108.              DosCreateMutexSem( NULL, &(vt->sending), 0, FALSE ) ||
  109.              DosCreateMutexSem( NULL, &(vt->lock), 0, FALSE ) );
  110.  
  111.       if ( !rc )
  112.       {
  113.         rc = DosCreateThread( &(vt->device),
  114.                               nvtprotocol, (ULONG)vt,
  115.                               CREATE_SUSPENDED |
  116.                               STACK_SPARSE,
  117.                               65536UL );
  118.  
  119.         if ( !rc )
  120.         {
  121.           vt->host = hostaddress( hostname );
  122.  
  123.           if ( vt->host == 0 || vt->host == INADDR_NONE )
  124.             rc = 1;
  125.           else
  126.           {
  127.             vt->sockit = socket( PF_INET, SOCK_STREAM, 0 );
  128.  
  129.             if ( vt->sockit == -1 )
  130.               rc = 1;
  131.             else
  132.             {
  133.               struct sockaddr_in server;
  134.  
  135.               memset( &server, 0, sizeof(server) );
  136.  
  137.               vt->port = port ? port : DEFAULTPORT;
  138.  
  139.               server.sin_family      = AF_INET;
  140.               server.sin_port        = htons(vt->port);
  141.               server.sin_addr.s_addr = vt->host;
  142.  
  143.               rc = connect( vt->sockit,
  144.                             (struct sockaddr *)&server,
  145.                             sizeof(server) );
  146.  
  147.               if ( !rc )
  148.               {
  149.                 vt->pending = NULL;
  150.                 vt->echoing = 0;
  151.  
  152.                 rc = DosResumeThread( vt->device );
  153.               }
  154.             }
  155.           }
  156.         }
  157.       }
  158.  
  159.       if ( rc )
  160.       {
  161.         nvtclose( (HNVT)vt );
  162.         vt = NULL;
  163.       }
  164.     }
  165.   }
  166.  
  167.   return (HNVT)vt;
  168. }
  169.  
  170. int nvtclose( HNVT hnvt )
  171. {
  172.   int rc;
  173.   NVT *vt = nvtptr(hnvt);
  174.  
  175.   if ( vt->device )
  176.     rc = DosKillThread( vt->device );
  177.  
  178.   if ( vt->available )
  179.     rc = DosCloseEventSem( vt->available );
  180.  
  181.   if ( vt->ready )
  182.     rc = DosCloseEventSem( vt->ready );
  183.  
  184.   if ( vt->sending )
  185.     rc = DosCloseMutexSem( vt->sending );
  186.  
  187.   if ( vt->lock )
  188.     rc = DosCloseMutexSem( vt->lock );
  189.  
  190.   if ( vt->sockit )
  191.   {
  192.     rc = shutdown( vt->sockit, 2 );
  193.     rc = soclose( vt->sockit );
  194.   }
  195.  
  196.   if ( vt->pool )
  197.     relsepool( vt->pool );
  198.  
  199.   return 0;
  200. }
  201.  
  202. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  203.  
  204. int nvtcommand( HNVT hnvt, char *command )
  205. {
  206.   int count = 0;
  207.   char cmd[3];
  208.  
  209.   cmd[0] = IAC;
  210.   cmd[1] = cmdkey( command );
  211.  
  212.   if ( cmd[1] )
  213.     count = nvtransmit( nvtptr(hnvt), cmd, 2, FALSE );
  214.  
  215.   return count;
  216. }
  217.  
  218. int nvtquery( HNVT hnvt, LNVT* link )
  219. {
  220.   if ( link )
  221.   {
  222.     NVT *vt = nvtptr(hnvt);
  223.  
  224.     link->addr   = vt->host;
  225.     link->port   = vt->port;
  226.     link->socket = vt->sockit;
  227.   }
  228.  
  229.   return sock_errno();
  230. }
  231.  
  232. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  233.  
  234. int nvtputs( HNVT hnvt, char *buf, int bufsize )
  235. {
  236.   NVT *vt = nvtptr(hnvt);
  237.  
  238.   if ( vt->echoing )
  239.     vt->echoing += 1;
  240.  
  241.   return nvtransmit( vt, buf, bufsize, TRUE );
  242. }
  243.  
  244. int nvtgets( HNVT hnvt, char *buf, int bufsize )
  245. {
  246.   int count = nvtdeq( nvtptr(hnvt), buf, bufsize-1 );
  247.  
  248.   if ( count >= 0 )
  249.     buf[count] = '\0';
  250.  
  251.   return count;
  252. }
  253.  
  254. int nvtpeek( HNVT hnvt, int timeout )
  255. {
  256.   NVT *vt = nvtptr(hnvt);
  257.  
  258.   wait( vt->ready, timeout );
  259.  
  260.   return vt->pending ? 1 : 0;
  261. }
  262.  
  263. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  264.  
  265. int nvtenq( NVT *vt, char *buf, int bufsize )
  266. {
  267.   linked i = NULL;
  268.  
  269.   do { i = alloc( vt->pool, bufsize + offsetof(linkitem,data) ); }
  270.   while ( !i && 0 == wait( vt->available, -1 ) );
  271.  
  272.   if ( i )
  273.   {
  274.     if ( bufsize )
  275.       memcpy( i->data, buf, bufsize );
  276.  
  277.     i->length = bufsize;
  278.  
  279.     queue( vt->lock, &(vt->pending), i );
  280.  
  281.     post( vt->ready );
  282.   }
  283.   else
  284.   {
  285.     bufsize = -bufsize;
  286.   }
  287.  
  288.   return bufsize;
  289. }
  290.  
  291. int nvtdeq( NVT *vt, char *buf, int bufsize )
  292. {
  293.   linked i = NULL;
  294.  
  295.   do { pop( vt->lock, &(vt->pending), &i ); }
  296.   while ( !i && 0 == wait( vt->ready, -1 ) );
  297.  
  298.   if ( !i )
  299.   {
  300.     buf = '\0';
  301.     bufsize = 0;
  302.   }
  303.   else
  304.   {
  305.     if ( i->length > bufsize )
  306.     {
  307.       buf = '\0';
  308.       bufsize = -(i->length);
  309.  
  310.       push( vt->lock, &(vt->pending), i );
  311.     }
  312.     else
  313.     {
  314.       if ( i->length )
  315.       {
  316.         memcpy( buf, i->data, i->length );
  317.         bufsize = i->length;
  318.       }
  319.       else
  320.       {
  321.         buf[0] = '\r';
  322.         bufsize = 1;
  323.       }
  324.  
  325.       relse( vt->pool, i, i->length + offsetof(linkitem,data) );
  326.       post( vt->available );
  327.     }
  328.   }
  329.  
  330.   return bufsize;
  331. }
  332.  
  333. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  334.  
  335. int nvtransmit( NVT *vt, char *buf, int bufsize, int crlf )
  336. {
  337.   int count = 0;
  338.   int used  = 0;
  339.  
  340.   APIRET rc = DosRequestMutexSem( vt->sending, SEM_INDEFINITE_WAIT );
  341.  
  342.   if ( !rc )
  343.   {
  344.     if ( !bufsize )
  345.       count = 1;
  346.     else
  347.       do
  348.       {
  349.         count    = send( vt->sockit, buf, bufsize, 0 );
  350.         bufsize -= count;
  351.         buf     += count;
  352.         used    += count;
  353.       }
  354.       while ( count > 0 && bufsize );
  355.  
  356.     if ( count > 0 )
  357.     {
  358.       count = used;
  359.  
  360.       if ( crlf )
  361.         used = send( vt->sockit, "\r\n", 2, 0 );
  362.     }
  363.  
  364.     rc = DosReleaseMutexSem( vt->sending );
  365.   }
  366.  
  367.   return count;
  368. }
  369.  
  370. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  371.  
  372. #define  TEXT      (LO_ASCII)
  373. #define  NOTEXT    (TEXT-1)
  374. #define  SB_END    (HI_ASCII+1)
  375.  
  376. intern int copy( char *to, char *from )
  377. {
  378.   int count = 0;
  379.   while ( *from ) { *to++ = *from++; count++; }
  380.   return count;
  381. }
  382.  
  383.  
  384. int nvtline( NVT *vt, char *line, int used )
  385. {
  386.   if ( vt->echoing > 1 )
  387.   {
  388.     vt->echoing -= 1;
  389.  
  390.     line -= 1;
  391.     used += 1;
  392.  
  393.     line[0] = ACK;
  394.   }
  395.  
  396.   if ( used )
  397.     used = nvtenq( vt, line, used );
  398.  
  399.   return used;
  400. }
  401.  
  402. VOID APIENTRY nvtprotocol( ULONG parm )
  403. {
  404.   NVT *vt = nvtptr(parm);
  405.  
  406.   char buf[MAXLINESIZE];
  407.   char *next;
  408.   char ch;
  409.  
  410.   long timeout = RECVTIMEOUT;
  411.   int  socks[1];
  412.  
  413.   char will[4]    = { IAC, WILL, 0, 0 };
  414.   char willnot[4] = { IAC, WONT, 0, 0 };
  415.   char donot[4]   = { IAC, DONT, 0, 0 };
  416.  
  417.   char text[MAXLINESIZE+1];
  418.   char *line    = text+1;
  419.   int  linesize = sizeof(text)-1;
  420.   char *current = line;
  421.   int  used     = 0;
  422.  
  423.   int mode  = TEXT;
  424.   int count = 0;
  425.  
  426.   while( mode )
  427.   {
  428.     if ( count < 1 )
  429.     {
  430.       socks[0] = vt->sockit;
  431.  
  432.       count = select( socks, 1, 0, 0, timeout );
  433.  
  434.       if ( count == 0 )
  435.       {
  436.         timeout = -1;
  437.  
  438.         if ( used )
  439.           buf[count++] = LF;
  440.  
  441.         buf[count++] = EOT;
  442.         buf[count++] = LF;
  443.       }
  444.       else
  445.       if ( count > 0 )
  446.       {
  447.         timeout = RECVTIMEOUT;
  448.  
  449.         count = recv( vt->sockit, buf, sizeof(buf)-1, 0 );
  450.       }
  451.  
  452.       if ( count > 0 )
  453.       {
  454.         next = buf;
  455.       }
  456.       else
  457.       {
  458.         /* if count < 0 then socket error  */
  459.         /* if count = 0 then socket closed */
  460.  
  461.         mode = 0;
  462.         break;
  463.       }
  464.     }
  465.  
  466.     /* begin telnet stream state machine */
  467.  
  468.     ch = *next;
  469.  
  470.     switch ( mode )
  471.     {
  472.     case TEXT: switch ( ch )
  473.                {
  474.                case IAC:
  475.                case CR: mode = ch;
  476.                         goto NEXT;
  477.  
  478.                case LF: goto CRLF;
  479.  
  480.                case EOT: goto USE;
  481.  
  482.                default: if ( ch < 0x80 ) goto USE; /* _isascii(ch) */
  483.                }
  484.                goto NEXT;
  485.  
  486.     case CR: switch( ch )
  487.              {
  488.              case NUL:
  489.              case LF: mode = TEXT;
  490.                       goto CRLF;
  491.              }
  492.              mode = TEXT;
  493.              goto NEXT;
  494.  
  495.     case IAC: switch( ch )
  496.               {
  497.               case DO:
  498.               case DONT:
  499.               case WILL:
  500.               case WONT: mode = ch;
  501.                          goto NEXT;
  502.  
  503.               case SB: mode = ch;
  504.                        goto NEXT;
  505.  
  506.               case EC: if ( used ) { current--; used--; }
  507.                        mode = TEXT;
  508.                        goto NEXT;
  509.  
  510.               case EL: mode = TEXT;
  511.                        goto NL;
  512.  
  513.                          /* generate a command message */
  514.               case ABORT:
  515.               case AO:
  516.               case AYT:
  517.               case BREAK:
  518.               case EOR:
  519.               case xEOF:
  520.               case GA:
  521.               case IP:
  522.               case NOP:
  523.               case SUSP:
  524.                         nvtline( vt, line, used );
  525.  
  526.                         line[0] = ENQ;
  527.                         used = 1 + copy( line+1, cmdstr(ch) );
  528.                         mode = TEXT;
  529.                         goto CRLF;
  530.  
  531.               case DM: mode = TEXT;
  532.                        goto NL;
  533.               }
  534.               mode = TEXT;
  535.               goto NEXT;
  536.  
  537.     case DO:
  538.     case DONT: willnot[2] = ch;
  539.                nvtransmit( vt, willnot, 3, FALSE );
  540.                mode = TEXT;
  541.                goto NEXT;
  542.  
  543.     case WILL: switch( ch )
  544.                {
  545.                case TELOPT_ECHO: vt->echoing = 1;
  546.                }
  547.                mode = TEXT;
  548.                goto NEXT;
  549.  
  550.     case WONT: switch( ch )
  551.                {
  552.                case TELOPT_ECHO: vt->echoing = 0;
  553.                }
  554.                mode = TEXT;
  555.                goto NEXT;
  556.  
  557.     case SB: switch( ch )
  558.              {
  559.              case IAC: mode = SB_END;
  560.                        goto NEXT;
  561.              }
  562.              goto NEXT;
  563.  
  564.     case SB_END: switch( ch )
  565.                  {
  566.                  case SE: mode = TEXT;
  567.                           goto NEXT;
  568.                  }
  569.                  mode = SB;
  570.                  goto NEXT;
  571.  
  572.     default: mode = TEXT;
  573.              goto NEXT;
  574.     }
  575.  
  576.     USE:
  577.          *current = ch;
  578.          current++;
  579.          used++;
  580.  
  581.          if ( used < linesize )
  582.            goto NEXT;
  583.     CRLF:
  584.          nvtline( vt, line, used );
  585.     NL:
  586.          current = line;
  587.          used = 0;
  588.  
  589.     NEXT:
  590.          next++;
  591.          count--;
  592.  
  593.     /* end telnet stream state machine */
  594.   }
  595.  
  596.   nvtline( vt, line, used );
  597.  
  598.   if ( count < 0 )  /* socket error */
  599.   {
  600.     line[0] = ENQ;
  601.     line[1] = 'E';
  602.     _itoa( sock_errno(), line+2, 10 );
  603.     used = strlen(line);
  604.  
  605.     nvtline( vt, line, used );
  606.   }
  607.  
  608.   DosPostEventSem( vt->ready );
  609.   DosCloseEventSem( vt->ready );
  610.  
  611.   DosExit(0,0);
  612. }
  613.  
  614. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  615.  
  616.  typedef struct { int i; char *c; } tcmd;
  617.  
  618.  intern tcmd tcmds[] = { GA,    _GA,
  619.                          AYT,   _AYT,
  620.                          AO,    _AO,
  621.                          IP,    _IP,
  622.                          BREAK, _BREAK,
  623.                          NOP,   _NOP,
  624.                          EOR,   _EOR,
  625.                          ABORT, _ABORT,
  626.                          SUSP,  _SUSP,
  627.                          xEOF,  _EOF,
  628.                          0,     "?" };
  629.  
  630. intern int different( char* l, char* s )
  631. {
  632.   while ( *l && *s && *l == ( *s & ~0x20 ) ) { l++; s++; } /* _toupper(*s) */
  633.   return ( *l || *s ) ? 1 : 0;
  634. }
  635.  
  636. int cmdkey( char *c )
  637. {
  638.   tcmd *t = tcmds;
  639.   while ( t->i && different(t->c,c) ) t++;
  640.   return t->i;
  641. }
  642.  
  643. char* cmdstr( int i )
  644. {
  645.   tcmd *t = tcmds;
  646.   while ( t->i && t->i != i ) t++;
  647.   return t->c;
  648. }
  649.  
  650. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  651.  
  652. int pop( HMTX lock, linked *list, linked *item )
  653. {
  654.   linked i = NULL;
  655.   APIRET rc = DosRequestMutexSem( lock, SEM_INDEFINITE_WAIT );
  656.  
  657.   if ( !rc )
  658.   {
  659.     i = *list;
  660.  
  661.     if ( i ) *list = i->next;
  662.  
  663.     rc = DosReleaseMutexSem( lock );
  664.   }
  665.  
  666.    *item = i;
  667.    return rc ? 0 : 1;
  668. }
  669.  
  670. int push( HMTX lock, linked *list, linked item )
  671. {
  672.   APIRET rc = DosRequestMutexSem( lock, SEM_INDEFINITE_WAIT );
  673.  
  674.   if ( !rc )
  675.   {
  676.     item->next = *list;
  677.     *list = item;
  678.  
  679.     rc = DosReleaseMutexSem( lock );
  680.   }
  681.  
  682.    return rc ? 0 : 1;
  683. }
  684.  
  685. int queue( HMTX lock, linked *list, linked item )
  686. {
  687.   APIRET rc = DosRequestMutexSem( lock, SEM_INDEFINITE_WAIT );
  688.  
  689.   if ( !rc )
  690.   {
  691.     item->next = NULL;
  692.  
  693.     if ( *list )
  694.     {
  695.       linked i = *list;
  696.       while ( i && i->next ) i = i->next;
  697.       i->next = item;
  698.     }
  699.     else
  700.     {
  701.       *list = item;
  702.     }
  703.  
  704.     rc = DosReleaseMutexSem( lock );
  705.   }
  706.  
  707.   return rc ? 0 : 1;
  708. }
  709.  
  710. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  711.  
  712. #define PAGESIZE 4096
  713.  
  714. void* allocpool()
  715. {
  716.   APIRET rc;
  717.   PVOID  pool = NULL;
  718.  
  719.   rc = DosAllocMem( &pool,
  720.                     PAGESIZE,
  721.                     PAG_READ | PAG_WRITE );
  722.   if ( !rc )
  723.     rc = DosSubSetMem( pool,
  724.                        DOSSUB_INIT |
  725.                        DOSSUB_SERIALIZE |
  726.                        DOSSUB_SPARSE_OBJ,
  727.                        PAGESIZE );
  728.  
  729.   return pool;
  730. }
  731.  
  732. void* relsepool( void* pool )
  733. {
  734.   APIRET rc;
  735.  
  736.   if ( pool )
  737.   {
  738.     rc = DosSubUnsetMem( pool );
  739.     rc = DosFreeMem( pool );
  740.     pool = NULL;
  741.   }
  742.  
  743.   return pool;
  744. }
  745.  
  746. void* alloc( void* pool, int bufsize )
  747. {
  748.   APIRET rc = 1;
  749.   PVOID  buf;
  750.  
  751.   if ( pool )
  752.     rc = DosSubAllocMem( pool, &buf, bufsize );
  753.  
  754.   return rc ? NULL : buf;
  755. }
  756.  
  757. void* relse( void* pool, void* buf, int bufsize )
  758. {
  759.   APIRET rc = 1;
  760.  
  761.   if ( pool )
  762.     rc = DosSubFreeMem( pool, buf, bufsize );
  763.  
  764.   return rc ? buf : NULL;
  765. }
  766.  
  767. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  768.  
  769. int wait( HEV event, int timeout )
  770. {
  771.   int rc = DosWaitEventSem( event, timeout );
  772.  
  773.   if ( !rc )
  774.   {
  775.     ULONG count;
  776.     rc = DosResetEventSem( event, &count );
  777.   }
  778.  
  779.   return rc;
  780. }
  781.  
  782. int post( HEV event )
  783. {
  784.   return DosPostEventSem( event );
  785. }
  786.  
  787. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  788.  
  789. unsigned long hostaddress( char *cp )
  790. {
  791.   unsigned long address = inet_addr( cp );
  792.  
  793.   if ( address == 0 || address == INADDR_NONE )
  794.   {
  795.     struct hostent *hp = gethostbyname( cp );
  796.  
  797.     if ( hp )
  798.       address = *((unsigned long *)(hp->h_addr));
  799.   }
  800.  
  801.   return address;
  802. }
  803.  
  804.