home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / PPPBCKP / SRC / SRC15B40.ZIP / WATTSRC.ZIP / APPS / TCPPORT.C < prev    next >
Text File  |  1994-11-28  |  18KB  |  677 lines

  1.  
  2. #define OLD 1       /* new changes not complete */
  3.  
  4. /*
  5.  * TCPPORT - make tcp connections from virtual serial ports
  6.  *
  7.  * Copyright (C) 1989, 1990, 1991, University of Waterloo
  8.  * Portions Copyright (C) 1991, Trustees of Columbia University
  9.  *    in the City of New York.  Permission is granted to any
  10.  *    individual or institution to use, copy, or redistribute
  11.  *    this software as long as it is not sold for profit, provided
  12.  *    this copyright notice is retained.
  13.  *
  14.  *   This program is distributed in the hope that it will be useful,
  15.  *   but without any warranty; without even the implied warranty of
  16.  *   merchantability or fitness for a particular purpose.
  17.  *
  18.  * Authors:
  19.  * Erick Engelke (erick@development.watstar.uwaterloo.ca),
  20.  *     Engineering Computing, University of Waterloo.
  21.  * Bruce Campbell (bruce@development.watstar.uwaterloo.ca),
  22.  *      Engineering Computing, University of Waterloo
  23.  * Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  24.  *    Columbia University Center for Computing Activities.
  25.  *
  26.  *   1.00 - May 13, 1991 : E. Engelke - stole negotiations from Frank's
  27.  *             & F. Da Cruz   telnet portion of C-KERMIT
  28.  *   0.04 - May  7, 1991 : E. Engelke - got echo/no echo working
  29.  *   0.03 - Apr 24, 1991 : E. Engelke - hacked terminal negotiation
  30.  *   0.02 - Mar 24, 1991 : E. Engelke - convert \r to \n for UNIX compatibility
  31.  *   0.01 - Feb   , 1991 : E. Engelke - converted Bruce's program to TCP
  32.  * - 1.00 -              : B. Campbell- created original program
  33.  *
  34.  *  To force a particular terminal type, set the environment variable
  35.  *  tcpterm to something like vt102, vt100, etc.
  36.  *
  37.  *  To decrease the size of the executable I have used outs rather than
  38.  *  printf.  outs is used by the Waterloo TCP kernal for displaying error
  39.  *  messages through the BIOS services.
  40.  *
  41.  */
  42.  
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <ctype.h>
  47. #include <mem.h>
  48. #include <dos.h>
  49. #include <conio.h>
  50. #include <tcp.h>
  51.  
  52.  
  53. typedef struct stk {
  54.     word bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs;
  55. };
  56.  
  57. extern outhexes( byte far *p, int n );
  58.  
  59.  
  60. #define IAC     255
  61. #define DONT    254
  62. #define DO      253
  63. #define WONT    252
  64. #define WILL    251
  65. #define SB      250
  66. #define BREAK   243
  67. #define SE      240
  68.  
  69. #define TELOPT_ECHO     1
  70. #define TELOPT_SGA      3
  71. #define TELOPT_STATUS   5
  72. #define TELOPT_TTYPE    24
  73. #define NTELOPTS        24
  74.  
  75. #define TCPTERM    "TCPTERM"    /* environment variable */
  76.  
  77. char termtype[ 32 ];    /* from the environment, used in negotiations */
  78. int echo = 1;            /* default on, but hate it */
  79.  
  80.  
  81. #define TRANSMIT_TICKS      1        /* do the transmit after this many ticks */
  82. #define TRANSMIT_BUF_SIZE 4096
  83. #define TRANSMIT_MAX      256       /* most to transmit at a time */
  84.  
  85. #define RECEIVE_TICKS    1
  86. #define RECEIVE_BUF_SIZE 4096
  87.  
  88. extern unsigned long rdvct();
  89. extern unsigned long get_general();
  90.  
  91. void far serial_2();
  92. void far serial_t();
  93.  
  94. unsigned char transmit_buffer[ TRANSMIT_BUF_SIZE ];
  95. unsigned char receive_buffer[ RECEIVE_BUF_SIZE ];
  96. unsigned int tran_in = 0;
  97. unsigned int tran_out = 0;
  98. unsigned int rec_in = 0;
  99. unsigned int rec_out = 0;
  100. int transmit_clock = TRANSMIT_TICKS;
  101. int receive_clock = RECEIVE_TICKS;
  102.  
  103. void interrupt far (*old14)(void);
  104. void interrupt far (*old8)(void);
  105.  
  106.  
  107. word oldsp, oldss;
  108. char stack[ 8192 ];
  109. char bigbuf[ 8192 ];    /* used to speed up tcp recvs */
  110. longword host;
  111. tcp_Socket *s, socketdata;
  112. int moved_vectors = 0;
  113. int sock_status = 0;
  114.  
  115.  
  116. int sem_stack = 0;
  117.  
  118. struct stk far *stkptr;
  119. longword recvtimeout;
  120.  
  121.  
  122.  
  123. /* TCP/IP Telnet negotiation support code */
  124.  
  125. static int sgaflg = 0;                      /* telnet SGA flag */
  126.  
  127. #ifndef TELCMDS
  128. char *telcmds[] = {
  129.     "SE", "NOP", "DMARK", "BRK",  "IP",   "AO", "AYT",  "EC",
  130.     "EL", "GA",  "SB",    "WILL", "WONT", "DO", "DONT", "IAC",
  131. };
  132. #endif /* TELCMDS */
  133.  
  134. char *telopts[] = {
  135.         "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME",
  136.         "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP",
  137.         "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS",
  138.         "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
  139.         "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
  140.     "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD",
  141.     "TACACS UID", "OUTPUT MARKING", "TTYLOC", "3270 REGIME",
  142.     "X.3 PAD", "NAWS", "TSPEED", "LFLOW", "LINEMODE"
  143. };
  144.  
  145. int ntelopts = sizeof(telopts) / sizeof(char *);
  146.  
  147. /*
  148.  * prototypes
  149.  */
  150. void do_reception(void);
  151. int do_transmission(void);
  152. int ttinc( int fast );
  153. int tn_sttyp(void);
  154. unsigned  sytek_int( unsigned ax /*, unsigned dx */ );
  155.  
  156. /*
  157.  * send_iac - send interupt character and pertanent stuff
  158.  *        - return 0 on success
  159.  */
  160.  
  161. int send_iac( char cmd, char opt)
  162. {
  163.     byte io_data[3];
  164.     io_data[0] = IAC;
  165.     io_data[1] = cmd;
  166.     io_data[2] = opt;
  167.     sock_fastwrite( s, io_data, 3 );
  168.     return( !tcp_tick( s ));
  169. }
  170.  
  171.  
  172. /* Initialize a telnet connection. */
  173. /* Returns -1 on error, 0 is ok */
  174.  
  175. int tn_ini( void )
  176. {
  177.     sgaflg = 0;                         /* SGA flag starts out this way. */
  178.     if (send_iac( WILL, TELOPT_TTYPE )) return( -1 );
  179.     if (send_iac( DO, TELOPT_SGA )) return( -1 );
  180.  
  181. /*
  182.  *  The ECHO negotiations are not necessary for talking to full-duplex
  183.  *  systems, and they don't seem to do any good when sent to half-duplex
  184.  *  ones -- they still refuse to echo, and what's worse, they get into
  185.  *  prolonged negotiation loops.  Real telnet sends only the two above
  186.  *  at the beginning of a connection.
  187.  */
  188.  
  189.     if (send_iac(WONT,TELOPT_ECHO)) return( -1 );  /* I won't echo. */
  190.     if (send_iac(DO,TELOPT_ECHO)) return( -1 );       /* Please, you echo. */
  191.     return(0);
  192. }
  193.  
  194. /*
  195.  * Process in-band Telnet negotiation characters from the remote host.
  196.  * Call with the telnet IAC character and the current duplex setting
  197.  * (0 = remote echo, 1 = local echo).
  198.  * Returns:
  199.  *   0 on success
  200.  *  -1 on failure (= internal or i/o error)
  201.  */
  202.  
  203. #define TSBUFSIZ 41
  204. char sb[TSBUFSIZ];                      /* Buffer for subnegotiations */
  205.  
  206. int tn_doop(int c)
  207. {
  208.     int x, y, n, flag;
  209.  
  210.  
  211.     x = ttinc(0) & 0xff;                /* Read command character */
  212.  
  213.     switch (x) {
  214.       case TELOPT_ECHO:                 /* ECHO negotiation. */
  215.         if (c == WILL) {                /* Host says it will echo. */
  216.         if (echo) {                 /* Only reply if change required */
  217.         echo = 0;
  218.         if (send_iac(DO,x))      /* Please do. */
  219.             return(-1);
  220.         }
  221.         return(0);
  222.     }
  223.  
  224.         if (c == WONT) {                /* Host says it won't echo. */
  225.             if (!echo) {                /* If I'm not echoing already */
  226.         if (send_iac(DONT,x)) /* agree to echo. */
  227.             return(-1);
  228.         echo = 1;
  229.         }
  230.         return(0);
  231.     }
  232.  
  233.         if (c == DO) {                  /* Host wants me to echo */
  234.         if (send_iac(WONT,x))    /* I say I won't, */
  235.         return(-1);
  236.         if (send_iac(DO,x))        /* and ask the host to echo. */
  237.         return(-1);
  238.         echo = 0;
  239.         return( 0 );
  240.         }
  241.         if (c == DONT) {                /* Host wants me not to echo */
  242.         if (send_iac(WONT,x))    /* I say I won't. */
  243.         return(-1);
  244.         echo = 0;
  245.         return( 0 );
  246.         }
  247.         return(0);
  248.  
  249.  
  250.       case TELOPT_SGA:                  /* Suppress Go-Ahead */
  251.         if (c == WONT) {                /* Host says it won't. */
  252.             sgaflg = 1;                 /* Remember. */
  253.             if (!echo) {                /* If we're not echoing, */
  254.         if (send_iac(DONT,x)) /* acknowledge, */
  255.             return(-1);
  256.         echo = 1;        /* and switch to local echo. */
  257.         }
  258.         }
  259.         if (c == WILL) {                /* Host says it will. */
  260.             sgaflg = 0;                 /* Remember. */
  261.             if (echo) {                 /* If I'm echoing now, */
  262.         if (send_iac(DO,x))    /* this is a change, so ACK. */
  263.             return(-1);
  264.         if (send_iac(DO,TELOPT_ECHO)) /* Request remote echo */
  265.             return(-1);
  266.             }
  267.         }
  268.         return(0);
  269.  
  270.  
  271.       case TELOPT_TTYPE:                /* Terminal Type */
  272.         switch (c) {
  273.           case DO:                      /* DO terminal type. */
  274.         if (send_iac(WILL,x))    /* Say I'll send it if asked. */
  275.         return(-1);
  276.         return(0);
  277.  
  278.       /* enter subnegociations */
  279.           case SB:
  280.             n = flag = 0;               /* Flag for when done reading SB */
  281.             while (n < TSBUFSIZ) {      /* Loop looking for IAC SE */
  282.                 if ((y = ttinc(0)) < 0)
  283.           return(-1);
  284.         y &= 0xff;              /* Make sure it's just 8 bits. */
  285.         sb[n++] = y;            /* Save what we got in buffer. */
  286.  
  287.                 if (y == IAC) {         /* If this is an IAC */
  288.                     flag = 1;           /* set the flag. */
  289.                 } else {                /* Otherwise, */
  290.                     if (flag && y == SE) /* if this is SE which immediately */
  291.                       break;            /* follows IAC, we're done. */
  292.                     else flag = 0;      /* Otherwise turn off flag. */
  293.                 }
  294.         }
  295.         if (!flag)
  296.            return(-1);      /* Make sure we got a valid SB */
  297.  
  298.  
  299.         if ( *sb == 1 ) {
  300.         if ( tn_sttyp() )
  301.                   return(-1);
  302.         };
  303.  
  304.  
  305.           default:                      /* Others, ignore */
  306.             return(0);
  307.         }
  308.  
  309.       default:                          /* All others: refuse */
  310.         switch(c) {
  311.           case WILL:                    /* You will? */
  312.         if (send_iac(DONT,x))    /* Please don't. */
  313.         return(-1);
  314.             break;
  315.           case DO:                      /* You want me to? */
  316.         if (send_iac(WONT,x))    /* I won't. */
  317.         return(-1);
  318.         if (send_iac(DONT,x))    /* Don't you either. */
  319.         return(-1);
  320.             break;
  321.           case DONT:                    /* (fall thru...) */
  322.         if (send_iac(WONT,x))    /* I won't. */
  323.         return(-1);
  324.           case WONT:                    /* You won't? */
  325.             break;                      /* Good. */
  326.           }
  327.         return(0);
  328.     }
  329. }
  330.  
  331.  
  332. /*
  333.  * serial port portion
  334.  *
  335.  */
  336.  
  337.  
  338. /* Telnet send terminal type */
  339. /* Returns -1 on error, 0 on success */
  340.  
  341. int tn_sttyp(void)
  342. {                            /* Send telnet terminal type. */
  343.     char *ttn;
  344.     int ttl;                 /* Name & length of terminal type. */
  345.  
  346.     ttn = termtype;        /* we already got this from environment */
  347.     if ((*ttn == 0) || ((ttl = strlen(ttn)) >= TSBUFSIZ)) {
  348.         ttn = "UNKNOWN";
  349.         ttl = 7;
  350.     }
  351.     ttn = strcpy(&sb[1],ttn);        /* Copy to subnegotiation buffer */
  352.     ttn = strchr( strupr(ttn), 0 );
  353.  
  354.     *sb    = 0;                /* 'is'... */
  355.     *ttn++ = IAC;
  356.     *ttn   = SE;
  357.  
  358.     if (send_iac(SB,TELOPT_TTYPE))    /* Send: Terminal Type */
  359.     return(-1);
  360.  
  361.     sock_fastwrite( s, sb, ttl+3 );
  362.     return(0);
  363. }
  364.  
  365.  
  366. /*
  367.  * ttinc   - destructively read a character from our buffer
  368.  *       - if fast = 0, never times out
  369.  */
  370. int ttinc( int fast )
  371. {
  372.     char ch;
  373.  
  374.     /* organized to reduce number of set_timeouts when data waiting */
  375.     while ( rec_in == rec_out ) {
  376.         if ( !tcp_tick( s )) {
  377.         sock_status = 0;
  378.             s = NULL;
  379.             return( -1 );
  380.         }
  381.  
  382.         /* do processing */
  383.     kbhit();
  384.         do_transmission();
  385.         do_reception();
  386.  
  387.         if (fast) break;
  388.     }
  389.     ch = receive_buffer[ rec_out ];
  390.     if ( ++rec_out >= RECEIVE_BUF_SIZE ) rec_out = 0;
  391.     return( (word)(ch) & 0x00ff );
  392. }
  393.  
  394. void interrupt ourhandler(unsigned bp /* , unsigned di, unsigned si, unsigned ds,
  395.    unsigned es, unsigned dx, unsigned cx, unsigned bx, unsigned ax,
  396.    unsigned ip, unsigned cs, unsigned flgs */)  /* trailing parms not used */
  397. {
  398.     stkptr = (struct stk far *)&bp;
  399.  
  400.     oldss = _SS;
  401.     oldsp = _SP;
  402.     _SS = FP_SEG(stack);
  403.     _SP = FP_OFF(&stack[ sizeof( stack ) - 2 ]);
  404.     stkptr->ax = sytek_int( stkptr->ax /*, stkptr->dx*/ );
  405.     _SS = oldss;
  406.     _SP = oldsp;
  407. }
  408.  
  409. void stuff_char( char ch )
  410. {
  411.     transmit_buffer[ tran_in ] = ch;
  412.     tran_in = (tran_in + 1) % TRANSMIT_BUF_SIZE;
  413. }
  414.  
  415. unsigned  sytek_int( unsigned ax /*, unsigned dx */ )
  416. {
  417.     unsigned char ah;
  418.     unsigned char ch;
  419. /*    int sent; */
  420.     unsigned int status;
  421.  
  422.  
  423.     if ( !s ) {
  424.         return( 0x1000 );   /* timeout */
  425.     }
  426.  
  427.     if (chk_timeout( recvtimeout )) {
  428.         do_reception();
  429.         recvtimeout = set_ttimeout( 2 );    /* 10 ms */
  430.     }
  431.  
  432.     /* disable(); receive_clock = RECEIVE_TICKS; enable(); } */
  433.  
  434.     ah = ax >> 8;
  435.  
  436.     if( ah == 1 ) {            /* send char in AL */
  437.     ch = ax & 0x0FF;
  438. /*    if (ch == '\r') ch = '\n'; */
  439.  
  440.     if( ((tran_in + 1) % TRANSMIT_BUF_SIZE) == tran_out ) {
  441.         outs( "?tr_buf_full?" );
  442.         status = 0x08000 | ch;
  443.     } else {
  444.         if ((ch == '\r') && echo ) stuff_char( '\n' );
  445.         else stuff_char( ch );
  446.  
  447.         status = 0x06000 | ch;
  448.  
  449.         /* local echoing if requested */
  450.         if ( echo ) {
  451.         receive_buffer[ rec_in ] = ch;
  452.         rec_in = (rec_in + 1) % RECEIVE_BUF_SIZE;
  453.         if (ch == '\r') {
  454.             receive_buffer[ rec_in ] = '\n';
  455.             rec_in = (rec_in + 1) % RECEIVE_BUF_SIZE;
  456.         }
  457.         }
  458.     }
  459.     } else if( ah == 2 ) {        /* receive char into AL */
  460.         do {
  461.             ch = 0;
  462.             if( rec_in == rec_out )
  463.             status = 0x08000;
  464.             else {
  465.         status = ch = (ttinc( 0 ) & 0xff);
  466.                 if ( ch == IAC ) {
  467.                     /* process this stuff */
  468.             ch = ttinc( 0 );
  469.                     if ( ch == IAC ) ch = 0; /* let it pass through */
  470.             else tn_doop(ch);
  471.                 }
  472.             }
  473.     } while ( ch == IAC );
  474.     /* status = 0x0800; timeout */
  475.     }
  476.     else if( ah == 3 ) {        /* get status */
  477.     if( rec_in == rec_out )
  478.         status = 0x06010;
  479.     else {
  480.         status = 0x06110;
  481.     }
  482.  
  483.     } else if( ah == 0 ) {        /* init port */
  484.     status = 0x06010;
  485.     } else {
  486.     status = ax;
  487.     outs( "?command_err?" );
  488.     }
  489.  
  490.     /* here we do the io */
  491.     if( transmit_clock <= 0 ) {
  492.         do_transmission();
  493.         disable();
  494.         transmit_clock = TRANSMIT_TICKS;
  495.         enable();
  496.     }
  497.  
  498.     return( status );
  499. }
  500.  
  501. void sytek_tick( void )
  502. {
  503.     if( transmit_clock ) transmit_clock--;
  504.     if( receive_clock ) receive_clock--;
  505. }
  506.  
  507. void interrupt tcpport_tick( void )
  508. {
  509.     (*old8)();
  510.     if( transmit_clock ) transmit_clock--;
  511.     if( receive_clock ) receive_clock--;
  512. }
  513.  
  514. void do_reception(void)
  515. {
  516.     unsigned int maxtransfer;
  517. #ifdef OLD
  518.     unsigned int newtransfer;
  519.     int status;
  520.     unsigned int chars_avail, i;
  521. #endif
  522.  
  523.     sock_tick( s, &status );
  524.  
  525. #ifdef OLD
  526.     if ( sock_dataready( s )) {
  527.     if (rec_out > rec_in ) {
  528.         /* we can fill intermediate portion of buffer */
  529.         maxtransfer = rec_out - rec_in;
  530.     } else {
  531.         /* we fill end of buffer and leave start for next attempt */
  532.         maxtransfer = RECEIVE_BUF_SIZE - rec_in;
  533.     }
  534.     if (maxtransfer) {
  535.         rec_in += sock_fastread( s, &receive_buffer[ rec_in ], maxtransfer );
  536.         if ( rec_in >= RECEIVE_BUF_SIZE )
  537.         rec_in -= RECEIVE_BUF_SIZE;
  538.     }
  539.     }
  540. #else
  541.     maxtransfer = RECEIVE_BUF_SIZE - rec_in;
  542.     if (rec_out > rec_in) maxtransfer = rec_out - rec_in;
  543.     maxtransfer = sock_recv( s, &receive_buffer[ rec_in ], maxtransfer );
  544.     if (maxtransfer)
  545.     rec_in = (rec_in + maxtransfer) % RECEIVE_BUF_SIZE ;
  546. #endif OLD
  547. /*    return( 0 ); */
  548.     return;
  549.  
  550. sock_err:
  551.     switch (status) {
  552.     case 1 : outs("\n\r\7[??Host closed connection??]\n\r");
  553.          break;
  554.     case-1 : outs("\n\r\7[??Host reset connection??]\n\r");
  555.          break;
  556.     }
  557.     s = NULL;
  558.     sock_status = 0;
  559. }
  560.  
  561. int do_transmission(void)
  562. {
  563.     unsigned int send_chars;
  564.     int status;
  565.  
  566.     if( tran_in == tran_out ) return(0);
  567.  
  568.     if( tran_in > tran_out )
  569.     send_chars = tran_in - tran_out;
  570.     else
  571.     send_chars = TRANSMIT_BUF_SIZE - tran_out;
  572.  
  573.     if( send_chars > TRANSMIT_MAX ) send_chars = TRANSMIT_MAX;
  574.  
  575.     sock_flushnext( s );
  576.     send_chars = sock_fastwrite( s, &transmit_buffer[ tran_out], send_chars );
  577.  
  578.     /* this only changes it by the number of bytes we have emptied out */
  579.     tran_out = (tran_out + send_chars) % TRANSMIT_BUF_SIZE;
  580.  
  581.     return(0);
  582. }
  583.  
  584.  
  585. int main( int argc, char *argv[] )
  586. {
  587. /*    int i; */
  588.     int status = 0;
  589.     char *temp;
  590.  
  591.     if (argc < 4 ) {
  592.     outs("SERTN host port program options\n\r");
  593.     exit(1);
  594.     }
  595.  
  596.     sock_init();
  597.  
  598.     if (!( host = resolve( argv[1] ))) {
  599.     outs( "Bad Host\n\r" );
  600.     exit(1);
  601.     }
  602.  
  603.     if ( (temp = getenv( TCPTERM )) != NULL ) {
  604.     /* deal with strncpy limitation */
  605.     movmem( temp, termtype, sizeof( termtype ));
  606.     termtype[ sizeof(termtype) -1 ] = 0;
  607.     outs("TERMINAL EMULATION :");
  608.     outs( termtype );
  609.     outs("\n\r");
  610.     } else
  611.     strcpy(termtype, "UNKNOWN");
  612.  
  613.  
  614.     s = &socketdata;
  615.     if ( host == my_ip_addr ) {
  616.     outs("Incomming sessions not supported...\n\r");
  617.     sock_wait_established( s, 0, NULL, &status );
  618.     exit( -3 );
  619.     }
  620.  
  621.     if (! tcp_open( s, 0, host, atoi( argv[2]), NULL )) {
  622. #ifndef OLD
  623.     sock_recv_init( s, bigbuf, sizeof( bigbuf ), 0);
  624. #endif OLD
  625.     outs( "Unable to open\n\r");
  626.     exit(1);
  627.     }
  628.  
  629.     sock_wait_established( s, sock_delay, NULL, &status );
  630.  
  631.     sock_mode( s, TCP_MODE_NAGLE );
  632.  
  633.     sock_status = 1;        /* allow interrupts */
  634.  
  635.     /* move vectors */
  636.     moved_vectors = 1;
  637.     old8 =  getvect( 0x08 );
  638.     old14 =  getvect( 0x014 );
  639. /*
  640.     setvect( 0x08, (void interrupt (*)())serial_t );
  641. */
  642.     setvect( 0x08, tcpport_tick );
  643.     setvect( 0x014,ourhandler);  /* was serial_2 */
  644.     recvtimeout = set_ttimeout( 1 );
  645.  
  646.     outs("Running...");
  647.     outs( argv[3] );
  648.     outs( "\n\r");
  649.     system( argv[ argc-1 ] );
  650.  
  651.     outs("Done, now closing session\n\r");
  652.  
  653.     setvect( 0x014, old14 );
  654.     setvect( 0x08, old8 );
  655.     moved_vectors = 0;
  656.  
  657.     if ( s ) {
  658.     sock_close( s );
  659.     sock_wait_closed( s, sock_delay, NULL, &status );
  660.     }
  661.  
  662. sock_err:
  663.     switch (status) {
  664.     case 1 : outs("Done.\n\r");
  665.          break;
  666.     case -1: outs("Remote host reset connection.");
  667.          break;
  668.     }
  669.     if (moved_vectors) {
  670.     setvect( 0x014, old14 );
  671.     setvect( 0x08, old8 );
  672.     }
  673.  
  674.     exit( (status)? 2 : 0);
  675.     return (0);   /* not reached */
  676. }
  677.