Пример #1
0
    virtual int read(char *buf, int maxlen) {
	int l = TerminalRead(buf, maxlen);
	if (l<0 && errno==WSAEWOULDBLOCK) l = 0;
	else if (l==0 && MODE_LOCAL_CHARS(globalmode) &&
		 (GetFileType(tin) == FILE_TYPE_CHAR)) {
	    /* EOF detection for line mode!!!! */
	    /* must be an EOF... */
	    *buf = termEofChar;
	    l = 1;
	}
	return l;
    }
Пример #2
0
int
TerminalSpecialChars (int c)
{
  if (c == termIntChar)
    {
      intp ();
      return 0;
    }
  else if (c == termQuitChar)
    {
#ifdef	KLUDGELINEMODE
      if (kludgelinemode)
	sendbrk ();
      else
#endif
	sendabort ();
      return 0;
    }
  else if (c == termEofChar)
    {
      if (my_want_state_is_will (TELOPT_LINEMODE))
	{
	  sendeof ();
	  return 0;
	}
      return 1;
    }
  else if (c == termSuspChar)
    {
      sendsusp ();
      return (0);
    }
  else if (c == termFlushChar)
    {
      xmitAO ();		/* Transmit Abort Output */
      return 0;
    }
  else if (!MODE_LOCAL_CHARS (globalmode))
    {
      if (c == termKillChar)
	{
	  xmitEL ();
	  return 0;
	}
      else if (c == termEraseChar)
	{
	  xmitEC ();		/* Transmit Erase Character */
	  return 0;
	}
    }
  return 1;
}
Пример #3
0
static int
telsnd(void)
{
    int tcc;
    int count;
    int returnValue = 0;
    unsigned char *tbp;

    tcc = 0;
    count = 0;
    while (NETROOM() > 2) {
	int sc;
	int c;

	if (tcc == 0) {
	    if (count) {
		ring_consumed(&ttyiring, count);
		returnValue = 1;
		count = 0;
	    }
	    tbp = ttyiring.consume;
	    tcc = ring_full_consecutive(&ttyiring);
	    if (tcc == 0) {
		break;
	    }
	}
	c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
	if (rlogin != _POSIX_VDISABLE) {
		if (bol) {
			bol = 0;
			if (sc == rlogin) {
				local = 1;
				continue;
			}
		} else if (local) {
			local = 0;
			if (sc == '.' || c == termEofChar) {
				bol = 1;
				command(0, "close\n", 6);
				continue;
			}
			if (sc == termSuspChar) {
				bol = 1;
				command(0, "z\n", 2);
				continue;
			}
			if (sc == escape) {
				command(0, tbp, tcc);
				bol = 1;
				count += tcc;
				tcc = 0;
				flushline = 1;
				break;
			}
			if (sc != rlogin) {
				++tcc;
				--tbp;
				--count;
				c = sc = rlogin;
			}
		}
		if ((sc == '\n') || (sc == '\r'))
			bol = 1;
	} else if (escape != _POSIX_VDISABLE && sc == escape) {
	    /*
	     * Double escape is a pass through of a single escape character.
	     */
	    if (tcc && strip(*tbp) == escape) {
		tbp++;
		tcc--;
		count++;
		bol = 0;
	    } else {
		command(0, (char *)tbp, tcc);
		bol = 1;
		count += tcc;
		tcc = 0;
		flushline = 1;
		break;
	    }
	} else
	    bol = 0;
#ifdef	KLUDGELINEMODE
	if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
	    if (tcc > 0 && strip(*tbp) == echoc) {
		tcc--; tbp++; count++;
	    } else {
		dontlecho = !dontlecho;
		settimer(echotoggle);
		setconnmode(0);
		flushline = 1;
		break;
	    }
	}
#endif
	if (MODE_LOCAL_CHARS(globalmode)) {
	    if (TerminalSpecialChars(sc) == 0) {
		bol = 1;
		break;
	    }
	}
	if (my_want_state_is_wont(TELOPT_BINARY)) {
	    switch (c) {
	    case '\n':
		    /*
		     * If we are in CRMOD mode (\r ==> \n)
		     * on our local machine, then probably
		     * a newline (unix) is CRLF (TELNET).
		     */
		if (MODE_LOCAL_CHARS(globalmode)) {
		    NETADD('\r');
		}
		NETADD('\n');
		bol = flushline = 1;
		break;
	    case '\r':
		if (!crlf) {
		    NET2ADD('\r', '\0');
		} else {
		    NET2ADD('\r', '\n');
		}
		bol = flushline = 1;
		break;
	    case IAC:
		NET2ADD(IAC, IAC);
		break;
	    default:
		NETADD(c);
		break;
	    }
	} else if (c == IAC) {
	    NET2ADD(IAC, IAC);
	} else {
	    NETADD(c);
	}
    }
    if (count)
	ring_consumed(&ttyiring, count);
    return returnValue||count;		/* Non-zero if we did anything */
}
Пример #4
0
int
process_rings (int netin, int netout, int netex, int ttyin, int ttyout,
	       int poll)
	/* If poll == 0, then block until something to do */
{
  int c;
  /* One wants to be a bit careful about setting returnValue
   * to one, since a one implies we did some useful work,
   * and therefore probably won't be called to block next
   * time (TN3270 mode only).
   */
  int returnValue = 0;
  static struct timeval TimeValue = { 0, 0 };
  int maxfd = -1;
  int tmp;

  if ((netout || netin || netex) && net > maxfd)
    maxfd = net;
  if (ttyout && tout > maxfd)
    maxfd = tout;
  if (ttyin && tin > maxfd)
    maxfd = tin;
  tmp = howmany (maxfd + 1, NFDBITS) * sizeof (fd_mask);
  if (tmp > fdsn)
    {
      if (ibitsp)
	free (ibitsp);
      if (obitsp)
	free (obitsp);
      if (xbitsp)
	free (xbitsp);
      fdsn = tmp;
      if ((ibitsp = (fd_set *) malloc (fdsn)) == NULL)
	err (1, "malloc");
      if ((obitsp = (fd_set *) malloc (fdsn)) == NULL)
	err (1, "malloc");
      if ((xbitsp = (fd_set *) malloc (fdsn)) == NULL)
	err (1, "malloc");
      memset (ibitsp, 0, fdsn);
      memset (obitsp, 0, fdsn);
      memset (xbitsp, 0, fdsn);
    }

  if (netout)
    FD_SET (net, obitsp);
  if (ttyout)
    FD_SET (tout, obitsp);
  if (ttyin)
    FD_SET (tin, ibitsp);
  if (netin)
    FD_SET (net, ibitsp);
  if (netex)
    FD_SET (net, xbitsp);

  if ((c = select (maxfd + 1, ibitsp, obitsp, xbitsp,
		   (poll == 0) ? (struct timeval *) 0 : &TimeValue)) < 0)
    {
      if (c == -1)
	{
	  /*
	   * we can get EINTR if we are in line mode,
	   * and the user does an escape (TSTP), or
	   * some other signal generator.
	   */
	  if (errno == EINTR)
	    {
	      return 0;
	    }
#	    if defined(TN3270)
	  /*
	   * we can get EBADF if we were in transparent
	   * mode, and the transcom process died.
	   */
	  if (errno == EBADF)
	    {
	      /*
	       * zero the bits (even though kernel does it)
	       * to make sure we are selecting on the right
	       * ones.
	       */
	      memset (ibitsp, 0, fdsn);
	      memset (obitsp, 0, fdsn);
	      memset (xbitsp, 0, fdsn);
	      return 0;
	    }
#	    endif /* defined(TN3270) */
	  /* I don't like this, does it ever happen? */
	  printf ("sleep(5) from telnet, after select\r\n");
	  sleep (5);
	}
      return 0;
    }

  /*
   * Any urgent data?
   */
  if (FD_ISSET (net, xbitsp))
    {
      FD_CLR (net, xbitsp);
      SYNCHing = 1;
      (void) ttyflush (1);	/* flush already enqueued data */
    }

  /*
   * Something to read from the network...
   */
  if (FD_ISSET (net, ibitsp))
    {
      int canread;

      FD_CLR (net, ibitsp);
      canread = ring_empty_consecutive (&netiring);
#if	!defined(SO_OOBINLINE)
      /*
       * In 4.2 (and some early 4.3) systems, the
       * OOB indication and data handling in the kernel
       * is such that if two separate TCP Urgent requests
       * come in, one byte of TCP data will be overlaid.
       * This is fatal for Telnet, but we try to live
       * with it.
       *
       * In addition, in 4.2 (and...), a special protocol
       * is needed to pick up the TCP Urgent data in
       * the correct sequence.
       *
       * What we do is:  if we think we are in urgent
       * mode, we look to see if we are "at the mark".
       * If we are, we do an OOB receive.  If we run
       * this twice, we will do the OOB receive twice,
       * but the second will fail, since the second
       * time we were "at the mark", but there wasn't
       * any data there (the kernel doesn't reset
       * "at the mark" until we do a normal read).
       * Once we've read the OOB data, we go ahead
       * and do normal reads.
       *
       * There is also another problem, which is that
       * since the OOB byte we read doesn't put us
       * out of OOB state, and since that byte is most
       * likely the TELNET DM (data mark), we would
       * stay in the TELNET SYNCH (SYNCHing) state.
       * So, clocks to the rescue.  If we've "just"
       * received a DM, then we test for the
       * presence of OOB data when the receive OOB
       * fails (and AFTER we did the normal mode read
       * to clear "at the mark").
       */
      if (SYNCHing)
	{
	  int atmark;
	  static int bogus_oob = 0, first = 1;

	  ioctl (net, SIOCATMARK, (char *) &atmark);
	  if (atmark)
	    {
	      c = recv (net, netiring.supply, canread, MSG_OOB);
	      if ((c == -1) && (errno == EINVAL))
		{
		  c = recv (net, netiring.supply, canread, 0);
		  if (clocks.didnetreceive < clocks.gotDM)
		    {
		      SYNCHing = stilloob (net);
		    }
		}
	      else if (first && c > 0)
		{
		  /*
		   * Bogosity check.  Systems based on 4.2BSD
		   * do not return an error if you do a second
		   * recv(MSG_OOB).  So, we do one.  If it
		   * succeeds and returns exactly the same
		   * data, then assume that we are running
		   * on a broken system and set the bogus_oob
		   * flag.  (If the data was different, then
		   * we probably got some valid new data, so
		   * increment the count...)
		   */
		  int i;
		  i = recv (net, netiring.supply + c, canread - c, MSG_OOB);
		  if (i == c &&
		      memcmp (netiring.supply, netiring.supply + c, i) == 0)
		    {
		      bogus_oob = 1;
		      first = 0;
		    }
		  else if (i < 0)
		    {
		      bogus_oob = 0;
		      first = 0;
		    }
		  else
		    c += i;
		}
	      if (bogus_oob && c > 0)
		{
		  int i;
		  /*
		   * Bogosity.  We have to do the read
		   * to clear the atmark to get out of
		   * an infinate loop.
		   */
		  i = read (net, netiring.supply + c, canread - c);
		  if (i > 0)
		    c += i;
		}
	    }
	  else
	    {
	      c = recv (net, netiring.supply, canread, 0);
	    }
	}
      else
	{
	  c = recv (net, netiring.supply, canread, 0);
	}
      settimer (didnetreceive);
#else /* !defined(SO_OOBINLINE) */
      c = recv (net, (char *) netiring.supply, canread, 0);
#endif /* !defined(SO_OOBINLINE) */
      if (c < 0 && errno == EWOULDBLOCK)
	{
	  c = 0;
	}
      else if (c <= 0)
	{
	  return -1;
	}
      if (netdata)
	{
	  Dump ('<', netiring.supply, c);
	}
      if (c)
	ring_supplied (&netiring, c);
      returnValue = 1;
    }

  /*
   * Something to read from the tty...
   */
  if (FD_ISSET (tin, ibitsp))
    {
      FD_CLR (tin, ibitsp);
      c = TerminalRead (ttyiring.supply, ring_empty_consecutive (&ttyiring));
      if (c < 0 && errno == EIO)
	c = 0;
      if (c < 0 && errno == EWOULDBLOCK)
	{
	  c = 0;
	}
      else
	{
	  /* EOF detection for line mode!!!! */
	  if ((c == 0) && MODE_LOCAL_CHARS (globalmode) && isatty (tin))
	    {
	      /* must be an EOF... */
	      *ttyiring.supply = termEofChar;
	      c = 1;
	    }
	  if (c <= 0)
	    {
	      return -1;
	    }
	  if (termdata)
	    {
	      Dump ('<', ttyiring.supply, c);
	    }
	  ring_supplied (&ttyiring, c);
	}
      returnValue = 1;		/* did something useful */
    }

  if (FD_ISSET (net, obitsp))
    {
      FD_CLR (net, obitsp);
      returnValue |= netflush ();
    }
  if (FD_ISSET (tout, obitsp))
    {
      FD_CLR (tout, obitsp);
      returnValue |= (ttyflush (SYNCHing | flushout) > 0);
    }

  return returnValue;
}
int
process_rings(int netin, int netout, int netex, int ttyin, int ttyout,
    int dopoll)		/* If 0, then block until something to do */
{
    struct pollfd set[3];
    int c;
		/* One wants to be a bit careful about setting returnValue
		 * to one, since a one implies we did some useful work,
		 * and therefore probably won't be called to block next
		 * time (TN3270 mode only).
		 */
    int returnValue = 0;

    set[0].fd = net;
    set[0].events = (netout ? POLLOUT : 0) | (netin ? POLLIN : 0) |
	(netex ? POLLPRI : 0);
    set[1].fd = tout;
    set[1].events = ttyout ? POLLOUT : 0;
    set[2].fd = tin;
    set[2].events = ttyin ? POLLIN : 0;

    if ((c = poll(set, 3, dopoll ? 0 : INFTIM)) < 0) {
	if (c == -1) {
		    /*
		     * we can get EINTR if we are in line mode,
		     * and the user does an escape (TSTP), or
		     * some other signal generator.
		     */
	    if (errno == EINTR) {
		return 0;
	    }
#ifdef TN3270
		    /*
		     * we can get EBADF if we were in transparent
		     * mode, and the transcom process died.
		    */
	    if (errno == EBADF)
		return 0;
#endif /* defined(TN3270) */
		    /* I don't like this, does it ever happen? */
	    printf("sleep(5) from telnet, after poll\r\n");
	    sleep(5);
	}
	return 0;
    }

    /*
     * Any urgent data?
     */
    if (set[0].revents & POLLPRI) {
	SYNCHing = 1;
	(void) ttyflush(1);	/* flush already enqueued data */
    }

    /*
     * Something to read from the network...
     */
    if (set[0].revents & POLLIN) {
	int canread;

	canread = ring_empty_consecutive(&netiring);
	c = recv(net, (char *)netiring.supply, canread, 0);
	if (c < 0 && errno == EWOULDBLOCK) {
	    c = 0;
	} else if (c <= 0) {
	    return -1;
	}
	if (netdata) {
	    Dump('<', netiring.supply, c);
	}
	if (c)
	    ring_supplied(&netiring, c);
	returnValue = 1;
    }

    /*
     * Something to read from the tty...
     */
    if (set[2].revents & POLLIN) {
	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
	if (c < 0 && errno == EIO)
	    c = 0;
	if (c < 0 && errno == EWOULDBLOCK) {
	    c = 0;
	} else {
	    if (c < 0) {
		return -1;
	    }
	    if (c == 0) {
		/* must be an EOF... */
		if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
		    *ttyiring.supply = termEofChar;
		    c = 1;
		} else {
		    clienteof = 1;
		    shutdown(net, 1);
		    return 0;
		}
	    }
	    if (termdata) {
		Dump('<', ttyiring.supply, c);
	    }
	    ring_supplied(&ttyiring, c);
	}
	returnValue = 1;		/* did something useful */
    }

    if (set[0].revents & POLLOUT) {
	returnValue |= netflush();
    }

    if (set[1].revents & (POLLHUP|POLLNVAL))
	return(-1);

    if (set[1].revents & POLLOUT) {
	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
    }

    return returnValue;
}