ckutio.c
资源名称:cku197.tar.Z [点击查看]
上传用户:dufan58
上传日期:2007-01-05
资源大小:3407k
文件大小:361k
源码类别:
通讯/手机编程
开发平台:
Windows_Unix
- debug(F101,"in_chk COHERENT select","",n);
- #else
- #ifdef SVR4
- n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
- debug(F101,"in_chk SVR4 select","",n);
- #else
- #ifdef __linux__
- n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
- debug(F101,"in_chk LINUX select","",n);
- #else
- n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv );
- debug(F101,"in_chk catchall select","",n);
- #endif /* __linux__ */
- #endif /* SVR4 */
- #endif /* COHERENT */
- #endif /* QNX */
- #endif /* SOLARIS */
- #endif /* BSD43 */
- #endif /* BSD44 */
- #endif /* BELLV10 */
- #endif /* Plan9 */
- }
- #else /* Not SELECT */
- #ifdef CK_POLL
- {
- struct pollfd pfd;
- pfd.fd = fd;
- pfd.events = POLLIN;
- pfd.revents = 0;
- n = poll(&pfd, 1, 0);
- debug(F101,"in_chk poll","",n);
- if ((n > 0) && (pfd.revents & POLLIN))
- n = 1;
- }
- #endif /* CK_POLL */
- #endif /* SELECT */
- #endif /* RDCHK */
- #endif /* PROVX1 */
- #endif /* V7 */
- #endif /* FIONREAD */
- /* From here down, treat console and communication device differently... */
- if (channel == 0) { /* Console */
- #ifdef SVORPOSIX
- #ifndef FIONREAD
- #ifndef SELECT
- #ifndef CK_POLL
- #ifndef RDCHK
- /*
- This is the hideous hack used in System V and POSIX systems that don't
- support FIONREAD, rdchk(), select(), poll(), etc, in which the user's
- CONNECT-mode escape character is attached to SIGQUIT. Used, obviously,
- only on the console.
- */
- if (conesc) { /* Escape character typed == SIGQUIT */
- debug(F100,"in_chk conesc","",conesc);
- conesc = 0;
- signal(SIGQUIT,esctrp); /* Restore signal */
- n += 1;
- }
- #endif /* RDCHK */
- #endif /* CK_POLL */
- #endif /* SELECT */
- #endif /* FIONREAD */
- #endif /* SVORPOSIX */
- return(n); /* Done with console */
- }
- if (channel != 0) { /* Communications connection */
- #ifdef MYREAD
- #ifndef FIONREAD
- /*
- select() or rdchk(), etc, has told us that something is waiting, but we
- don't know how much. So we do a read to get it and then we know. Note:
- This read is NOT nonblocking if nothing is there (because of VMIN=1), but
- it should be safe in this case since the OS tells us at least one byte is
- waiting to be read, and MYREAD reads return as much as is there without
- waiting for any more. Controlled tests on Solaris and Unixware (with
- FIONREAD deliberately undefined) show this to be true.
- */
- debug(F101,"in_chk read my_count","",my_count);
- debug(F101,"in_chk read n","",n);
- if (n > 0 && my_count == 0) {
- /* This also catches disconnects etc */
- /* Do what mygetbuf does except don't grab a character */
- my_count = myfillbuf();
- my_item = -1; /* ^^^ */
- debug(F101,"in_chk myfillbuf my_count","",my_count);
- if (my_count < 0)
- return(-1);
- else
- n = 0; /* NB: n is replaced by my_count */
- }
- #endif /* FIONREAD */
- /*
- Here we add whatever we think is unread to what is still in our
- our internal buffer. Thus the importance of setting n to 0 just above.
- */
- debug(F101,"in_chk my_count","",my_count);
- debug(F101,"in_chk n","",n);
- if (my_count > 0)
- n += my_count;
- #endif /* MYREAD */
- }
- debug(F101,"in_chk result","",n);
- /* Errors here don't prove the connection has dropped so just say 0 */
- return(n < 0 ? 0 : n);
- }
- /* T T C H K -- Tell how many characters are waiting in tty input buffer */
- int
- ttchk() {
- int fd;
- #ifdef NETCMD
- if (ttpipe)
- fd = fdin;
- else
- #endif /* NETCMD */
- fd = ttyfd;
- return(in_chk(1,fd));
- }
- /* T T X I N -- Get n characters from tty input buffer */
- /* Returns number of characters actually gotten, or -1 on failure */
- /* Intended for use only when it is known that n characters are actually */
- /* Available in the input buffer. */
- int
- ttxin(n,buf) int n; CHAR *buf; {
- register int x = 0, i = 0, c = -2;
- char cc;
- int fd;
- if (n < 1) /* Nothing to do */
- return(0);
- #ifdef TTLEBUF
- if (ttpush >= 0) {
- buf[0] = ttpush; /* Put pushed char in buffer*/
- ttpush = -1; /* Clear the push buffer */
- if (ttchk() > 0)
- return(ttxin(n-1, &buf[1]) + 1);
- else
- return(1);
- }
- if (le_data) {
- while (le_inbuf() > 0) {
- if (le_getchar(&buf[i])) {
- i++;
- n--;
- }
- }
- if (ttchk() > 0)
- return(ttxin(n,&buf[i])+i);
- else
- return(i);
- }
- #endif /* TTLEBUF */
- #ifdef NETCMD
- if (ttpipe)
- fd = fdin;
- else
- #endif /* NETCMD */
- fd = ttyfd;
- #ifdef SUNX25
- if (netconn && (ttnet == NET_SX25)) /* X.25 connection */
- return(x25xin(n,buf));
- #endif /* SUNX25 */
- #ifdef IBMX25
- /* riehm: possibly not needed. Test worked with normal reads and writes */
- if (netconn && (ttnet == NET_IX25)) { /* X.25 connection */
- x = x25xin(n,buf);
- if (x > 0) buf[x] = ' ';
- return(x);
- }
- #endif /* IBMX25 */
- #ifdef MYREAD
- debug(F101,"ttxin MYREAD","",n);
- while (x < n) {
- c = myread();
- if (c < 0) {
- debug(F101,"ttxin myread returns","",c);
- if (c == -3) x = -1;
- break;
- }
- buf[x++] = c & ttpmsk;
- #ifdef RLOGCODE
- #ifdef CK_KERBEROS
- /* It is impossible to know how many characters are waiting */
- /* to be read when you are using Encrypted Rlogin or SSL */
- /* as the transport since the number of real data bytes */
- /* can be greater or less than the number of bytes on the */
- /* wire which is what ttchk() returns. */
- if (netconn && (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN))
- if (ttchk() <= 0)
- break;
- #endif /* CK_KERBEROS */
- #endif /* RLOGCODE */
- #ifdef CK_SSL
- if (ssl_active_flag || tls_active_flag)
- if (ttchk() <= 0)
- break;
- #endif /* CK_SSL */
- }
- #else
- debug(F101,"ttxin READ","",n);
- x = read(fd,buf,n);
- for (c = 0; c < n; c++) /* Strip any parity */
- buf[c] &= ttpmsk;
- #endif /* MYREAD */
- debug(F101,"ttxin x","",x); /* Done */
- if (x > 0) buf[x] = ' ';
- if (x < 0) x = -1;
- return(x);
- }
- /* T T O L -- Write string s, length n, to communication device. */
- /*
- Returns:
- >= 0 on success, number of characters actually written.
- -1 on failure.
- */
- #ifdef CK_ENCRYPTION
- CHAR * xpacket = NULL;
- int nxpacket = 0;
- #endif /* CK_ENCRYPTION */
- #define TTOLMAXT 5
- int
- ttol(s,n) int n; CHAR *s; {
- int x, len, tries, fd;
- #ifdef CKXXCHAR
- extern int dblflag; /* For SET SEND DOUBLE-CHARACTER */
- extern short dblt[];
- CHAR *p = NULL, *p2, *s2, c;
- int n2 = 0;
- #endif /* CKXXCHAR */
- if (ttyfd < 0) /* Not open? */
- return(-3);
- #ifdef DEBUG
- if (deblog) hexdump("ttol s",s,n);
- #endif /* DEBUG */
- #ifdef NETCMD
- if (ttpipe)
- fd = fdout;
- else
- #endif /* NETCMD */
- fd = ttyfd;
- #ifdef CKXXCHAR
- /* Double any characters that must be doubled. */
- debug(F101,"ttol dblflag","",dblflag);
- if (dblflag) {
- p = (CHAR *) malloc(n + n + 1);
- if (p) {
- s2 = s;
- p2 = p;
- n2 = 0;
- while (*s2) {
- c = *s2++;
- *p2++ = c;
- n2++;
- if (dblt[(unsigned) c] & 2) {
- *p2++ = c;
- n2++;
- }
- }
- s = p;
- n = n2;
- s[n] = ' ';
- }
- }
- debug(F111,"ttol doubled",s,n);
- #endif /* CKXXCHAR */
- tries = TTOLMAXT; /* Allow up to this many tries */
- len = n; /* Remember original length */
- #ifdef CK_ENCRYPTION
- /*
- This is to avoid encrypting a packet that is already encrypted, e.g.
- when we resend a packet directly out of the packet buffer, and also to
- avoid encrypting a constant (literal) string, which can cause a memory
- fault.
- */
- if (TELOPT_ME(TELOPT_ENCRYPTION)) {
- int x;
- if (nxpacket < n) {
- if (xpacket) {
- free(xpacket);
- xpacket = NULL;
- nxpacket = 0;
- }
- x = n > 10240 ? n : 10240;
- xpacket = (CHAR *)malloc(x);
- if (!xpacket) {
- fprintf(stderr,"ttol malloc failuren");
- return(-1);
- } else
- nxpacket = x;
- }
- memcpy((char *)xpacket,(char *)s,n);
- s = xpacket;
- ck_tn_encrypt((char *)s,n);
- }
- #endif /* CK_ENCRYPTION */
- while (n > 0 &&
- (tries-- > 0
- #ifdef CK_ENCRYPTION
- /* keep trying if we are encrypting */
- || TELOPT_ME(TELOPT_ENCRYPTION)
- #endif /* CK_ENCRYPTION */
- )) { /* Be persistent */
- debug(F101,"ttol try","",TTOLMAXT - tries);
- #ifdef BEOSORBEBOX
- if (netconn && !ttpipe && !ttpty)
- x = nettol(s,n); /* Write string to device */
- else
- #endif /* BEOSORBEBOX */
- #ifdef IBMX25
- if (ttnet == NET_IX25)
- /*
- * this is a more controlled way of writing to X25
- * STREAMS, however write should also work!
- */
- x = x25write(ttyfd, s, n);
- else
- #endif /* IBMX25 */
- #ifdef CK_SSL
- if (ssl_active_flag || tls_active_flag) {
- int error;
- /* Write using SSL */
- if (ssl_active_flag)
- x = SSL_write(ssl_con, s, n);
- else
- x = SSL_write(tls_con, s, n);
- switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
- case SSL_ERROR_NONE:
- break;
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_READ:
- x = 0;
- break;
- case SSL_ERROR_SYSCALL:
- case SSL_ERROR_WANT_X509_LOOKUP:
- case SSL_ERROR_SSL:
- case SSL_ERROR_ZERO_RETURN:
- default:
- ttclos(0);
- return(-3);
- }
- } else
- #endif /* CK_SSL */
- #ifdef RLOGCODE
- #ifdef CK_KERBEROS
- #ifdef KRB4
- if (ttnproto == NP_EK4LOGIN) {
- return(krb4_des_write(ttyfd,s,n));
- } else
- #endif /* KRB4 */
- #ifdef KRB5
- if (ttnproto == NP_EK5LOGIN) {
- return(krb5_des_write(ttyfd,s,n));
- } else
- #endif /* KRB5 */
- #endif /* CK_KERBEROS */
- #endif /* RLOGCODE */
- x = write(fd,s,n); /* Write string to device */
- if (x == n) { /* Worked? */
- debug(F101,"ttol ok","",x); /* OK */
- #ifdef CKXXCHAR
- if (p) free(p);
- #endif /* CKXXCHAR */
- return(len); /* Done */
- } else if (x < 0) { /* No, got error? */
- debug(F101,"ttol write error","",errno);
- #ifdef EWOULDBLOCK
- if (errno == EWOULDBLOCK) {
- msleep(10);
- continue;
- } else
- #endif /* EWOULDBLOCK */
- #ifdef TCPSOCKET
- if (netconn && ttnet == NET_TCPB) {
- debug(F101,"ttol TCP error","",errno);
- ttclos(0); /* Close the connection. */
- x = -3;
- }
- #endif /* TCPSOCKET */
- #ifdef CKXXCHAR
- if (p) free(p);
- #endif /* CKXXCHAR */
- return(x);
- } else { /* No error, so partial success */
- debug(F101,"ttol partial","",x); /* This never happens */
- s += x; /* Point to part not written yet */
- n -= x; /* Adjust length */
- if (x > 0) msleep(10); /* Wait 10 msec */
- } /* Go back and try again */
- }
- #ifdef CKXXCHAR
- if (p) free(p);
- #endif /* CKXXCHAR */
- return(n < 1 ? len : -1); /* Return the results */
- }
- /* T T O C -- Output a character to the communication line */
- /*
- This function should only be used for interactive, character-mode operations,
- like terminal connection, script execution, dialer i/o, where the overhead
- of the signals and alarms does not create a bottleneck.
- */
- int
- #ifdef CK_ANSIC
- ttoc(char c)
- #else
- ttoc(c) char c;
- #endif /* CK_ANSIC */
- /* ttoc */ {
- #define TTOC_TMO 15 /* Timeout in case we get stuck */
- int xx, fd;
- if (ttyfd < 0) /* Check for not open. */
- return(-1);
- #ifdef NETCMD
- if (ttpipe)
- fd = fdout;
- else
- #endif /* NETCMD */
- fd = ttyfd;
- c &= 0xff;
- /* debug(F101,"ttoc","",(CHAR) c); */
- saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
- xx = alarm(TTOC_TMO); /* for this many seconds. */
- if (xx < 0) xx = 0; /* Save old alarm value. */
- /* debug(F101,"ttoc alarm","",xx); */
- if (
- #ifdef CK_POSIX_SIG
- sigsetjmp(sjbuf,1)
- #else
- setjmp(sjbuf)
- #endif /* CK_POSIX_SIG */
- ) { /* Timer went off? */
- ttimoff(); /* Yes, cancel this alarm. */
- if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
- /* debug(F100,"ttoc timeout","",0); */
- #ifdef NETCONN
- if (!netconn) {
- #endif /* NETCONN */
- debug(F101,"ttoc timeout","",c);
- if (ttflow == FLO_XONX) {
- debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */
- #ifndef Plan9
- #ifdef POSIX
- /* POSIX way to unstick. */
- debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON));
- #else
- #ifdef BSD4 /* Berkeley way to do it. */
- #ifdef TIOCSTART
- /* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);". Who knows? */
- {
- int x = 0;
- debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x));
- }
- #endif /* TIOCSTART */
- #endif /* BSD4 */
- /* Is there a Sys V way to do this? */
- #endif /* POSIX */
- #endif /* Plan9 */
- }
- #ifdef NETCONN
- }
- #endif /* NETCONN */
- return(-1); /* Return failure code. */
- } else {
- int rc;
- #ifdef BEOSORBEBOX
- #ifdef NETCONN
- if (netconn && !ttpipe && !ttpty)
- rc = nettoc(c);
- else
- #endif /* BEOSORBEBOX */
- #endif /* NETCONN */
- #ifdef CK_ENCRYPTION
- if (TELOPT_ME(TELOPT_ENCRYPTION))
- ck_tn_encrypt(&c,1);
- #endif /* CK_ENCRYPTION */
- #ifdef IBMX25
- /* riehm: maybe this isn't necessary after all. Test program
- * worked fine with data being sent and retrieved with normal
- * read's and writes!
- */
- if (ttnet == NET_IX25)
- rc = x25write(ttyfd,&c,1); /* as above for X25 streams */
- else
- #endif /* IBMX25 */
- #ifdef CK_SSL
- if (ssl_active_flag || tls_active_flag) {
- int error;
- /* Write using SSL */
- if (ssl_active_flag)
- rc = SSL_write(ssl_con, &c, 1);
- else
- rc = SSL_write(tls_con, &c, 1);
- switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,rc)){
- case SSL_ERROR_NONE:
- break;
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_READ:
- rc = 0;
- break;
- case SSL_ERROR_SYSCALL:
- case SSL_ERROR_WANT_X509_LOOKUP:
- case SSL_ERROR_SSL:
- case SSL_ERROR_ZERO_RETURN:
- default:
- ttclos(0);
- return(-1);
- }
- } else
- #endif /* CK_SSL */
- #ifdef RLOGCODE
- #ifdef CK_KERBEROS
- #ifdef KRB4
- if (ttnproto == NP_EK4LOGIN) {
- rc = (krb4_des_write(ttyfd,&c,1) == 1);
- } else
- #endif /* KRB4 */
- #ifdef KRB5
- if (ttnproto == NP_EK5LOGIN) {
- rc = (krb5_des_write(ttyfd,&c,1) == 1);
- } else
- #endif /* KRB5 */
- #endif /* CK_KERBEROS */
- #endif /* RLOGCODE */
- rc = write(fd,&c,1); /* Try to write the character. */
- if (rc < 1) { /* Failed */
- ttimoff(); /* Turn off the alarm. */
- alarm(xx); /* Restore previous alarm. */
- debug(F101,"ttoc errno","",errno); /* Log the error, */
- return(-1); /* and return the error code. */
- }
- }
- ttimoff(); /* Success, turn off the alarm. */
- alarm(xx); /* Restore previous alarm. */
- return(0); /* Return good code. */
- }
- /* T T I N L -- Read a record (up to break character) from comm line. */
- /*
- Reads up to "max" characters from the communication line, terminating on:
- (a) the packet length field if the "turn" argument is zero, or
- (b) on the packet-end character (eol) if the "turn" argument is nonzero
- (c) a certain number of Ctrl-C's in a row
- Returns:
- >= 0, the number of characters read upon success;
- -1 if "max" exceeded, timeout, or other correctable error;
- -2 on user interruption (c);
- -3 on fatal error like connection lost.
- The characters that were input are copied into "dest" with their parity bits
- stripped if parity was selected. Returns the number of characters read.
- Characters after the eol are available upon the next call to this function.
- The idea is to minimize the number of system calls per packet, and also to
- minimize timeouts. This function is the inner loop of the protocol and must
- be as efficient as possible. The current strategy is to use myread().
- WARNING: This function calls parchk(), which is defined in another module.
- Normally, ckutio.c does not depend on code from any other module, but there
- is an exception in this case because all the other ck?tio.c modules also
- need to call parchk(), so it's better to have it defined in a common place.
- */
- #ifdef CTRLC
- #undef CTRLC
- #endif /* CTRLC */
- #define CTRLC ' 3'
- /*
- We have four different declarations here because:
- (a) to allow Kermit to be built without the automatic parity sensing feature
- (b) one of each type for ANSI C, one for non-ANSI.
- */
- static int csave = -1;
- #ifndef NOXFER
- int
- #ifdef PARSENSE
- #ifdef CK_ANSIC
- ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
- #else
- ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
- #endif /* CK_ANSIC */
- #else /* not PARSENSE */
- #ifdef CK_ANSIC
- ttinl(CHAR *dest, int max,int timo, CHAR eol)
- #else
- ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
- #endif /* __SDTC__ */
- #endif /* PARSENSE */
- /* ttinl */ {
- #ifndef MYREAD
- CHAR ch, dum;
- #endif /* MYREAD */
- #ifdef PARSENSE
- int pktlen = -1;
- int lplen = 0;
- int havelen = 0;
- #endif /* PARSENSE */
- int cc = 0; /* Character count */
- int fd;
- int sopmask = 0xff; /* Start-Of-Packet mask */
- #ifdef CKXXCHAR
- extern short dblt[]; /* Ignore-character table */
- extern int ignflag;
- #endif /* CKXXCHAR */
- #ifdef TCPSOCKET
- extern CHAR stchr;
- #endif /* TCPSOCKET */
- int x;
- if (ttyfd < 0) return(-3); /* Not open. */
- debug(F101,"ttinl max","",max);
- debug(F101,"ttinl timo","",timo);
- #ifdef NETCMD
- if (ttpipe)
- fd = fdin;
- else
- #endif /* NETCMD */
- fd = ttyfd;
- #ifdef COMMENT
- if (xlocal && conchk() > 0) /* Allow for console interruptions */
- return(-1);
- #endif /* COMMENT */
- *dest = ' '; /* Clear destination buffer */
- if (timo < 0) timo = 0; /* Safety */
- if (timo) { /* Don't time out if timo == 0 */
- int xx;
- saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
- xx = alarm(timo); /* Set it. */
- debug(F101,"ttinl alarm","",xx);
- }
- if (
- #ifdef CK_POSIX_SIG
- sigsetjmp(sjbuf,1)
- #else
- setjmp(sjbuf)
- #endif /* CK_POSIX_SIG */
- ) { /* Timer went off? */
- debug(F100,"ttinl timout","",0); /* Get here on timeout. */
- /* debug(F110," with",(char *) dest,0); */
- ttimoff(); /* Turn off timer */
- return(-1); /* and return error code. */
- } else {
- register int i, n; /* local variables */
- int ccn = 0;
- #ifdef PARSENSE
- register int flag = 0;
- debug(F000,"ttinl start","",start);
- #endif /* PARSENSE */
- ttpmsk = ttprty ? 0177 : 0377; /* Set parity stripping mask. */
- sopmask = needpchk ? 0177 : ttpmsk; /* And SOP matching mask. */
- /* Now read into destination, stripping parity and looking for the */
- /* the packet terminator, and also for several Ctrl-C's typed in a row. */
- i = 0; /* Destination index */
- debug(F101,"ttinl eol","",eol);
- while (i < max-1) {
- #ifdef MYREAD
- /* debug(F101,"ttinl i","",i); */
- errno = 0;
- if (csave > -1) {
- n = csave;
- debug(F101,"ttinl unsaving","",n);
- } else
- #ifdef COMMENT
- if (xlocal && conchk() > 0) {
- /* Here we could catch keyboard interruptions. */
- /* But this would be VERY expensive. */
- /* We could also do it in myread() but it would be */
- /* expensive there too -- even if done with select()... */
- }
- #endif /* COMMENT */
- if ((n = myread()) < 0) { /* Timeout or i/o error? */
- #ifdef DEBUG
- if (deblog) {
- debug(F101,"ttinl myread failure, n","",n);
- debug(F101,"ttinl myread errno","",errno);
- }
- #endif /* DEBUG */
- /* Don't let EINTR break packets. */
- if (n == -3) {
- if (errno == EINTR && i > 0) {
- debug(F111,"ttinl EINTR myread i","continuing",i);
- continue;
- } else {
- debug(F110,"ttinl non-EINTR -3","closing",0);
- wasclosed = 1;
- ttimoff(); /* Turn off timer */
- ttclos(0);
- return(n);
- }
- } else if (n == -2 && netconn /* && timo == 0 */ ) {
- /* Here we try to catch broken network connections */
- /* even when ioctl() and read() do not catch them */
- debug(F111,"ttinl network myread failure","closing",n);
- wasclosed = 1;
- ttimoff();
- ttclos(0);
- return(-3);
- }
- break; /* Break out of while loop */
- }
- #else /* not MYREAD (is this code used anywhere any more?) */
- if (csave > -1) /* Char saved from last time */
- ch = csave;
- else if ((n = read(fd, &ch, 1)) < 1)
- break; /* Error - break out of while loop */
- n = ch;
- #endif /* MYREAD */
- /* Get here with char in n */
- #ifdef CK_ENCRYPTION
- /* If csave > -1 we already decrypted this character */
- /* So don't decrypt it again */
- if (TELOPT_U(TELOPT_ENCRYPTION) && csave == -1) {
- CHAR ch = n;
- ck_tn_decrypt(&ch,1);
- n = ch;
- }
- #endif /* CK_ENCRYPTION */
- csave = -1; /* Unflag that we unsaved a char */
- #ifdef TCPSOCKET
- if (n == IAC && /* Handle Telnet options */
- ((xlocal && netconn && (ttnproto == NP_TELNET)) ||
- (!xlocal && sstelnet))) {
- n = tt_tnopt(n);
- if (n < 0)
- return(n);
- else if (n == 1)
- start = stchr;
- if (n != 255) /* No data - go back for next char */
- continue;
- } /* Quoted IAC - keep going */
- #endif /* TCPSOCKET */
- #ifdef CKXXCHAR
- if (ignflag)
- if (dblt[(unsigned) n] & 1) /* Character to ignore? */
- continue;
- #endif /* CKXXCHAR */
- /*
- Use parity mask, rather than always stripping parity, to check for
- cancellation. Otherwise, runs like x03x83x03 in a packet could cancel
- the transfer when parity is NONE. (Note that x03x03x03 is extremely
- unlikely due to run-length encoding.)
- */
- /* Check cancellation */
- if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
- if (++ccn >= xfrnum) { /* If xfrnum in a row, bail out. */
- if (timo) { /* Clear timer. */
- ttimoff();
- }
- if (xfrchr < 32)
- printf("^%c...rn",(char)(xfrchr+64));
- else
- printf("Canceled...rn");
- return(-2);
- }
- } else ccn = 0; /* No cancellation, reset counter, */
- #ifdef PARSENSE
- if (flag == 0) { /* Find the Start-Of-Packet. */
- if ((n & sopmask) == start) { /* Got it */
- flag = 1;
- } else { /* Keep looking... */
- debug(F000,"ttinl skipping","",n);
- continue;
- }
- }
- dest[i++] = n & ttpmsk;
- /*
- If we have not been instructed to wait for a turnaround character, we
- can go by the packet length field. If turn != 0, we must wait for the
- end of line (eol) character before returning. This is an egregious
- violation of all principles of layering...
- */
- if (!havelen) {
- if (i == 2) {
- pktlen = xunchar(dest[1] & 0x7f);
- if (pktlen > 1) {
- havelen = 1;
- debug(F101,"ttinl length","",pktlen);
- }
- } else if (i == 5 && pktlen == 0) {
- lplen = xunchar(dest[4] & 0x7f);
- } else if (i == 6 && pktlen == 0) {
- pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
- havelen = 1;
- debug(F101,"ttinl extended length","",pktlen);
- }
- }
- /*
- Suppose we looked at the sequence number here and found it was out of
- range? This would mean either (a) incoming packets had SOP unprefixed
- and we are out of sync, or (b) the packet is damaged. Since (a) is bad
- practice, let's ignore it. So what should we do here if we know the
- packet is damaged?
- 1. Nothing -- keep trying to read the packet till we find what we think
- is the end, or we time out, and let the upper layer decide what to
- do. But since either the packet is corrupt or we are out of sync,
- our criterion for finding the end does not apply and we are likely
- to time out (or swallow a piece of the next packet) if our assumed
- length is too long. (This was the behavior prior to version 7.0.)
- 2. set flag = 0 and continue? This would force us to wait for the
- next packet to come in, and therefore (in the nonwindowing case),
- would force a timeout in the other Kermit.
- 3. set flag = 0 and continue, but only if the window size is > 1 and
- the window is not blocked? Talk about cheating!
- 4. Return a failure code and let the upper layer decide what to do.
- This should be equivalent to 3, but without the cheating. So let's
- do it that way...
- */
- if (i == 3) { /* Peek at sequence number */
- x = xunchar(dest[i-1]); /* If it's not in range... */
- if (x < 0 || x > 63) {
- debug(F111,"ttinl bad seq",dest,x);
- if (timo) ttimoff();
- return(-1); /* return a nonfatal error */
- }
- }
- #else /* PARSENSE */
- dest[i++] = n & ttpmsk;
- #endif /* PARSENSE */
- /* Check for end of packet */
- if (
- #ifdef PARSENSE
- /*
- Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
- This allows packet terminators and handshake characters to appear
- literally inside a packet data field.
- */
- (havelen && (i > pktlen+1) &&
- (!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */
- #else /* !PARSENSE */
- /*
- Built without PARSENSE, so just look for packet terminator.
- */
- ((n & 0x7f) == eol)
- #endif /* PARSENSE */
- ) {
- #ifndef PARSENSE
- debug(F101,"ttinl got eol","",eol); /* (or turn) */
- dest[i] = ' '; /* Yes, terminate the string, */
- /* debug(F101,"ttinl i","",i); */
- #else
- #ifdef DEBUG
- if (deblog) {
- if ((n & 0x7f) != eol) {
- debug(F101,"ttinl EOP length","",pktlen);
- debug(F101,"ttinl i","",i);
- #ifdef MYREAD
- #ifdef PARSENSE
- /*
- We read a packet based on its length. This leaves the EOP character still
- unread, and so ttchk() will always return at least 1 because of this. But
- if we know it is there, we can safely get rid of it. So...
- */
- {
- int x;
- while (my_count > 0) {
- x = ttinc(0);
- /* Start of next packet */
- if (x == start) { /* Save for next time */
- csave = (unsigned)((unsigned)x & 0xff);
- debug(F000,"ttinl csaved","",x);
- break;
- }
- debug(F000,"ttinl removed","",x);
- }
- }
- #endif /* PARSENSE */
- #endif /* MYREAD */
- } else debug(F101,"ttinl got eol","",eol); /* (or turn) */
- }
- #endif /* DEBUG */
- dest[i] = ' '; /* Terminate the string, */
- if (needpchk) { /* Parity checked yet? */
- if (ttprty == 0) { /* No, check. */
- if ((ttprty = parchk(dest,start,i)) > 0) {
- int j;
- debug(F101,"ttinl senses parity","",ttprty);
- debug(F110,"ttinl packet before",dest,0);
- ttpmsk = 0x7f;
- for (j = 0; j < i; j++)
- dest[j] &= 0x7f; /* Strip parity from packet */
- debug(F110,"ttinl packet after ",dest,0);
- } else ttprty = 0; /* Restore if parchk error */
- }
- sopmask = ttprty;
- needpchk = 0;
- }
- #endif /* PARSENSE */
- if (timo) { /* Turn off timer. */
- ttimoff();
- }
- debug(F011,"ttinl got", dest, (i < 60) ? i : -60);
- return(i);
- }
- } /* End of while() */
- ttimoff();
- return(n);
- }
- }
- #endif /* NOXFER */
- /* T T I N C -- Read a character from the communication line */
- /*
- On success, returns the character that was read, >= 0.
- On failure, returns -1 or other negative myread error code,
- or -2 if connection is broken or ttyfd < 0.
- or -3 if session limit has expired,
- or -4 if something or other...
- NOTE: The API does not provide for ttinc() returning a special code
- upon timeout, but we need it. So for this we have a global variable,
- ttinctimo.
- */
- static int ttinctimo = 0; /* Yuk */
- int
- ttinc(timo) int timo; {
- int n = 0, fd;
- int is_tn = 0;
- CHAR ch = 0;
- ttinctimo = 0;
- if (ttyfd < 0) return(-2); /* Not open. */
- is_tn = (xlocal && netconn && ttnproto == NP_TELNET) ||
- (!xlocal && sstelnet);
- #ifdef TTLEBUF
- if (ttpush >= 0) {
- debug(F111,"ttinc","ttpush",ttpush);
- ch = ttpush;
- ttpush = -1;
- return(ch);
- }
- if (le_data) {
- if (le_getchar(&ch) > 0) {
- debug(F111,"ttinc le_getchar","ch",ch);
- return(ch);
- }
- }
- #endif /* TTLEBUF */
- #ifdef NETCMD
- if (ttpipe)
- fd = fdin;
- else
- #endif /* NETCMD */
- fd = ttyfd;
- if ((timo <= 0) /* Untimed. */
- #ifdef MYREAD
- || (my_count > 0) /* Buffered char already waiting. */
- #endif /* MYREAD */
- ) {
- #ifdef MYREAD
- /* Comm line failure returns -1 thru myread, so no &= 0377 */
- n = myread(); /* Wait for a character... */
- /* debug(F000,"ttinc MYREAD n","",n); */
- #ifdef CK_ENCRYPTION
- /* debug(F101,"ttinc u_encrypt","",TELOPT_U(TELOPT_ENCRYPTION)); */
- if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
- ch = n;
- ck_tn_decrypt(&ch,1);
- n = ch;
- }
- #endif /* CK_ENCRYPTION */
- #ifdef NETPTY
- if (ttpty && n < 0) {
- debug(F101,"ttinc error on pty","",n);
- ttclos(0);
- return(n);
- }
- #endif /* NETPTY */
- #ifdef TNCODE
- if ((n > -1) && is_tn)
- return((unsigned)(n & 0xff));
- else
- #endif /* TNCODE */
- return(n < 0 ? n : (unsigned)(n & ttpmsk));
- #else /* MYREAD */
- while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */
- /* Shouldn't have to loop in ver 5A. */
- #ifdef NETCONN
- if (netconn) { /* Special handling for net */
- netclos(); /* If read() returns 0 it means */
- netconn = 0; /* the connection has dropped. */
- errno = ENOTCONN;
- return(-2);
- }
- #endif /* NETCONN */
- ;
- /* debug(F101,"ttinc","",ch); */
- #ifdef TNCODE
- if ((n > 0) && is_tn) {
- #ifdef CK_ENCRYPTION
- if (TELOPT_U(TELOPT_ENCRYPTION)) {
- ck_tn_decrypt(&ch,1);
- n = ch;
- }
- #endif /* CK_ENCRYPTION */
- return((unsigned)(ch & 0xff));
- } else
- #endif /* TNCODE */
- return((n < 0) ? -4 : ((n == 0) ? -1 : (unsigned)(ch & ttpmsk)));
- #endif /* MYREAD */
- } else { /* Timed read */
- int oldalarm;
- saval = signal(SIGALRM,timerh); /* Set up handler, save old one. */
- oldalarm = alarm(timo); /* Set alarm, save old one. */
- if (
- #ifdef CK_POSIX_SIG
- sigsetjmp(sjbuf,1)
- #else
- setjmp(sjbuf)
- #endif /* CK_POSIX_SIG */
- ) { /* Timer expired */
- ttinctimo = 1;
- n = -1; /* set flag */
- } else {
- #ifdef MYREAD
- n = myread(); /* If managing own buffer... */
- debug(F101,"ttinc myread","",n);
- ch = n;
- #else
- n = read(fd,&ch,1); /* Otherwise call the system. */
- if (n == 0) n = -1;
- debug(F101,"ttinc read","",n);
- #endif /* MYREAD */
- #ifdef CK_ENCRYPTION
- if (TELOPT_U(TELOPT_ENCRYPTION) && n >= 0) {
- ck_tn_decrypt(&ch,1);
- }
- #endif /* CK_ENCRYPTION */
- if (n >= 0)
- n = (unsigned) (ch & 0xff);
- else
- n = (n < 0) ? -4 : -2; /* Special return codes. */
- }
- ttimoff(); /* Turn off the timer */
- if (oldalarm > 0) {
- if (n == -1) /* and restore any previous alarm */
- oldalarm -= timo;
- if (oldalarm < 0) /* adjusted by our timeout interval */
- oldalarm = 0;
- if (oldalarm) {
- debug(F101,"ttinc restoring oldalarm","",oldalarm);
- alarm(oldalarm);
- }
- }
- #ifdef NETCONN
- if (netconn) {
- if (n == -2) { /* read() returns 0 */
- netclos(); /* on network read failure */
- netconn = 0;
- errno = ENOTCONN;
- }
- }
- #endif /* NETCONN */
- #ifdef TNCODE
- if ((n > -1) && is_tn)
- return((unsigned)(n & 0xff));
- else
- #endif /* TNCODE */
- /* Return masked char or neg. */
- return( (n < 0) ? n : (unsigned)(n & ttpmsk) );
- }
- }
- /* S N D B R K -- Send a BREAK signal of the given duration */
- static int
- #ifdef CK_ANSIC
- sndbrk(int msec) { /* Argument is milliseconds */
- #else
- sndbrk(msec) int msec; {
- #endif /* CK_ANSIC */
- #ifndef POSIX
- int x, n;
- #endif /* POSIX */
- #ifdef OXOS
- #define BSDBREAK
- #endif /* OXOS */
- #ifdef ANYBSD
- #define BSDBREAK
- #endif /* ANYBSD */
- #ifdef BSD44
- #define BSDBREAK
- #endif /* BSD44 */
- #ifdef COHERENT
- #ifdef BSDBREAK
- #undef BSDBREAK
- #endif /* BSDBREAK */
- #endif /* COHERENT */
- #ifdef BELLV10
- #ifdef BSDBREAK
- #undef BSDBREAK
- #endif /* BSDBREAK */
- #endif /* BELLV10 */
- #ifdef PROVX1
- char spd;
- #endif /* PROVX1 */
- debug(F101,"ttsndb ttyfd","",ttyfd);
- if (ttyfd < 0) return(-1); /* Not open. */
- #ifdef Plan9
- return p9sndbrk(msec);
- #else
- #ifdef NETCONN
- #ifdef NETCMD
- if (ttpipe) /* Pipe */
- return(ttoc(' '));
- #endif /* NETCMD */
- #ifdef NETPTY
- if (ttpty)
- return(ttoc(' '));
- #endif /* NETPTY */
- if (netconn) /* Send network BREAK */
- return(netbreak());
- #endif /* NETCONN */
- if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
- #ifdef POSIX /* Easy in POSIX */
- debug(F101,"sndbrk POSIX","",msec);
- return(tcsendbreak(ttyfd,msec / 375));
- #else
- #ifdef PROVX1
- gtty(ttyfd,&ttbuf); /* Get current tty flags */
- spd = ttbuf.sg_ospeed; /* Save speed */
- ttbuf.sg_ospeed = B50; /* Change to 50 baud */
- stty(ttyfd,&ttbuf); /* ... */
- n = (int)strlen(brnuls); /* Send the right number of nulls */
- x = msec / 91;
- if (x > n) x = n;
- write(ttyfd,brnuls,n);
- ttbuf.sg_ospeed = spd; /* Restore speed */
- stty(ttyfd,&ttbuf); /* ... */
- return(0);
- #else
- #ifdef aegis
- sio_$control((short)ttyfd, sio_$send_break, msec, st);
- return(0);
- #else
- #ifdef BSDBREAK
- n = FWRITE; /* Flush output queue. */
- /* Watch out for int vs long problems in &n arg! */
- debug(F101,"sndbrk BSDBREAK","",msec);
- ioctl(ttyfd,TIOCFLUSH,&n); /* Ignore any errors.. */
- if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) { /* Turn on BREAK */
- perror("Can't send BREAK");
- return(-1);
- }
- x = msleep(msec); /* Sleep for so many milliseconds */
- if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) { /* Turn off BREAK */
- perror("BREAK stuck!!!");
- doexit(BAD_EXIT,-1); /* Get out, closing the line. */
- /* with bad exit status */
- }
- return(x);
- #else
- #ifdef ATTSV
- /*
- No way to send a long BREAK in Sys V, so send a bunch of regular ones.
- (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
- but there's no way for this code to know for sure.)
- */
- debug(F101,"sndbrk ATTSV","",msec);
- x = msec / 275;
- for (n = 0; n < x; n++) {
- /* Reportedly the cast breaks this function on some systems */
- /* But then why was it here in the first place? */
- if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) {
- perror("Can't send BREAK");
- return(-1);
- }
- }
- return(0);
- #else
- #ifdef V7
- debug(F101,"sndbrk V7","",msec);
- return(genbrk(ttyfd,250)); /* Simulate a BREAK */
- #else
- debug(F101,"sndbrk catchall","",msec);
- ttoc(0);ttoc(0);ttoc(0);ttoc(0);
- return(0);
- #endif /* V7 */
- #endif /* BSDBREAK */
- #endif /* ATTSV */
- #endif /* aegis */
- #endif /* PROVX1 */
- #endif /* POSIX */
- #endif /* Plan9 */
- }
- /* T T S N D B -- Send a BREAK signal */
- int
- ttsndb() {
- return(sndbrk(275));
- }
- /* T T S N D L B -- Send a Long BREAK signal */
- int
- ttsndlb() {
- return(sndbrk(1500));
- }
- /* M S L E E P -- Millisecond version of sleep(). */
- /*
- Call with number of milliseconds (thousandths of seconds) to sleep.
- Intended only for small intervals. For big ones, just use sleep().
- Highly system-dependent.
- Returns 0 always, even if it didn't work.
- */
- /* Define MSLFTIME for systems that must use an ftime() loop. */
- #ifdef ANYBSD /* For pre-4.2 BSD versions */
- #ifndef BSD4
- #define MSLFTIME
- #endif /* BSD4 */
- #endif /* ANYBSD */
- #ifdef TOWER1 /* NCR Tower OS 1.0 */
- #define MSLFTIME
- #endif /* TOWER1 */
- #ifdef COHERENT /* Coherent... */
- #ifndef _I386 /* Maybe Coherent/386 should get this, too */
- #define MSLFTIME /* Opinions are divided */
- #endif /* _I386 */
- #endif /* COHERENT */
- #ifdef COMMENT
- #ifdef GETMSEC
- /* Millisecond timer */
- static long msecbase = 0L; /* Unsigned long not portable */
- long
- getmsec() { /* Milliseconds since base time */
- struct timeval xv;
- struct timezone xz;
- long secs, msecs;
- if (
- #ifdef GTODONEARG
- gettimeofday(&tv)
- #else
- #ifdef PTX
- gettimeofday(&tv, NULL)
- #else
- gettimeofday(&tv, &tz)
- #endif /* PTX */
- #endif /* GTODONEARG */
- < 0)
- return(-1);
- if (msecbase == 0L) { /* First call, set base time. */
- msecbase = tv.tv_sec;
- debug(F101,"getmsec base","",msecbase);
- }
- return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L));
- }
- #endif /* GETMSEC */
- #endif /* COMMENT */
- #ifdef SELECT
- int
- ttwait(fd, secs) int fd, secs; {
- int x;
- fd_set rfds;
- FD_ZERO(&rfds);
- FD_SET(fd,&rfds);
- tv.tv_sec = secs;
- tv.tv_usec = 0L;
- errno = 0;
- if ((x = select(FD_SETSIZE,
- #ifdef HPUX9
- (int *)
- #else
- #ifdef HPUX1000
- (int *)
- #endif /* HPUX1000 */
- #endif /* HPUX9 */
- &rfds,
- 0, 0, &tv)) < 0) {
- debug(F101,"ttwait select errno","",errno);
- return(0);
- } else {
- debug(F101,"ttwait OK","",errno);
- x = FD_ISSET(fd, &rfds);
- debug(F101,"ttwait select x","",x);
- return(x ? 1 : 0);
- }
- }
- #endif /* SELECT */
- int
- msleep(m) int m; {
- /*
- Other possibilities here are:
- nanosleep(), reportedly defined in POSIX.4.
- sginap(), IRIX only (back to what IRIX version I don't know).
- */
- #ifdef Plan9
- return _SLEEP(m);
- #else
- #ifdef BEOSORBEBOX
- snooze(m*1000);
- #else /* BEOSORBEBOX */
- #ifdef SELECT
- int t1, x;
- debug(F101,"msleep SELECT 1","",m);
- if (m <= 0) return(0);
- if (m >= 1000) { /* Catch big arguments. */
- sleep(m/1000);
- m = m % 1000;
- if (m < 10) return(0);
- }
- debug(F101,"msleep SELECT 2","",m);
- #ifdef BELLV10
- x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m );
- debug(F101,"msleep BELLV10 select","",x);
- #else /* BELLV10 */
- #ifdef HPUX9
- gettimeofday(&tv, &tz);
- #else
- #ifndef COHERENT
- #ifdef GTODONEARG
- if (gettimeofday(&tv) < 0)
- #else
- #ifdef PTX
- if (gettimeofday(&tv,NULL) < 0)
- #else
- if (gettimeofday(&tv, &tz) < 0)
- #endif /* PTX */
- #endif /* GTODONEARG */
- return(-1);
- t1 = tv.tv_sec; /* Seconds */
- #endif /* COHERENT */
- #endif /* HPUX9 */
- tv.tv_sec = 0; /* Use select() */
- tv.tv_usec = m * 1000L;
- #ifdef BSD44
- x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
- debug(F101,"msleep BSD44 select","",x);
- #else /* BSD44 */
- #ifdef __linux__
- x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
- debug(F101,"msleep __linux__ select","",x);
- #else /* __linux__ */
- #ifdef BSD43
- x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
- debug(F101,"msleep BSD43 select","",x);
- #else /* BSD43 */
- #ifdef QNX
- x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
- debug(F101,"msleep QNX select","",x);
- #else /* QNX */
- #ifdef COHERENT
- x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
- debug(F101,"msleep COHERENT select","",x);
- #else /* COHERENT */
- #ifdef HPUX1000 /* 10.00 only, not 10.10 or later */
- x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
- debug(F101,"msleep HP-UX 10.00 select","",x);
- #else /* HPUX1000 */
- #ifdef SVR4
- x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
- debug(F101,"msleep SVR4 select","",x);
- #else /* SVR4 */
- #ifdef OSF40
- x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
- debug(F101,"msleep OSF40 select","",x);
- #else /* OSF40 */
- #ifdef PTX
- x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
- debug(F101,"msleep OSF40 select","",x);
- #else
- x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
- debug(F101,"msleep catch-all select","",x);
- #endif /* PTX */
- #endif /* OSF40 */
- #endif /* HP1000 */
- #endif /* SVR4 */
- #endif /* COHERENT */
- #endif /* QNX */
- #endif /* BSD43 */
- #endif /* __linux__ */
- #endif /* BSD44 */
- #endif /* BELLV10 */
- return(0);
- #else /* Not SELECT */
- #ifdef CK_POLL /* We have poll() */
- struct pollfd pfd; /* Supply a valid address for poll() */
- #ifdef ODT30 /* But in SCO ODT 3.0 */
- #ifdef NAP /* we should use nap() instead */
- debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */
- nap((long)m); /* seems to break dialing. */
- return(0);
- #else
- debug(F101,"msleep ODT 3.0 POLL","",m);
- poll(&pfd, 0, m);
- return(0);
- #endif /* NAP */
- #else
- debug(F101,"msleep POLL","",m);
- poll(&pfd, 0, m);
- return(0);
- #endif /* ODT30 */
- /*
- We could handle the above more cleanly by just letting nap() take
- always take precedence over poll() in this routine, but there is no way
- to know whether that would break something else.
- */
- #else /* Not POLL */
- #ifdef USLEEP
- /*
- "This routine is implemented using setitimer(2); it requires eight
- system calls...". In other words, it might take 5 minutes to sleep
- 10 milliseconds...
- */
- debug(F101,"msleep USLEEP","",m);
- if (m >= 1000) { /* Catch big arguments. */
- sleep(m/1000);
- m = m % 1000;
- if (m < 10) return(0);
- }
- usleep((unsigned int)(m * 1000));
- return(0);
- #else
- #ifdef aegis
- time_$clock_t dur;
- debug(F101,"msleep aegis","",m);
- dur.c2.high16 = 0;
- dur.c2.low32 = 250 * m; /* one millisecond = 250 four microsecond ticks */
- time_$wait(time_$relative, dur, st);
- return(0);
- #else
- #ifdef PROVX1
- debug(F101,"msleep Venix","",m);
- if (m <= 0) return(0);
- sleep(-((m * 60 + 500) / 1000));
- return(0);
- #else
- #ifdef NAP
- debug(F101,"msleep NAP","",m);
- nap((long)m);
- return(0);
- #else
- #ifdef ATTSV
- #ifndef BSD44
- extern long times(); /* Or #include <times.h> ? */
- #endif /* BSD44 */
- long t1, t2, tarray[4];
- int t3;
- char *cp = getenv("HZ");
- int CLOCK_TICK;
- int hertz;
- if (cp && (hertz = atoi(cp))) {
- CLOCK_TICK = 1000 / hertz;
- } else { /* probably single user mode */
- #ifdef HZ
- CLOCK_TICK = 1000 / HZ;
- #else
- static warned = 0;
- /* HZ always exists in, for instance, SCO Xenix, so you don't have to
- * make special #ifdefs for XENIX here, like in ver 4F. Also, if you
- * have Xenix, you have should have nap(), so the best is to use -DNAP
- * in the makefile. Most systems have HZ.
- */
- CLOCK_TICK = 17; /* 1/60 sec */
- if (!warned) {
- printf("warning: environment variable HZ bad... using HZ=%drn",
- 1000 / CLOCK_TICK);
- warned = 1;
- }
- #endif /* !HZ */
- }
- debug(F101,"msleep ATTSV","",m);
- if (m <= 0) return(0);
- if (m >= 1000) { /* Catch big arguments. */
- sleep(m/1000);
- m = m % 1000;
- if (m < 10) return(0);
- }
- if ((t1 = times(tarray)) < 0) return(-1);
- while (1) {
- if ((t2 = times(tarray)) < 0) return(-1);
- t3 = ((int)(t2 - t1)) * CLOCK_TICK;
- if (t3 > m) return(t3);
- }
- #else /* Not ATTSV */
- #ifdef MSLFTIME /* Use ftime() loop... */
- int t1, t3 = 0;
- debug(F101,"msleep MSLFTIME","",m);
- if (m <= 0) return(0);
- if (m >= 1000) { /* Catch big arguments. */
- sleep(m/1000);
- m = m % 1000;
- if (m < 10) return(0);
- }
- #ifdef QNX
- ftime(&ftp); /* void ftime() in QNX */
- #else
- if (ftime(&ftp) < 0) return(-1); /* Get base time. */
- #endif /* QNX */
- t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
- while (1) {
- ftime(&ftp); /* Get current time and compare. */
- t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
- if (t3 > m) return(0);
- }
- #else
- /* This includes true POSIX, which has no way to do this. */
- debug(F101,"msleep busy loop","",m);
- if (m >= 1000) { /* Catch big arguments. */
- sleep(m/1000);
- m = m % 1000;
- if (m < 10) return(0);
- }
- if (m > 0) while (m > 0) m--; /* Just a dumb busy loop */
- return(0);
- #endif /* MSLFTIME */
- #endif /* ATTSV */
- #endif /* NAP */
- #endif /* PROVX1 */
- #endif /* aegis */
- #endif /* CK_POLL */
- #endif /* SELECT */
- #endif /* BEOSORBEBOX */
- #endif /* USLEEP */
- #endif /* Plan9 */
- }
- /* R T I M E R -- Reset elapsed time counter */
- VOID
- rtimer() {
- tcount = time( (time_t *) 0 );
- }
- /* G T I M E R -- Get current value of elapsed time counter in seconds */
- int
- gtimer() {
- int x;
- x = (int) (time( (time_t *) 0 ) - tcount);
- debug(F101,"gtimer","",x);
- return( (x < 0) ? 0 : x );
- }
- #ifdef GFTIMER
- /*
- Floating-point timers. Require not only floating point support, but
- also gettimeofday().
- */
- static struct timeval tzero;
- VOID
- rftimer() {
- #ifdef GTODONEARG /* Account for Mot's definition */
- (VOID) gettimeofday(&tzero);
- #else
- (VOID) gettimeofday(&tzero, (struct timezone *)0);
- #endif /* GTODONEARG */
- }
- CKFLOAT
- gftimer() {
- struct timeval tnow, tdelta;
- CKFLOAT s, sb;
- #ifdef DEBUG
- char fpbuf[64];
- #endif /* DEBUG */
- #ifdef GTODONEARG /* Acount for Mot's definition */
- (VOID) gettimeofday(&tnow);
- #else
- (VOID) gettimeofday(&tnow, (struct timezone *)0);
- #endif /* GTODONEARG */
- tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
- tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
- if (tdelta.tv_usec < 0) {
- tdelta.tv_sec--;
- tdelta.tv_usec += 1000000;
- }
- s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
- if (s < GFMINTIME)
- s = GFMINTIME;
- #ifdef DEBUG
- if (deblog) {
- sprintf(fpbuf,"%f",s);
- debug(F110,"gftimer",fpbuf,0);
- }
- #endif /* DEBUG */
- return(s);
- }
- #endif /* GFTIMER */
- /* Z T I M E -- Return asctime()-format date/time string */
- /*
- NOTE: as a side effect of calling this routine, we can also set the
- following two variables, giving the micro- and milliseconds (fractions of
- seconds) of the clock time. Currently this is done only in BSD-based builds
- that use gettimeofday(). When these variables are not filled in, they are
- left with a value of -1L.
- */
- VOID
- ztime(s) char **s; {
- #ifdef GFTIMER
- /*
- The gettimeofday() method, which also sets ztmsec and ztusec, works for
- all GFTIMER builds. NOTE: ztmsec and ztusec are defined in ckcmai.c,
- and extern declarations for them are in ckcdeb.h; thus they are
- declared in this file by inclusion of ckcdeb.h.
- */
- char *asctime();
- struct tm *localtime();
- struct tm *tp;
- ztmsec = -1L;
- ztusec = -1L;
- #ifdef GTODONEARG
- /* No 2nd arg in Motorola SV88 and some others */
- if (gettimeofday(&tv) > -1)
- #else
- #ifndef COHERENT
- #ifdef PTX
- if (gettimeofday(&tv,NULL) > -1)
- #else
- if (gettimeofday(&tv,&tz) > -1)
- #endif /* PTX */
- #endif /* COHERENT */
- #endif /* GTODONEARG */
- { /* Fill in tm struct */
- ztusec = tv.tv_usec; /* Microseconds */
- ztmsec = ztusec / 1000L; /* Milliseconds */
- #ifdef HPUX9
- {
- time_t zz;
- zz = tv.tv_sec;
- tp = localtime(&zz); /* Convert to local time */
- }
- #else
- #ifdef HPUX1000
- {
- time_t zz;
- zz = tv.tv_sec;
- tp = localtime(&zz);
- }
- #else
- #ifdef LINUX
- { /* avoid unaligned access trap on 64-bit platforms */
- time_t zz;
- zz = tv.tv_sec;
- tp = localtime(&zz);
- }
- #else
- #ifdef MACOSX
- tp = localtime((time_t *)&tv.tv_sec); /* Convert to local time */
- #else
- tp = localtime(&tv.tv_sec);
- #endif /* MACOSX */
- #endif /* LINUX */
- #endif /* HPUX1000 */
- #endif /* HPUX9 */
- *s = asctime(tp); /* Convert result to ASCII string */
- debug(F111,"ztime GFTIMER gettimeofday",*s,ztusec);
- }
- #else /* Not GFTIMER */
- #undef ZTIMEV7 /* Which systems need to use */
- #ifdef COHERENT /* old UNIX Version 7 way... */
- #define ZTIMEV7
- #endif /* COHERENT */
- #ifdef TOWER1
- #define ZTIMEV7
- #endif /* TOWER1 */
- #ifdef ANYBSD
- #ifndef BSD42
- #define ZTIMEV7
- #endif /* BSD42 */
- #endif /* ANYBSD */
- #ifdef V7
- #ifndef MINIX
- #define ZTIMEV7
- #endif /* MINIX */
- #endif /* V7 */
- #ifdef POSIX
- #define ZTIMEV7
- #endif /* POSIX */
- #ifdef HPUX1020
- /*
- Prototypes are in <time.h>, included above.
- */
- time_t clock_storage;
- clock_storage = time((void *) 0);
- *s = ctime(&clock_storage);
- debug(F110,"ztime: HPUX 10.20",*s,0);
- #else
- #ifdef ATTSV /* AT&T way */
- /* extern long time(); */ /* Theoretically these should */
- char *ctime(); /* already been dcl'd in <time.h> */
- time_t clock_storage;
- clock_storage = time(
- #ifdef IRIX60
- (time_t *)
- #else
- #ifdef BSD44
- (time_t *)
- #else
- (long *)
- #endif /* BSD44 */
- #endif /* IRIX60 */
- 0 );
- *s = ctime( &clock_storage );
- debug(F110,"ztime: ATTSV",*s,0);
- #else
- #ifdef PROVX1 /* Venix 1.0 way */
- int utime[2];
- time(utime);
- *s = ctime(utime);
- debug(F110,"ztime: PROVX1",*s,0);
- #else
- #ifdef BSD42 /* 4.2BSD way */
- char *asctime();
- struct tm *localtime();
- struct tm *tp;
- gettimeofday(&tv, &tz);
- ztusec = tv.tv_usec;
- ztmsec = tv.tv_usec / 1000L;
- tp = localtime(&tv.tv_sec);
- *s = asctime(tp);
- debug(F111,"ztime: BSD42",*s,ztusec);
- #else
- #ifdef MINIX /* MINIX way */
- #ifdef COMMENT
- extern long time(); /* Already got these from <time.h> */
- extern char *ctime();
- #endif /* COMMENT */
- time_t utime[2];
- time(utime);
- *s = ctime(utime);
- debug(F110,"ztime: MINIX",*s,0);
- #else
- #ifdef ZTIMEV7 /* The regular way */
- char *asctime();
- struct tm *localtime();
- struct tm *tp;
- long xclock; /* or unsigned long for BeBox? */
- time(&xclock);
- tp = localtime(&xclock);
- *s = asctime(tp);
- debug(F110,"ztime: ZTIMEV7",*s,0);
- #else /* Catch-all for others... */
- *s = "Day Mon 00 00:00:00 0000n"; /* Return dummy in asctime() format */
- debug(F110,"ztime: catch-all",*s,0);
- #endif /* ZTIMEV7 */
- #endif /* MINIX */
- #endif /* BSD42 */
- #endif /* PROVX1 */
- #endif /* ATTSV */
- #endif /* HPUX1020 */
- #endif /* GFTIMER */
- }
- /* C O N G M -- Get console terminal modes. */
- /*
- Saves initial console mode, and establishes variables for switching
- between current (presumably normal) mode and other modes.
- Should be called when program starts, but only after establishing
- whether program is in the foreground or background.
- Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
- */
- int
- congm() {
- int fd;
- if (backgrd || !isatty(0)) { /* If in background. */
- cgmf = -1; /* Don't bother, modes are garbage. */
- return(-1);
- }
- if (cgmf > 0) return(0); /* Already did this. */
- debug(F100,"congm getting modes","",0); /* Need to do it. */
- #ifdef aegis
- ios_$inq_type_uid(ios_$stdin, conuid, st);
- if (st.all != status_$ok) {
- fprintf(stderr, "problem getting stdin objtype: ");
- error_$print(st);
- }
- concrp = (conuid == mbx_$uid);
- conbufn = 0;
- #endif /* aegis */
- #ifndef BEBOX
- if ((fd = open(CTTNAM,2)) < 0) { /* Open controlling terminal */
- #ifdef COMMENT
- fprintf(stderr,"Error opening %sn", CTTNAM);
- perror("congm");
- return(-1);
- #else
- fd = 0;
- #endif /* COMMENT */
- }
- #else
- fd = 0;
- #endif /* !BEBOX */
- #ifdef BSD44ORPOSIX
- if (tcgetattr(fd,&ccold) < 0) return(-1);
- if (tcgetattr(fd,&cccbrk) < 0) return(-1);
- if (tcgetattr(fd,&ccraw) < 0) return(-1);
- #else
- #ifdef ATTSV
- if (ioctl(fd,TCGETA,&ccold) < 0) return(-1);
- if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
- if (ioctl(fd,TCGETA,&ccraw) < 0) return(-1);
- #ifdef VXVE
- cccbrk.c_line = 0; /* STTY line 0 for CDC VX/VE */
- if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
- ccraw.c_line = 0; /* STTY line 0 for CDC VX/VE */
- if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
- #endif /* VXVE */
- #else
- #ifdef BELLV10
- if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1);
- if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1);
- if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1);
- debug(F101,"cccbrk.sg_flags orig","", cccbrk.sg_flags);
- #else
- if (gtty(fd,&ccold) < 0) return(-1);
- if (gtty(fd,&cccbrk) < 0) return(-1);
- if (gtty(fd,&ccraw) < 0) return(-1);
- #endif /* BELLV10 */
- #endif /* ATTSV */
- #endif /* BSD44ORPOSIX */
- #ifdef sony_news /* Sony NEWS */
- if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
- perror("congm error getting Kanji mode");
- debug(F101,"congm error getting Kanji mode","",0);
- km_con = -1; /* Make sure this stays undefined. */
- return(-1);
- }
- #endif /* sony_news */
- if (fd > 0)
- close(fd);
- cgmf = 1; /* Flag that we got them. */
- return(1);
- }
- /* C O N C B -- Put console in cbreak mode. */
- /* Returns 0 if ok, -1 if not */
- int
- #ifdef CK_ANSIC
- concb(char esc)
- #else
- concb(esc) char esc;
- #endif /* CK_ANSIC */
- /* concb */ {
- int x;
- debug(F101,"concb cgmf","",cgmf);
- debug(F101,"concb backgrd","",backgrd);
- if (cgmf < 1) /* Did we get console modes yet? */
- if (!backgrd) /* No, in background? */
- congm(); /* No, try to get them now. */
- if (cgmf < 1) /* Still don't have them? */
- return(0); /* Give up. */
- debug(F101,"concb ttyfd","",ttyfd);
- debug(F101,"concb ttfdflg","",ttfdflg);
- #ifdef COMMENT
- /* This breaks returning to prompt after protocol with "-l 0" */
- /* Commented out July 1998 */
- if (ttfdflg && ttyfd >= 0 && ttyfd < 3)
- return(0);
- #endif /* COMMENT */
- x = isatty(0);
- debug(F101,"concb isatty","",x);
- if (!x) return(0); /* Only when running on real ttys */
- debug(F101,"concb suspend","",suspend);
- if (backgrd) return(0); /* Do nothing if in background. */
- escchr = esc; /* Make this available to other fns */
- ckxech = 1; /* Program can echo characters */
- #ifdef aegis
- conbufn = 0;
- if (concrp) return(write(1, "