Annotation of 43BSDTahoe/ucb/telnet/Source/sys_bsd.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1988 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted
                      6:  * provided that this notice is preserved and that due credit is given
                      7:  * to the University of California at Berkeley. The name of the University
                      8:  * may not be used to endorse or promote products derived from this
                      9:  * software without specific prior written permission. This software
                     10:  * is provided ``as is'' without express or implied warranty.
                     11:  */
                     12: 
                     13: #ifndef lint
                     14: static char sccsid[] = "@(#)sys_bsd.c  1.11 (Berkeley) 3/27/88";
                     15: #endif /* not lint */
                     16: 
                     17: /*
                     18:  * The following routines try to encapsulate what is system dependent
                     19:  * (at least between 4.x and dos) which is used in telnet.c.
                     20:  */
                     21: 
                     22: #if    defined(unix)
                     23: 
                     24: #include <sys/ioctl.h>
                     25: #include <sys/types.h>
                     26: #include <sys/time.h>
                     27: #include <sys/socket.h>
                     28: #include <signal.h>
                     29: #include <errno.h>
                     30: 
                     31: #include "ring.h"
                     32: 
                     33: #include "fdset.h"
                     34: 
                     35: #include "defines.h"
                     36: #include "externs.h"
                     37: #include "types.h"
                     38: 
                     39: int
                     40:        tout,                   /* Output file descriptor */
                     41:        tin,                    /* Input file descriptor */
                     42:        net,
                     43:        HaveInput;              /* There is input available to scan */
                     44: 
                     45: static struct  tchars otc = { 0 }, ntc = { 0 };
                     46: static struct  ltchars oltc = { 0 }, nltc = { 0 };
                     47: static struct  sgttyb ottyb = { 0 }, nttyb = { 0 };
                     48: 
                     49: static fd_set ibits, obits, xbits;
                     50: 
                     51: 
                     52: init_sys()
                     53: {
                     54:     tout = fileno(stdout);
                     55:     tin = fileno(stdin);
                     56:     FD_ZERO(&ibits);
                     57:     FD_ZERO(&obits);
                     58:     FD_ZERO(&xbits);
                     59: 
                     60:     errno = 0;
                     61: }
                     62: 
                     63: 
                     64: TerminalWrite(buf, n)
                     65: char   *buf;
                     66: int    n;
                     67: {
                     68:     return write(tout, buf, n);
                     69: }
                     70: 
                     71: TerminalRead(buf, n)
                     72: char   *buf;
                     73: int    n;
                     74: {
                     75:     return read(tin, buf, n);
                     76: }
                     77: 
                     78: /*
                     79:  *
                     80:  */
                     81: 
                     82: int
                     83: TerminalAutoFlush()
                     84: {
                     85: #if    defined(LNOFLSH)
                     86:     int flush;
                     87: 
                     88:     ioctl(0, TIOCLGET, (char *)&flush);
                     89:     return !(flush&LNOFLSH);   /* if LNOFLSH, no autoflush */
                     90: #else  /* LNOFLSH */
                     91:     return 1;
                     92: #endif /* LNOFLSH */
                     93: }
                     94: 
                     95: /*
                     96:  * TerminalSpecialChars()
                     97:  *
                     98:  * Look at an input character to see if it is a special character
                     99:  * and decide what to do.
                    100:  *
                    101:  * Output:
                    102:  *
                    103:  *     0       Don't add this character.
                    104:  *     1       Do add this character
                    105:  */
                    106: 
                    107: int
                    108: TerminalSpecialChars(c)
                    109: int    c;
                    110: {
                    111:     void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
                    112: 
                    113:     if (c == ntc.t_intrc) {
                    114:        intp();
                    115:        return 0;
                    116:     } else if (c == ntc.t_quitc) {
                    117:        sendbrk();
                    118:        return 0;
                    119:     } else if (c == nltc.t_flushc) {
                    120:        xmitAO();               /* Transmit Abort Output */
                    121:        return 0;
                    122:     } else if (!MODE_LOCAL_CHARS(globalmode)) {
                    123:        if (c == nttyb.sg_kill) {
                    124:            xmitEL();
                    125:            return 0;
                    126:        } else if (c == nttyb.sg_erase) {
                    127:            xmitEC();           /* Transmit Erase Character */
                    128:            return 0;
                    129:        }
                    130:     }
                    131:     return 1;
                    132: }
                    133: 
                    134: 
                    135: /*
                    136:  * Flush output to the terminal
                    137:  */
                    138:  
                    139: void
                    140: TerminalFlushOutput()
                    141: {
                    142:     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
                    143: }
                    144: 
                    145: void
                    146: TerminalSaveState()
                    147: {
                    148:     ioctl(0, TIOCGETP, (char *)&ottyb);
                    149:     ioctl(0, TIOCGETC, (char *)&otc);
                    150:     ioctl(0, TIOCGLTC, (char *)&oltc);
                    151: 
                    152:     ntc = otc;
                    153:     nltc = oltc;
                    154:     nttyb = ottyb;
                    155: 
                    156:     termEofChar = ntc.t_eofc;
                    157:     termEraseChar = nttyb.sg_erase;
                    158:     termFlushChar = nltc.t_flushc;
                    159:     termIntChar = ntc.t_intrc;
                    160:     termKillChar = nttyb.sg_kill;
                    161:     termQuitChar = ntc.t_quitc;
                    162: }
                    163: 
                    164: void
                    165: TerminalRestoreState()
                    166: {
                    167: }
                    168: 
                    169: /*
                    170:  * TerminalNewMode - set up terminal to a specific mode.
                    171:  */
                    172: 
                    173: 
                    174: void
                    175: TerminalNewMode(f)
                    176: register int f;
                    177: {
                    178:     static int prevmode = 0;
                    179:     struct tchars *tc;
                    180:     struct tchars tc3;
                    181:     struct ltchars *ltc;
                    182:     struct sgttyb sb;
                    183:     int onoff;
                    184:     int old;
                    185:     struct     tchars notc2;
                    186:     struct     ltchars noltc2;
                    187:     static struct      tchars notc =   { -1, -1, -1, -1, -1, -1 };
                    188:     static struct      ltchars noltc = { -1, -1, -1, -1, -1, -1 };
                    189: 
                    190:     globalmode = f;
                    191:     if (prevmode == f)
                    192:        return;
                    193:     old = prevmode;
                    194:     prevmode = f;
                    195:     sb = nttyb;
                    196: 
                    197:     switch (f) {
                    198: 
                    199:     case 0:
                    200:        onoff = 0;
                    201:        tc = &otc;
                    202:        ltc = &oltc;
                    203:        break;
                    204: 
                    205:     case 1:            /* remote character processing, remote echo */
                    206:     case 2:            /* remote character processing, local echo */
                    207:     case 6:            /* 3270 mode - like 1, but with xon/xoff local */
                    208:                    /* (might be nice to have "6" in telnet also...) */
                    209:            sb.sg_flags |= CBREAK;
                    210:            if ((f == 1) || (f == 6)) {
                    211:                sb.sg_flags &= ~(ECHO|CRMOD);
                    212:            } else {
                    213:                sb.sg_flags |= ECHO|CRMOD;
                    214:            }
                    215:            sb.sg_erase = sb.sg_kill = -1;
                    216:            if (f == 6) {
                    217:                tc = &tc3;
                    218:                tc3 = notc;
                    219:                    /* get XON, XOFF characters */
                    220:                tc3.t_startc = otc.t_startc;
                    221:                tc3.t_stopc = otc.t_stopc;
                    222:            } else {
                    223:                /*
                    224:                 * If user hasn't specified one way or the other,
                    225:                 * then default to not trapping signals.
                    226:                 */
                    227:                if (!donelclchars) {
                    228:                    localchars = 0;
                    229:                }
                    230:                if (localchars) {
                    231:                    notc2 = notc;
                    232:                    notc2.t_intrc = ntc.t_intrc;
                    233:                    notc2.t_quitc = ntc.t_quitc;
                    234:                    tc = &notc2;
                    235:                } else {
                    236:                    tc = &notc;
                    237:                }
                    238:            }
                    239:            ltc = &noltc;
                    240:            onoff = 1;
                    241:            break;
                    242:     case 3:            /* local character processing, remote echo */
                    243:     case 4:            /* local character processing, local echo */
                    244:     case 5:            /* local character processing, no echo */
                    245:            sb.sg_flags &= ~CBREAK;
                    246:            sb.sg_flags |= CRMOD;
                    247:            if (f == 4)
                    248:                sb.sg_flags |= ECHO;
                    249:            else
                    250:                sb.sg_flags &= ~ECHO;
                    251:            notc2 = ntc;
                    252:            tc = &notc2;
                    253:            noltc2 = oltc;
                    254:            ltc = &noltc2;
                    255:            /*
                    256:             * If user hasn't specified one way or the other,
                    257:             * then default to trapping signals.
                    258:             */
                    259:            if (!donelclchars) {
                    260:                localchars = 1;
                    261:            }
                    262:            if (localchars) {
                    263:                notc2.t_brkc = nltc.t_flushc;
                    264:                noltc2.t_flushc = -1;
                    265:            } else {
                    266:                notc2.t_intrc = notc2.t_quitc = -1;
                    267:            }
                    268:            noltc2.t_suspc = escape;
                    269:            noltc2.t_dsuspc = -1;
                    270:            onoff = 1;
                    271:            break;
                    272: 
                    273:     default:
                    274:            return;
                    275:     }
                    276:     ioctl(tin, TIOCSLTC, (char *)ltc);
                    277:     ioctl(tin, TIOCSETC, (char *)tc);
                    278:     ioctl(tin, TIOCSETP, (char *)&sb);
                    279: #if    (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
                    280:     ioctl(tin, FIONBIO, (char *)&onoff);
                    281:     ioctl(tout, FIONBIO, (char *)&onoff);
                    282: #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
                    283: #if    defined(TN3270)
                    284:     if (noasynch == 0) {
                    285:        ioctl(tin, FIOASYNC, (char *)&onoff);
                    286:     }
                    287: #endif /* defined(TN3270) */
                    288: 
                    289:     if (MODE_LINE(f)) {
                    290:        void doescape();
                    291: 
                    292:        signal(SIGTSTP, doescape);
                    293:     } else if (MODE_LINE(old)) {
                    294:        signal(SIGTSTP, SIG_DFL);
                    295:        sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
                    296:     }
                    297: }
                    298: 
                    299: 
                    300: int
                    301: NetClose(net)
                    302: int    net;
                    303: {
                    304:     return close(net);
                    305: }
                    306: 
                    307: 
                    308: void
                    309: NetNonblockingIO(fd, onoff)
                    310: int
                    311:        fd,
                    312:        onoff;
                    313: {
                    314:     ioctl(fd, FIONBIO, (char *)&onoff);
                    315: }
                    316: 
                    317: void
                    318: NetSigIO(fd, onoff)
                    319: int
                    320:        fd,
                    321:        onoff;
                    322: {
                    323:     ioctl(fd, FIOASYNC, (char *)&onoff);       /* hear about input */
                    324: }
                    325: 
                    326: void
                    327: NetSetPgrp(fd)
                    328: int fd;
                    329: {
                    330:     int myPid;
                    331: 
                    332:     myPid = getpid();
                    333: #if    defined(NOT43)
                    334:     myPid = -myPid;
                    335: #endif /* defined(NOT43) */
                    336:     ioctl(fd, SIOCSPGRP, (char *)&myPid);      /* set my pid */
                    337: }
                    338: 
                    339: /*
                    340:  * Various signal handling routines.
                    341:  */
                    342: 
                    343: static void
                    344: deadpeer()
                    345: {
                    346:        setcommandmode();
                    347:        longjmp(peerdied, -1);
                    348: }
                    349: 
                    350: static void
                    351: intr()
                    352: {
                    353:     if (localchars) {
                    354:        intp();
                    355:        return;
                    356:     }
                    357:     setcommandmode();
                    358:     longjmp(toplevel, -1);
                    359: }
                    360: 
                    361: static void
                    362: intr2()
                    363: {
                    364:     if (localchars) {
                    365:        sendbrk();
                    366:        return;
                    367:     }
                    368: }
                    369: 
                    370: static void
                    371: doescape()
                    372: {
                    373:     command(0);
                    374: }
                    375: 
                    376: void
                    377: sys_telnet_init()
                    378: {
                    379: #if    defined(TN3270)
                    380:     int myPid;
                    381: #endif /* defined(TN3270) */
                    382: 
                    383:     signal(SIGINT, intr);
                    384:     signal(SIGQUIT, intr2);
                    385:     signal(SIGPIPE, deadpeer);
                    386: 
                    387:     setconnmode();
                    388: 
                    389:     NetNonblockingIO(net, 1);
                    390: 
                    391: #if    defined(TN3270)
                    392:     if (noasynch == 0) {                       /* DBX can't handle! */
                    393:        NetSigIO(net, 1);
                    394:        NetSetPgrp(net);
                    395:     }
                    396: #endif /* defined(TN3270) */
                    397: 
                    398: #if    defined(SO_OOBINLINE)
                    399:     SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
                    400: #endif /* defined(SO_OOBINLINE) */
                    401: }
                    402: 
                    403: /*
                    404:  * Process rings -
                    405:  *
                    406:  *     This routine tries to fill up/empty our various rings.
                    407:  *
                    408:  *     The parameter specifies whether this is a poll operation,
                    409:  *     or a block-until-something-happens operation.
                    410:  *
                    411:  *     The return value is 1 if something happened, 0 if not.
                    412:  */
                    413: 
                    414: int
                    415: process_rings(netin, netout, netex, ttyin, ttyout, poll)
                    416: int poll;              /* If 0, then block until something to do */
                    417: {
                    418:     register int c;
                    419:                /* One wants to be a bit careful about setting returnValue
                    420:                 * to one, since a one implies we did some useful work,
                    421:                 * and therefore probably won't be called to block next
                    422:                 * time (TN3270 mode only).
                    423:                 */
                    424:     int returnValue = 0;
                    425:     static struct timeval TimeValue = { 0 };
                    426: 
                    427:     if (netout) {
                    428:        FD_SET(net, &obits);
                    429:     } 
                    430:     if (ttyout) {
                    431:        FD_SET(tout, &obits);
                    432:     }
                    433: #if    defined(TN3270)
                    434:     if (ttyin) {
                    435:        FD_SET(tin, &ibits);
                    436:     }
                    437: #else  /* defined(TN3270) */
                    438:     if (ttyin) {
                    439:        FD_SET(tin, &ibits);
                    440:     }
                    441: #endif /* defined(TN3270) */
                    442: #if    defined(TN3270)
                    443:     if (netin) {
                    444:        FD_SET(net, &ibits);
                    445:     }
                    446: #   else /* !defined(TN3270) */
                    447:     if (netin) {
                    448:        FD_SET(net, &ibits);
                    449:     }
                    450: #   endif /* !defined(TN3270) */
                    451:     if (netex) {
                    452:        FD_SET(net, &xbits);
                    453:     }
                    454:     if ((c = select(16, &ibits, &obits, &xbits,
                    455:                        (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
                    456:        if (c == -1) {
                    457:                    /*
                    458:                     * we can get EINTR if we are in line mode,
                    459:                     * and the user does an escape (TSTP), or
                    460:                     * some other signal generator.
                    461:                     */
                    462:            if (errno == EINTR) {
                    463:                return 0;
                    464:            }
                    465: #          if defined(TN3270)
                    466:                    /*
                    467:                     * we can get EBADF if we were in transparent
                    468:                     * mode, and the transcom process died.
                    469:                    */
                    470:            if (errno == EBADF) {
                    471:                        /*
                    472:                         * zero the bits (even though kernel does it)
                    473:                         * to make sure we are selecting on the right
                    474:                         * ones.
                    475:                        */
                    476:                FD_ZERO(&ibits);
                    477:                FD_ZERO(&obits);
                    478:                FD_ZERO(&xbits);
                    479:                return 0;
                    480:            }
                    481: #          endif /* defined(TN3270) */
                    482:                    /* I don't like this, does it ever happen? */
                    483:            printf("sleep(5) from telnet, after select\r\n");
                    484:            sleep(5);
                    485:        }
                    486:        return 0;
                    487:     }
                    488: 
                    489:     /*
                    490:      * Any urgent data?
                    491:      */
                    492:     if (FD_ISSET(net, &xbits)) {
                    493:        FD_CLR(net, &xbits);
                    494:        SYNCHing = 1;
                    495:        ttyflush(1);    /* flush already enqueued data */
                    496:     }
                    497: 
                    498:     /*
                    499:      * Something to read from the network...
                    500:      */
                    501:     if (FD_ISSET(net, &ibits)) {
                    502:        int canread;
                    503: 
                    504:        FD_CLR(net, &ibits);
                    505:        canread = ring_empty_consecutive(&netiring);
                    506: #if    !defined(SO_OOBINLINE)
                    507:            /*
                    508:             * In 4.2 (and some early 4.3) systems, the
                    509:             * OOB indication and data handling in the kernel
                    510:             * is such that if two separate TCP Urgent requests
                    511:             * come in, one byte of TCP data will be overlaid.
                    512:             * This is fatal for Telnet, but we try to live
                    513:             * with it.
                    514:             *
                    515:             * In addition, in 4.2 (and...), a special protocol
                    516:             * is needed to pick up the TCP Urgent data in
                    517:             * the correct sequence.
                    518:             *
                    519:             * What we do is:  if we think we are in urgent
                    520:             * mode, we look to see if we are "at the mark".
                    521:             * If we are, we do an OOB receive.  If we run
                    522:             * this twice, we will do the OOB receive twice,
                    523:             * but the second will fail, since the second
                    524:             * time we were "at the mark", but there wasn't
                    525:             * any data there (the kernel doesn't reset
                    526:             * "at the mark" until we do a normal read).
                    527:             * Once we've read the OOB data, we go ahead
                    528:             * and do normal reads.
                    529:             *
                    530:             * There is also another problem, which is that
                    531:             * since the OOB byte we read doesn't put us
                    532:             * out of OOB state, and since that byte is most
                    533:             * likely the TELNET DM (data mark), we would
                    534:             * stay in the TELNET SYNCH (SYNCHing) state.
                    535:             * So, clocks to the rescue.  If we've "just"
                    536:             * received a DM, then we test for the
                    537:             * presence of OOB data when the receive OOB
                    538:             * fails (and AFTER we did the normal mode read
                    539:             * to clear "at the mark").
                    540:             */
                    541:        if (SYNCHing) {
                    542:            int atmark;
                    543: 
                    544:            ioctl(net, SIOCATMARK, (char *)&atmark);
                    545:            if (atmark) {
                    546:                c = recv(net, netiring.supply, canread, MSG_OOB);
                    547:                if ((c == -1) && (errno == EINVAL)) {
                    548:                    c = recv(net, netiring.supply, canread, 0);
                    549:                    if (clocks.didnetreceive < clocks.gotDM) {
                    550:                        SYNCHing = stilloob(net);
                    551:                    }
                    552:                }
                    553:            } else {
                    554:                c = recv(net, netiring.supply, canread, 0);
                    555:            }
                    556:        } else {
                    557:            c = recv(net, netiring.supply, canread, 0);
                    558:        }
                    559:        settimer(didnetreceive);
                    560: #else  /* !defined(SO_OOBINLINE) */
                    561:        c = recv(net, netiring.supply, canread, 0);
                    562: #endif /* !defined(SO_OOBINLINE) */
                    563:        if (c < 0 && errno == EWOULDBLOCK) {
                    564:            c = 0;
                    565:        } else if (c <= 0) {
                    566:            return -1;
                    567:        }
                    568:        if (netdata) {
                    569:            Dump('<', netiring.supply, c);
                    570:        }
                    571:        if (c)
                    572:            ring_supplied(&netiring, c);
                    573:        returnValue = 1;
                    574:     }
                    575: 
                    576:     /*
                    577:      * Something to read from the tty...
                    578:      */
                    579:     if (FD_ISSET(tin, &ibits)) {
                    580:        FD_CLR(tin, &ibits);
                    581:        c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
                    582:        if (c < 0 && errno == EWOULDBLOCK) {
                    583:            c = 0;
                    584:        } else {
                    585:            /* EOF detection for line mode!!!! */
                    586:            if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
                    587:                        /* must be an EOF... */
                    588:                *ttyiring.supply = termEofChar;
                    589:                c = 1;
                    590:            }
                    591:            if (c <= 0) {
                    592:                return -1;
                    593:            }
                    594:            ring_supplied(&ttyiring, c);
                    595:        }
                    596:        returnValue = 1;                /* did something useful */
                    597:     }
                    598: 
                    599:     if (FD_ISSET(net, &obits)) {
                    600:        FD_CLR(net, &obits);
                    601:        returnValue |= netflush();
                    602:     }
                    603:     if (FD_ISSET(tout, &obits)) {
                    604:        FD_CLR(tout, &obits);
                    605:        returnValue |= ttyflush(SYNCHing|flushout);
                    606:     }
                    607: 
                    608:     return returnValue;
                    609: }
                    610: #endif /* defined(unix) */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.