Annotation of coherent/e/bin/cku179/ckcnet.c, revision 1.1.1.1

1.1       root        1: char *cknetv = "Network support, 5A(007) 8 Feb 91";
                      2: 
                      3: /*  C K C N E T  --  Network support  */
                      4: /*
                      5:  Authors:
                      6: 
                      7:  Frank da Cruz ([email protected], [email protected]),
                      8:    Columbia University Center for Computing Activities.
                      9:  netopen() routine for TCP/IP originally by Ken Yap, Rochester University
                     10:    ([email protected]) (no longer at that address).
                     11:  SunLink X.25 support by Marcello Frutig, Catholic University,
                     12:    Rio de Janeiro, Brazil ([email protected]).
                     13:  Missing pieces for Excelan sockets library from William Bader, Moravian
                     14:    College <[email protected]>.
                     15:  telnet protocol support by Frank da Cruz.
                     16:  TGV MultiNet code by Frank da Cruz.
                     17:  Other contributions as indicated below.
                     18: 
                     19:  Copyright (C) 1991, 1992, Trustees of Columbia University in the City of New 
                     20:  York.  Permission is granted to any individual or institution to use, copy, or
                     21:  redistribute this software as long as it is not sold for profit, provided this
                     22:  copyright notice is retained. 
                     23: */
                     24: 
                     25: #include "ckcdeb.h"
                     26: #include "ckcker.h"
                     27: #include "ckcnet.h"
                     28: 
                     29: #ifdef NETCONN
                     30: /* Don't need these if there is no network support. */
                     31: 
                     32: #include <errno.h>
                     33: #include <signal.h>
                     34: #ifndef ZILOG
                     35: #include <setjmp.h>
                     36: #else
                     37: #include <setret.h>
                     38: #endif /* ZILOG */
                     39: 
                     40: extern SIGTYP (*saval)();              /* For saving alarm handler */
                     41: extern int duplex, debses, seslog, ttyfd, quiet; /* External variables */
                     42: 
                     43: #ifdef SVR4
                     44: /*
                     45:   These suggested by Rob Healey, [email protected], to avoid
                     46:   bugs in Berkeley compatibility library on Sys V R4 systems, but untested
                     47:   by me (fdc).  Remove this bit if it gives you trouble.
                     48:   (Later corrected by Marc Boucher <[email protected]> because
                     49:   bzero/bcopy are not argument-compatible with memset/memcpy|memmove.)
                     50: */
                     51: #define bzero(s,n) memset(s,0,n) 
                     52: #define bcopy(h,a,l) memmove(a,h,l)
                     53: #endif /* SVR4 */
                     54: 
                     55: #define NAMECPYL 100                   /* Local copy of hostname */
                     56: static char namecopy[NAMECPYL];
                     57: 
                     58: char ipaddr[20] = { '\0' };            /* Global copy of IP address */
                     59: 
                     60: #ifdef MULTINET
                     61: /*
                     62:   General global variables, but so far used only by MultiNet.
                     63:   Kept within #ifdef MULTINET..#endif to keep strict compilers (and lint)
                     64:   from complaining about unused variables.
                     65: */
                     66: static jmp_buf njbuf;                  /* For timeout longjumps */
                     67: #endif /* MULTINET */
                     68: 
                     69: #endif /* NETCONN */
                     70: 
                     71: int ttnet = NET_NONE;                  /* Network type */
                     72: int ttnproto = NP_NONE;                        /* Network virtual terminal protocol */
                     73: int tn_init = 0;                       /* Telnet protocol initialized flag */
                     74: 
                     75: #ifndef NETCONN
                     76: /*
                     77:   Network support not defined.  
                     78:   Dummy functions here in case #ifdef's forgotten elsewhere.
                     79: */
                     80: int                                    /* Open network connection */
                     81: netopen(name, lcl, nett) char *name; int *lcl, nett; {
                     82:     return(-1);
                     83: }
                     84: int                                    /* Close network connection */
                     85: netclos() {
                     86:     return(-1);
                     87: }
                     88: int                                    /* Check network input buffer */
                     89: nettchk() {
                     90:     return(-1);
                     91: }
                     92: int                                    /* Flush network input buffer */
                     93: netflui() {
                     94:     return(-1);
                     95: }
                     96: int                                    /* Send network BREAK */
                     97: netbreak() {
                     98:     return(-1);
                     99: }
                    100: int                                    /* Input character from network */
                    101: netinc(timo) int timo; {
                    102: }
                    103: int                                    /* Output character to network */
                    104: #ifdef CK_ANSIC
                    105: nettoc(char c)
                    106: #else
                    107: nettoc(c) char c;
                    108: #endif /* CK_ANSIC */
                    109: /* nettoc */ {
                    110:     return(-1);
                    111: }
                    112: int
                    113: nettol(s,n) char *s; int n; {
                    114:     return(-1);
                    115: }
                    116: 
                    117: #else /* NETCONN is defined (rest of this module...) */
                    118: 
                    119: #ifdef MULTINET
                    120: 
                    121: /* For buffered network reads... */
                    122: /*
                    123:   If the buffering code is written right, it shouldn't matter how long this
                    124:   buffer is -- it could even be shorter than a Kermit packet.
                    125: */
                    126: #define TTIBUFL 8192                   /* Maybe 8K?... */
                    127: static CHAR ttibuf[TTIBUFL+1];
                    128: static int ttibp = 0, ttibn = 0;
                    129: 
                    130: /*
                    131:   Read bytes from network into internal buffer ttibuf[].
                    132:   To be called when input buffer is empty, i.e. when ttibn == 0.
                    133: 
                    134:   Other network reading routines, like ttinc, ttinl, ttxin, should check the
                    135:   internal buffer first, and call this routine for a refill if necessary.
                    136: 
                    137:   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
                    138:   returns number of bytes read, and sets global ttibn to that number and
                    139:   ttibp (the buffer pointer) to zero.
                    140: */
                    141: int
                    142: ttbufr() {                             /* TT Buffer Read */
                    143:     int x, count;
                    144:     if (ttnet != NET_TCPB) {           /* First make sure current net is */
                    145:        /* Fill in support for DECnet, etc, here */
                    146:        return(-1);                     /* TCP/IP; if not, do nothing. */
                    147:     } else {
                    148:        /* Read as much as there us, up to our buffer size. */
                    149:        count = nettchk();
                    150:        if (count < 0) return(-1);
                    151:        if (count > TTIBUFL) count = TTIBUFL;
                    152:        if (count == 0) count = 1;
                    153:        debug(F101,"ttbufr count","",count);
                    154: 
                    155: #ifdef COMMENT
                    156: /*
                    157:  This is for nonblocking reads, which we don't do any more.  This code didn't
                    158:  work anyway, in the sense that a broken connection was never sensed.
                    159: */
                    160:        if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
                    161:            if (count == -1 && socket_errno == EWOULDBLOCK) {
                    162:                debug(F100,"ttbufr finds nothing","",0);
                    163:                return(0);
                    164:            } else if (count == 0) {
                    165:                debug(F100,"ttbufr socket eof","",0);           
                    166:                return(-1);
                    167:            } else {
                    168:                debug(F101,"ttbufr socket_read error","",socket_errno);
                    169:                return(-1);
                    170:            }
                    171:        }
                    172: #else
                    173: /* This is for blocking reads */
                    174:        if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
                    175:            debug(F101,"ttbufr socket_read","",count);
                    176:            debug(F101,"ttbufr socket_errno","",socket_errno);
                    177:            return(-1);
                    178:        }
                    179: #endif /* COMMENT */
                    180:        debug(F101,"ttbufr","",count);  /* Got some bytes. */
                    181:        ttibp = 0;                      /* Reset buffer pointer. */
                    182:        return(ttibn = count);          /* Set and return buffer count. */
                    183:     }
                    184: }
                    185: #endif /* MULTINET */
                    186: 
                    187: /*
                    188:   C-Kermit network open/close functions for BSD-sockets.
                    189:   Much of this code shared by SunLink X.25, which also uses the socket library.
                    190: */
                    191: 
                    192: /*  N E T O P E N  --  Open a network connection.  */
                    193: 
                    194: /*  Returns 0 on success, -1 on failure.  */
                    195: 
                    196: #define        TELNET_PORT     23         /* Should do lookup, but it won't change */
                    197: 
                    198: /* This symbol is not known to, e.g., Ultrix 2.0 */
                    199: #ifndef TELOPT_TTYPE
                    200: #define TELOPT_TTYPE 24
                    201: #endif /* TELOPT_TTYPE */
                    202: 
                    203: /*  N E T O P N  --  Open a network connection.  */
                    204: /*
                    205:   Call with:
                    206:     name of host (or host:service),
                    207:     lcl - local-mode flag to be set if this function succeeds,
                    208:     network type - value defined in ckunet.h.
                    209: */
                    210: 
                    211: #ifdef EXCELAN
                    212: /*
                    213:   Most other BSD sockets implementations define these in header files
                    214:   and libraries.
                    215: */
                    216: struct servent {
                    217:     unsigned short s_port;
                    218: };
                    219: 
                    220: struct hostent {
                    221:     short h_addrtype;
                    222:     struct in_addr h_addr;
                    223:     int h_length;
                    224: };
                    225: 
                    226: struct servent *
                    227: getservbyname(service, connection) char *service,*connection; {
                    228:     static struct servent servrec;
                    229:     int port;
                    230: 
                    231:     port = 0;
                    232:     if (strcmp(service, "telnet") == 0) port = 23;
                    233:     else if (strcmp(service, "smtp") == 0) port = 25;
                    234:     else port = atoi(service);
                    235: 
                    236:     debug(F101,"getservbyname return port ","",port);
                    237: 
                    238:     if (port > 0) {
                    239:        servrec.s_port = htons(port);
                    240:        return( &servrec );
                    241:     }
                    242:     return( (struct servent *) NULL );
                    243: }
                    244: 
                    245: struct hostent *
                    246: gethostbyname(hostname) char *hostname; {
                    247:     return( (struct hostent *) NULL );
                    248: }
                    249: 
                    250: unsigned long
                    251: inet_addr(name) char *name; {
                    252:     unsigned long addr;
                    253: 
                    254:     addr = rhost(&name);
                    255:     debug(F111,"inet_addr ",name,(int)addr);
                    256:     return(addr);
                    257: }
                    258: 
                    259: char *
                    260: inet_ntoa(in) struct in_addr in; {
                    261:     static char name[80];
                    262:     sprintf(name, "%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno);
                    263:     return(name);
                    264: }
                    265: #endif /* EXCELAN */
                    266: 
                    267: /*  N E T O P E N  --  Open a network connection  */
                    268: /*
                    269:   Calling conventions same as ttopen(), except third argument is network
                    270:   type rather than modem type.  Designed to be called from within ttopen.
                    271: */
                    272: int
                    273: netopen(name, lcl, nett) char *name; int *lcl, nett; {
                    274:     char *p;
                    275:     int on = 1, i, x;
                    276:     struct servent *service, servrec;
                    277:     struct hostent *host;
                    278:     struct sockaddr_in saddr;
                    279: #ifdef EXCELAN
                    280:     struct sockaddr_in send_socket;
                    281: #endif /* EXCELAN */
                    282: 
                    283: #ifdef SUNX25                          /* Code for SunLink X.25 support */
                    284: #define X29PID 1                       /* X.29 Protocol ID */
                    285:     VOID x25oobh(); 
                    286:     CONN_DB x25host;
                    287:     FACILITY_DB x25facil;
                    288:     static int needh = 1;
                    289:     PID_T pid;
                    290:     extern int linkid, lcn, x25ver;
                    291:     extern int revcall, closgr, cudata;
                    292:     extern char udata[MAXCUDATA];
                    293: #endif /* SUNX25 */
                    294: 
                    295:     debug(F101,"netopen nett","",nett);
                    296:     *ipaddr = '\0';                    /* Initialize IP address string */
                    297: 
                    298: #ifdef SUNX25 
                    299:     if (nett == NET_SX25) {            /* If network type is X.25 */
                    300:         netclos();                     /* Close any previous net connection */
                    301:         ttnproto = NP_NONE;            /* No protocol selected yet */
                    302: 
                    303:         /* Set up host structure */
                    304:         bzero ((char *)&x25host,sizeof(x25host));
                    305:         if ((x25host.hostlen = pkx121 (name,x25host.host)) < 0) {
                    306:             fprintf (stderr,"Invalid X.121 host address %s\n",name);
                    307:             errno = 0;
                    308:             return (-1);
                    309:         }
                    310:         x25host.datalen = X29PIDLEN;
                    311:         x25host.data[0] = X29PID;
                    312: 
                    313:        /* Set call user data if specified */
                    314:         if (cudata) {
                    315:             strncpy(x25host.data+X29PIDLEN,udata,(int)strlen(udata));
                    316:             x25host.datalen += (int)strlen(udata);
                    317:         }
                    318: 
                    319:         /* Open SunLink X.25 socket */
                    320:         if ((ttyfd = socket (AF_X25, SOCK_STREAM, 0)) < 0) {
                    321:            debug(F101,"netopen socket error","",errno);
                    322:             perror ("X.25 connect socket error");
                    323:             return (-1);
                    324:         }
                    325: 
                    326:         /* Setting X.25 out-of-band data handler */
                    327:         pid = getpid();
                    328:         if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
                    329:             perror("Setting process group id");
                    330:             return(-1);
                    331:         }    
                    332:         (VOID) signal(SIGURG,x25oobh);
                    333: 
                    334:         /* Set reverse charge call and closed user group if requested */
                    335:         bzero ((char *)&x25facil,sizeof(x25facil));
                    336:         if (revcall) x25facil.reverse_charge = revcall;
                    337:         if (closgr > -1) {
                    338:             x25facil.cug_req = 1;
                    339:             x25facil.cug_index = closgr;
                    340:         }
                    341:         if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
                    342:             perror ("Setting X.25 facilities");
                    343:             return (-1);
                    344:         }
                    345: 
                    346:         /*  Need X.25 header with bits Q and M */
                    347:         if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
                    348:             perror ("Setting X.25 header");
                    349:             return (-1);
                    350:         }
                    351: 
                    352:         /* Connects to remote host via SunLink X.25 */
                    353:         if (connect(ttyfd,&x25host,sizeof(x25host)) < 0) {
                    354:             debug(F101,"netopen connect errno","",errno);
                    355:             i = errno;
                    356:            if (errno) {
                    357:                 perror("netopen");
                    358:                 x25diag();
                    359:             }
                    360:             (VOID) close (ttyfd);
                    361:             ttyfd = -1;
                    362:             errno = i;
                    363:             return (-1);
                    364:         }
                    365:         
                    366:         /* Get X.25 link identification used for the connection */
                    367:         if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
                    368:             perror ("Getting X.25 link id");
                    369:             return (-1);
                    370:         }
                    371: 
                    372:         /* Get X.25 logical channel number used for the connection */
                    373:         if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
                    374:             perror ("Getting X.25 lcn");
                    375:             return (-1);
                    376:         }
                    377: 
                    378:         /* Get SunLink X.25 version */
                    379:         if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
                    380:             perror ("Getting SunLink X.25 version");
                    381:             return (-1);
                    382:         }
                    383:         ttnet = nett;                   /* Sunlink X.25 network */
                    384:         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
                    385:         if (*lcl < 0) *lcl = 1;         /* Local mode */
                    386:         return(0);
                    387:     } else /* Note that SUNX25 support can coexist with TCP/IP support. */
                    388: #endif /* SUNX25 */
                    389: /*
                    390:   Add support for other networks here.
                    391: */
                    392:     if (nett != NET_TCPB) return(-1);  /* BSD socket support */
                    393: 
                    394:     netclos();                         /* Close any previous connection. */
                    395:     strncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
                    396:     ttnproto = NP_NONE;                        /* No protocol selected yet. */
                    397:     debug(F110,"netopen namecopy",namecopy,0);
                    398: 
                    399:     p = namecopy;                      /* Was a service requested? */
                    400:     while (*p != '\0' && *p != ':') p++; /* Look for colon */
                    401:     if (*p == ':') {                   /* Have a colon */
                    402:        *p++ = '\0';                    /* Get service name or number */
                    403:     } else {                           /* Otherwise use telnet */
                    404:        p = "telnet";
                    405:     }
                    406:     debug(F110,"netopen service requested",p,0);
                    407:     if (isdigit(*p)) {                 /* Use socket number without lookup */
                    408:        service = &servrec;
                    409:        service->s_port = htons((unsigned short)atoi(p));
                    410:     } else {                           /* Otherwise lookup the service name */
                    411:        service = getservbyname(p, "tcp");
                    412:     }
                    413:     if (!service) {
                    414:        fprintf(stderr, "Cannot find port for service %s\n", p);
                    415: #ifdef MULTINET
                    416:        debug(F101,"netopen can't get service","",socket_errno);
                    417: #else
                    418:        debug(F101,"netopen can't get service","",errno);
                    419: #endif /* MULTINET */
                    420:        errno = 0;                      /* rather than mislead */
                    421:        return(-1);
                    422:     }
                    423:     /* Set up socket structure and get host address */
                    424: 
                    425:     bzero((char *)&saddr, sizeof(saddr));
                    426:     if ((host = gethostbyname(namecopy)) != NULL) {
                    427:        saddr.sin_family = host->h_addrtype;
                    428:        bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
                    429:     } else {
                    430: #ifdef INADDRX
                    431: /* inet_addr() is of type struct in_addr */
                    432:        struct in_addr ina;
                    433:        unsigned long uu;
                    434:        ina = inet_addr(namecopy);
                    435:        uu = *(unsigned long *)&ina;
                    436: #else
                    437: /* inet_addr() is unsigned long */
                    438:        unsigned long uu;
                    439:        uu = inet_addr(namecopy);
                    440: #endif /* INADDRX */
                    441:        if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1))
                    442:          saddr.sin_family = AF_INET;
                    443:        else {
                    444:          fprintf(stderr, "Can't get address for %s\n", namecopy);
                    445: #ifdef MULTINET
                    446:          debug(F101,"netopen can't get address","",socket_errno);
                    447: #else
                    448:          debug(F101,"netopen can't get address","",errno);
                    449: #endif /* MULTINET */
                    450:          errno = 0;                    /* rather than mislead */
                    451:          return(-1);
                    452:       }
                    453:     }
                    454: 
                    455:     /* Get a file descriptor for the connection. */
                    456: 
                    457:     saddr.sin_port = service->s_port;
                    458:     sprintf(ipaddr,"%s", inet_ntoa(saddr.sin_addr));
                    459:     if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr);
                    460:     
                    461: #ifdef EXCELAN
                    462:     send_socket.sin_family = AF_INET;
                    463:     send_socket.sin_addr.s_addr = 0;
                    464:     send_socket.sin_port = 0;
                    465:     if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
                    466:                &send_socket, SO_REUSEADDR)) < 0)
                    467: #else
                    468:     if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
                    469: #endif /* EXCELAN */
                    470:       {
                    471: #ifdef EXCELAN
                    472:        experror("TCP socket error");
                    473: #else
                    474: #ifdef MULTINET
                    475:        socket_perror("TCP socket error");
                    476:        debug(F101,"netopen socket error","",socket_errno);
                    477: #else
                    478:        perror("TCP socket error");
                    479:        debug(F101,"netopen socket error","",errno);
                    480: #endif /* MULTINET */
                    481: #endif /* EXCELAN */
                    482:        return (-1);
                    483:     }
                    484:     errno = 0;
                    485: 
                    486:     /* Now connect to the socket on the other end. */
                    487: 
                    488: #ifdef EXCELAN
                    489:     if (connect(ttyfd, &saddr) < 0)
                    490: #else
                    491:     if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
                    492: #endif /* EXCELAN */
                    493:       {
                    494:        i = errno;                      /* save error code */
                    495:        close(ttyfd);
                    496:        ttyfd = -1;
                    497:        errno = i;                      /* and report this error */
                    498: #ifdef EXCELAN
                    499:        if (errno) experror("netopen connect");
                    500: #else
                    501: #ifdef MULTINET
                    502:        debug(F101,"netopen connect error","",socket_errno);
                    503:        if (errno) socket_perror("netopen connect");
                    504: #else
                    505:        debug(F101,"netopen connect errno","",errno);
                    506: #endif /* MULTINET */
                    507: #endif /* EXCELAN */
                    508:        return(-1);
                    509:     }
                    510: #ifdef SO_OOBINLINE
                    511:     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); /* (void) */
                    512:     /* the symbol SO_OOBINLINE is not known to Ultrix 2.0 */
                    513:     /* it means "leave out of band data inline" */
                    514:     /* normal value is 0x0100 */
                    515:     /* better not to try this on systems where the symbol is undefined. */
                    516: #endif /* SO_OOBINLINE */
                    517: 
                    518:     /* See if the service is TELNET. */
                    519:     if ((x = ntohs((unsigned short)service->s_port)) == TELNET_PORT)
                    520:       ttnproto = NP_TELNET;            /* Yes, set global flag. */
                    521:     debug(F101,"netopen service","",x);
                    522:     ttnet = nett;                      /* TCP/IP (sockets) network */
                    523:     tn_init = 0;                       /* Telnet protocol not init'd yet */
                    524:     if (*lcl < 0) *lcl = 1;            /* Local mode. */
                    525:     return(0);                         /* Done. */
                    526: }
                    527: 
                    528: /*  N E T C L O S  --  Close current network connection.  */
                    529: 
                    530: int
                    531: netclos() {
                    532:     int x = 0;
                    533:     if (ttyfd < 0)                     /* Was open? */
                    534:       return(0);                       /* Wasn't. */
                    535:     if (ttyfd > -1)                    /* Was. */
                    536: #ifdef MULTINET
                    537:       x = socket_close(ttyfd);         /* Close it. */
                    538: #else
                    539:       x = close(ttyfd);
                    540: #endif /* MULTINET */
                    541:     ttyfd = -1;                                /* Mark it as closed. */
                    542:     tn_init = 0;                       /* Remember about telnet protocol... */
                    543:     *ipaddr = '\0';                    /* Zero the IP address string */
                    544:     return(x);
                    545: }
                    546: 
                    547: /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
                    548: /*
                    549:   Returns number of bytes waiting, or -1 if connection has been dropped.
                    550: */
                    551: int                                    /* Check how many bytes are ready */
                    552: nettchk() {                            /* for reading from network */
                    553: #ifdef MULTINET
                    554:     unsigned int count;
                    555:     int x, y;
                    556:     char c;
                    557: 
                    558:     socket_errno = 0;
                    559: /*
                    560:   Note: this socket_ioctl() call does NOT return an error if the
                    561:   connection has been broken.
                    562: */
                    563:     if (socket_ioctl(ttyfd,FIONREAD,&count) < 0) {
                    564:        debug(F101,"nettchk socket_ioctl error","",socket_errno);
                    565:        if (ttibn < 1) return(-1);
                    566:        else return(ttibn);
                    567:     } else {
                    568:        if (count == 0) {
                    569: /*
                    570:   Here we need to tell the difference between a 0 count on an active
                    571:   connection, and a 0 count because the remote end of the socket broke
                    572:   the connection.  There is no mechanism in TGV MultiNet to query the
                    573:   status of the connection, so we have to do a read.  -1 means there was
                    574:   no data available (socket_errno == EWOULDBLOCK), 0 means the connection
                    575:   is down.  But if, by chance, we actually get a character, we have to
                    576:   put it where it won't be lost.
                    577: */
                    578:            y = 1;                      /* Turn on nonblocking reads */
                    579:            socket_ioctl(ttyfd,FIONBIO,&y);
                    580:            x = socket_read(ttyfd,&c,1); /* Returns -1 if no data */
                    581:            y = 0;                      /* Turn them back off */
                    582:            socket_ioctl(ttyfd,FIONBIO,&y);
                    583:            if (x == 0) return(-1);     /* Connection is broken. */
                    584:            if (x == 1) {               /* Oops, actually got a byte? */
                    585:                ttibuf[ttibp+ttibn] = c;
                    586:                ttibn++;                /* Add it to the buffer. */
                    587:            }
                    588:        }
                    589:        debug(F101,"nettchk count","",count);
                    590:        return(count + ttibn);
                    591:     }  
                    592: #else
                    593: /*
                    594:   Note, for regular UNIX TCP/IP connections, might be able to use the
                    595:   same technique as for MultiNet.  But as yet there is no need for it.
                    596: */
                    597:     return(0);
                    598: #endif /* MULTINET */
                    599: }
                    600: 
                    601: /*  N E T T I N C --  Input character from network */
                    602: 
                    603: int                    
                    604: netinc(timo) int timo; {
                    605: #ifdef MULTINET
                    606:     int x; unsigned char c;            /* The locals. */
                    607: 
                    608:     if (ttibn > 0) {                   /* Something in internal buffer? */
                    609:        debug(F100,"netinc char in buf","",0); /* Yes. */
                    610:        x = 0;                          /* Success. */
                    611:     } else {                           /* Else must read from network. */
                    612:        x = -1;                         /* Assume failure. */
                    613:        debug(F101,"netinc goes to net, timo","",timo);
                    614:        if (timo <= 0) {                /* Untimed case. */
                    615:            while (1) {                 /* Wait forever if necessary. */
                    616:                if (ttbufr() < 0)       /* Refill buffer. */
                    617:                  break;                /* Error, fail. */
                    618:                if (ttibn > 0) {        /* Success. */
                    619:                    x = 0;
                    620:                    break;
                    621:                }
                    622:            }
                    623:        } else {                        /* Timed case... */
                    624:            saval = signal(SIGALRM,ttimoff); /* Enable timer interrupt */
                    625:            alarm(timo);                /* for requested interval. */
                    626:            if (setjmp(njbuf)) {        /* Timer went off? */
                    627:                x = -1;                 /* Yes, fail. */
                    628:            } else {
                    629:                while (1) {
                    630:                    if (ttbufr() < 0)   /* Keep trying to refill it. */
                    631:                      break;            /* Till we get an error. */
                    632:                    if (ttibn > 0) {    /* Or we get a character. */
                    633:                        x = 0;
                    634:                        break;
                    635:                    }
                    636:                }
                    637:            }
                    638:            ttimoff();                  /* Timer off. */
                    639:        }
                    640:     }
                    641:     if (x < 0) {                       /* Return -1 if we failed. */
                    642:        debug(F100,"netinc timed out","",0);
                    643:        return(-1);
                    644:     } else {                           /* Otherwise */
                    645:        ttibn--;                        /* Return what we got. */
                    646:        c = ttibuf[ttibp++];
                    647:        debug(F101,"netinc returning","",c);
                    648:        return((c & 0xff));
                    649:     }
                    650: #else /* Not MULTINET */
                    651:     return(-1);
                    652: #endif /* MULTINET */
                    653: }
                    654: 
                    655: /*  N E T T O L  --  Output a string of bytes to the network  */
                    656: /*
                    657:   Call with s = pointer to string, n = length.
                    658:   Returns number of bytes actuall written on success, or
                    659:   -1 on i/o error, -2 if called improperly.
                    660: */
                    661: int
                    662: nettol(s,n) char *s; int n; {
                    663: #ifdef MULTINET
                    664:     int count;
                    665:     if (ttnet == NET_TCPB) {
                    666:        if ((count = socket_write(ttyfd,s,n)) < 1) {
                    667:            debug(F101,"nettol socket_write error","",socket_errno);
                    668:            return(-1);
                    669:        }
                    670:        debug(F111,"nettol socket_write",s,count);
                    671:        return(count);
                    672:     } else return(-2);
                    673: #else
                    674:     return(-2);
                    675: #endif /* MULTINET */
                    676: }
                    677: 
                    678: /*  N E T T O C  --   Output character to network */
                    679: /*
                    680:   Call with character to be transmitted.
                    681:   Returns 0 if transmission was successful, or
                    682:   -1 upon i/o error, or -2 if called improperly.
                    683: */
                    684: int                    
                    685: #ifdef CK_ANSIC
                    686: nettoc(char c)
                    687: #else
                    688: nettoc(c) char c;
                    689: #endif /* CK_ANSIC */
                    690: /* nettoc */ {
                    691: #ifdef MULTINET
                    692:     unsigned char cc;
                    693:     cc = c;
                    694:     if (ttnet == NET_TCPB) {
                    695:        debug(F101,"nettoc cc","",cc);
                    696:        if (socket_write(ttyfd,&cc,1) < 1) {
                    697:            debug(F101,"nettoc socket_write error","",socket_errno);
                    698:            return(-1);
                    699:        }
                    700:        debug(F101,"nettoc socket_write","", cc);
                    701:        return(0);
                    702:     } else return(-2);
                    703: #else
                    704:     return(-2);
                    705: #endif /* MULTINET */
                    706: }
                    707: 
                    708: /*  N E T F L U I  --  Flush network input buffer  */
                    709: 
                    710: int
                    711: netflui() {
                    712:     int n;
                    713:     if ((n = nettchk()) > 0) {
                    714: #ifdef MULTINET
                    715:        char c;
                    716:        if (ttnet == NET_TCPB)
                    717:          while ((n--) && socket_read(ttyfd,&c,1) > 1) ;
                    718: #endif /* MULTINET */
                    719:     }
                    720: #ifdef MULTINET
                    721:     ttibn = ttibp = 0;                 /* Also flush internal buffer. */
                    722: #endif /* MULTINET */
                    723:     return(0);
                    724: }
                    725: 
                    726: #ifdef TNCODE                          /* Compile in telnet support code */
                    727: 
                    728: /* TCP/IP Telnet negotiation support code */
                    729: 
                    730: static int sgaflg = 0;                 /* telnet SGA flag */
                    731: static int wttflg = 0;                 /* telnet terminal type flag */
                    732: 
                    733: #ifndef TELCMDS
                    734: char *telcmds[] = {
                    735:     "SE", "NOP", "DMARK", "BRK",  "IP",   "AO", "AYT",  "EC",
                    736:     "EL", "GA",  "SB",    "WILL", "WONT", "DO", "DONT", "IAC",
                    737: };
                    738: #endif /* TELCMDS */
                    739: 
                    740: #ifndef TELOPTS
                    741: char *telopts[] = {
                    742:        "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME",
                    743:        "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP",
                    744:        "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS",
                    745:        "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
                    746:        "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
                    747:        "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD"
                    748: #ifdef TELOPT_TUID
                    749:        ,"TACACS UID"
                    750: #ifdef TELOPT_OUTMRK
                    751:        ,"OUTPUT MARKING"
                    752: #ifdef TELOPT_TTYLOC
                    753:        ,"TTYLOC"
                    754: #ifdef TELOPT_3270REGIME
                    755:        ,"3270 REGIME"
                    756: #ifdef TELOPT_X3PAD
                    757:        ,"X.3 PAD"
                    758: #ifdef TELOPT_NAWS
                    759:        ,"NAWS"
                    760: #ifdef TELOPT_TSPEED
                    761:        ,"TSPEED"
                    762: #ifdef TELOPT_LFLOW
                    763:        ,"LFLOW"
                    764: #ifdef TELOPT_LINEMODE
                    765:        ,"LINEMODE"
                    766: #endif
                    767: #endif
                    768: #endif
                    769: #endif
                    770: #endif
                    771: #endif
                    772: #endif
                    773: #endif
                    774: #endif
                    775: };
                    776: #endif /* TELOPTS */
                    777: 
                    778: int ntelopts = sizeof(telopts) / sizeof(char *);
                    779: #endif /* TNCODE */
                    780: 
                    781: 
                    782: /* Send network BREAK */
                    783: /*
                    784:   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
                    785: */
                    786: int
                    787: netbreak() {
                    788:     if (ttnet == NET_TCPB) {
                    789:        if (ttnproto == NP_TELNET) {
                    790: #ifdef TNCODE
                    791:            if (ttoc(IAC) < 0) return(-1);
                    792:            if (ttoc(BREAK) < 0) return(-1);
                    793:            debug(F101,"telnet BREAK ok","",BREAK);    
                    794:            return(1);
                    795: #else
                    796:            debug(F100,"netbreak no TNCODE","",0);
                    797:            return(0);
                    798: #endif /* TNCODE */
                    799:        }
                    800:        /* Insert other TCP/IP protocols here */
                    801:     }
                    802:     /* Insert other networks here */
                    803:     return(0);
                    804: }
                    805: 
                    806: /* Send a telnet option, avoid loops. */
                    807: /* Returns 1 if command was sent, 0 if not, -1 on error */
                    808: 
                    809: int
                    810: tn_sopt(cmd,opt) int cmd, opt; {       /* TELNET SEND OPTION */
                    811:     if (ttnet != NET_TCPB) return(0);  /* Must be TCP/IP */
                    812:     if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
                    813: #ifdef TNCODE
                    814:     if (ttoc(IAC) < 0)                 /* Send Interpret As Command (IAC) */
                    815:       return(-1);
                    816:     if (ttoc(cmd) < 0)                 /* Command (WILL, WONT, DO, DONT) */
                    817:       return(-1);
                    818:     if (ttoc(opt) < 0)                 /* Option */
                    819:       return(-1);
                    820:     debug(F111,"telnet cmd >",telcmds[cmd - SE],cmd);
                    821:     debug(F111,"telnet opt >",
                    822:          (opt < ntelopts) ? telopts[opt] : "UNKNOWN", opt );
                    823:     if (debses && cmd != SB)
                    824:       printf("[%s %s]",telcmds[cmd - SE],
                    825:             (opt < ntelopts) ? telopts[opt] : "UNKNOWN");
                    826:     return(1);
                    827: #else
                    828:     debug(F100,"tn_sopt no TNCODE","",0);
                    829:     return(0);
                    830: #endif /* TNCODE */
                    831: }
                    832: 
                    833: /* Initialize a telnet connection. */
                    834: /* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */
                    835: 
                    836: int
                    837: tn_ini() {
                    838: #ifndef TNCODE
                    839:     debug(F100,"tn_ini no TNCODE","",0);
                    840:     return(0);
                    841: #else /* TELNET protocol support */
                    842:     debug(F101,"tn_ini ttnproto","",ttnproto);
                    843:     debug(F101,"tn_ini tn_init","",tn_init);
                    844: 
                    845:     if (ttnet != NET_TCPB)             /* Make sure connection is TCP/IP. */
                    846:       return(0);
                    847:     if (tn_init)                       /* Have we done this already? */
                    848:       return(0);                       /* Don't do it again. */
                    849:     duplex = 1;                                /* Assume local echo. */
                    850:     sgaflg = 0;                                /* Assume Go-Ahead suppressed. */
                    851:     wttflg = 0;                                /* Did not send WILL TERM TYPE yet. */
                    852:     if (ttnproto == NP_NONE) {         /* If not talking to a telnet port, */
                    853:        ttnproto = NP_TELNET;           /* pretend it's telnet anyway, */
                    854:        tn_init = 1;                    /* but don't send initial options. */
                    855:        debug(F100,"tn_ini skipping telnet negotiations","",0);
                    856:        return(0);
                    857:     }
                    858:     /* Talking to telnet port, so send WILL TERMINAL TYPE and DO SGA */
                    859: 
                    860:     if (tn_sopt(WILL,TELOPT_TTYPE) < 0)        /* Will send terminal type. */
                    861:       return(-1);
                    862:     wttflg = 1;                                /* Remember I said I would. */
                    863:     if (tn_sopt(DO,TELOPT_SGA) < 0)    /* Please suppress go-ahead. */
                    864:       return(-1);
                    865: #ifdef COMMENT
                    866:     if (tn_sopt(DO,TELOPT_ECHO) < 0)   /* Ask the server to echo, since */
                    867:       return(-1);                      /* I'm assuming it will. */
                    868: #endif /* COMMENT */
                    869:     tn_init = 1;                       /* Set telnet-initialized flag. */
                    870: 
                    871:     /* Don't send anthing else! */
                    872: 
                    873:     debug(F101,"tn_ini duplex","",duplex);
                    874:     return(1);
                    875: #endif /* TNCODE */
                    876: }
                    877: 
                    878: /*
                    879:   Process in-band Telnet negotiation characters from the remote host.
                    880:   Call with the telnet IAC character and the current duplex setting
                    881:   (0 = remote echo, 1 = local echo).
                    882:   Returns:
                    883:     3 if server has sent us a quoted IAC
                    884:     2 if local echo must be changed to remote
                    885:     1 if remote echo must be changed to local
                    886:     0 if nothing happens or no action necessary
                    887:    -1 on failure (= internal or i/o error)
                    888: */
                    889: 
                    890: #define TSBUFSIZ 41
                    891: char sb[TSBUFSIZ];                     /* Buffer for subnegotiations */
                    892: 
                    893: int
                    894: #ifdef CK_ANSIC                                /* TELNET DO OPTION */
                    895: tn_doop(CHAR z, int echo)
                    896: #else
                    897: tn_doop(z, echo) CHAR z; int echo;
                    898: #endif /* CK_ANSIC */
                    899: /* tn_doop */ {
                    900:     int c, x, y, e, n, flag;
                    901: 
                    902: #ifndef TNCODE
                    903:     debug(F100,"tn_doop no TNCODE","",0);
                    904:     return(0);
                    905: #else
                    906:     if (z != IAC) {
                    907:        debug(F101,"tn_doop bad call","",z);
                    908:        return(-1);
                    909:     }
                    910:     if (ttnet != NET_TCPB) return(0);
                    911:     if (ttnproto != NP_TELNET) return(0);      /* Check protocol */
                    912: /*
                    913:   This is a weakness.  Because this module uses ttinc(), it prevents any
                    914:   code that uses this routine from using any kind of buffering strategy.
                    915:   Also, there's no reason why this module should have to know anything about
                    916:   the session log.  It would be better to pass a character input function as
                    917:   an argument to this routine -- that function could worry about buffering,
                    918:   logging, etc.
                    919: */
                    920: 
                    921: /* Have IAC, read command character. */
                    922: 
                    923:     c = ttinc(0) & 0xff;               /* Read command character */
                    924:     if (seslog) {                      /* Copy to session log, if any. */
                    925:        if (zchout(ZSFILE,z) < 0) seslog = 0; /* Log the IAC. */
                    926:        else if (zchout(ZSFILE,c) < 0) seslog = 0; /* Log the command. */
                    927:     }
                    928:     debug(F111,"telnet cmd <",telcmds[c - SE],c); /* Debug log. */
                    929: 
                    930:     if (c == IAC) return(3);           /* Quoted IAC */
                    931:     if (c < SB) return(0);             /* Other command with no arguments. */
                    932: 
                    933: /* SB, WILL, WONT, DO, or DONT need more bytes... */
                    934: 
                    935:     if ((x = ttinc(0)) < 0) return(-1); /* Get the option. */
                    936:     x &= 0xff;                         /* Trim to 8 bits. */
                    937: 
                    938:     debug(F111,"telnet opt <",
                    939:          (x < ntelopts) ? telopts[x] : "UNKNOWN", x );
                    940:     if (seslog)                                /* Session log */
                    941:       if (zchout(ZSFILE,x) < 0) seslog = 0;
                    942: 
                    943:     /* Now handle the command */
                    944: 
                    945:     if (debses && c != SB)             /* Debug to screen. */
                    946:       printf("<%s %s>",telcmds[c-SE],
                    947:             (x < ntelopts) ? telopts[x] : "UNKNOWN" );
                    948:     switch (x) {
                    949:       case TELOPT_ECHO:                        /* ECHO negotiation. */
                    950:        switch (c) {                    /* Command */
                    951:          case WILL:                    /* Host says it will echo. */
                    952:            if (echo)                   /* Only reply if change required. */
                    953:              return((tn_sopt(DO,x) < 0) ? -1 : 2); /* Please do. */
                    954:            else return(0);             /* Otherwise no change. */
                    955:          case WONT:                    /* Host says it won't echo. */
                    956:            if (!echo)                  /* If I'm full duplex */
                    957:              return ((tn_sopt(DONT,x) < 0) ? -1 : 1); /* Switch to half */
                    958:            else return(0);             /* Otherwise, no change.  */
                    959:          case DO:                      /* Host wants me to echo */
                    960:            if (tn_sopt(WONT,x) < 0)    /* but the client never echoes */
                    961:              return(-1);               /* back to the server. */
                    962:          default:                      /* Don't reply to anything else */
                    963:            return(0);
                    964:        }
                    965: 
                    966:       case TELOPT_SGA:                 /* Suppress Go-Ahead */
                    967:        switch (c) {                    /* Command... */
                    968:          case WONT:                    /* Host says it won't. */
                    969:            if (!sgaflg) {
                    970:                sgaflg = 1;             /* Remember. */
                    971:                if (tn_sopt(DONT,x) < 0) /* acknowledge, */
                    972:                  return(-1);
                    973:            }
                    974:            return(echo ? 0 : 1);       /* Switch to half duplex */
                    975:          case WILL:                    /* Server says it will SGA */
                    976:            if (sgaflg) {               /* ACK only if necessary */
                    977:                if (tn_sopt(DO,x) < 0)
                    978:                  return(-1);
                    979:                sgaflg = 0;             /* Remember new SGA state. */
                    980:            }
                    981:            return(0);                  /* But don't change echo state. */
                    982:        }
                    983: 
                    984: #ifdef TELOPT_TTYPE
                    985:       case TELOPT_TTYPE:               /* Terminal Type */
                    986:        switch (c) {
                    987:          case DO:                      /* DO terminal type. */
                    988:            if (wttflg == 0) {          /* If I haven't said so before, */
                    989:                if (tn_sopt(WILL,x) < 0) /* say I'll send it if asked. */
                    990:                  return(-1);
                    991:                wttflg++;
                    992:            }
                    993:            return(0);
                    994:          case SB:
                    995:            debug(F100,"telnet subnegotiation:","",0);
                    996:            n = flag = 0;               /* Flag for when done reading SB */
                    997:            while (n < TSBUFSIZ) {      /* Loop looking for IAC SE */
                    998:                if ((y = ttinc(0)) < 0)
                    999:                  return(-1);
                   1000:                y &= 0xff;              /* Make sure it's just 8 bits. */
                   1001:                sb[n++] = y;            /* Save what we got in buffer. */
                   1002:                if (seslog)             /* Log it if logging. */
                   1003:                  if (zchout(ZSFILE,y) < 0)
                   1004:                    seslog = 0;
                   1005:                if (y == IAC) {         /* If this is an IAC */
                   1006:                    flag = 1;           /* set the flag. */
                   1007:                } else {                /* Otherwise, */
                   1008:                    if (flag && y == SE) /* if this is SE which immediately */
                   1009:                      break;            /* follows IAC, we're done. */
                   1010:                    else flag = 0;      /* Otherwise turn off flag. */
                   1011:                }
                   1012:                debug(F111,"telnet subopt <","",y);
                   1013:                }
                   1014:            if (!flag) return(-1);      /* Make sure we got a valid SB */
                   1015:            if (debses) {               /* Debug to screen. */
                   1016:                int i;
                   1017:                printf("<SB %s ",telopts[TELOPT_TTYPE]);
                   1018:                for (i = 0; i < n-2; i++) printf("%02x",sb[i]);
                   1019:                printf(" IAC SE>");
                   1020:            }       
                   1021:            debug(F101,"telnet suboption","",sb[0]);
                   1022:            if (sb[0] == 1) {           /* SEND terminal type? */
                   1023:                if (tn_sttyp() < 0)     /* Yes, so send it. */
                   1024:                  return(-1);
                   1025:            }
                   1026:          default:                      /* Others, ignore */
                   1027:            return(0);
                   1028:        }
                   1029: #endif /* TELOPT_TTYPE */
                   1030: 
                   1031:       default:                         /* All others: refuse */
                   1032:        switch(c) {
                   1033:          case WILL:                    /* You will? */
                   1034:            if (tn_sopt(DONT,x) < 0)    /* Please don't. */
                   1035:              return(-1);
                   1036:            break;
                   1037:          case DO:                      /* You want me to? */
                   1038:            if (tn_sopt(WONT,x) < 0)    /* I won't. */
                   1039:              return(-1);
                   1040:            break;
                   1041:          case DONT:                    /* You don't want me to? */
                   1042:            if (tn_sopt(WONT,x) < 0)    /* I won't. */
                   1043:              return(-1);
                   1044:          case WONT:                    /* You won't? */
                   1045:            break;                      /* Good. */
                   1046:          }
                   1047:        return(0);
                   1048:     }
                   1049: #endif /* TNCODE */
                   1050: }
                   1051: 
                   1052: /* Telnet send terminal type */
                   1053: /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
                   1054: 
                   1055: int
                   1056: tn_sttyp() {                           /* Send telnet terminal type. */
                   1057: #ifndef TNCODE
                   1058:     debug(F100,"tn_sttyp no TNCODE","",0);
                   1059:     return(0);
                   1060: #else
                   1061:     char *ttn; int ttl;                        /* Name & length of terminal type. */
                   1062: 
                   1063:     if (ttnet != NET_TCPB) return(0);
                   1064:     if (ttnproto != NP_TELNET) return(0);
                   1065:     ttn = getenv("TERM");              /* Get it from the environment. */
                   1066:     if ((ttn == ((char *)0)) || ((ttl = (int)strlen(ttn)) >= TSBUFSIZ)) {
                   1067:        ttn = "UNKNOWN";
                   1068:        ttl = 7;
                   1069:     }
                   1070:     strcpy(sb,ttn);                    /* Copy to subnegotiation buffer */
                   1071:     ttn = sb;                          /* Point back to beginning */
                   1072:     if (tn_sopt(SB,TELOPT_TTYPE) < 0)  /* Send: Terminal Type */
                   1073:       return(-1);
                   1074:     if (ttoc((char) 0))                        /* IS... */
                   1075:       return(-1);
                   1076:     while (*ttn) {                     /* name of terminal */
                   1077:        if (islower(*ttn)) *ttn = toupper(*ttn); /* converted to uppercase. */
                   1078:        ttoc(*ttn++);
                   1079:     }
                   1080:     if (ttoc(IAC) < 0)                 /* Terminate the subnegotiation. */
                   1081:       return(-1);
                   1082:     if (ttoc(SE) < 0)
                   1083:       return(-1);
                   1084:     debug(F111,"telnet SB sent ttype",sb,ttl);
                   1085:     if (debses)                                /* Debug to screen. */
                   1086:       printf("[SB TERMINAL TYPE 00 %s IAC SE]",sb);
                   1087:     return(1);
                   1088: #endif /* TNCODE */
                   1089: }
                   1090: 
                   1091: #ifdef SUNX25
                   1092: /*
                   1093:   SunLink X.25 support by Marcello Frutig, Catholic University,
                   1094:   Rio de Janeiro, Brazil, 1990.
                   1095: */
                   1096: 
                   1097: /* PAD X.3, X.28 and X.29 support */
                   1098: 
                   1099: static CHAR x29err [MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
                   1100: 
                   1101: 
                   1102: /* Initialize PAD */
                   1103: 
                   1104: extern CHAR padparms[MAXPADPARMS+1];
                   1105: 
                   1106: VOID
                   1107: initpad() {
                   1108:   padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
                   1109:   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
                   1110:   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
                   1111:   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
                   1112:   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
                   1113:   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
                   1114:   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
                   1115:   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
                   1116:   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
                   1117:   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
                   1118:   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
                   1119:   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
                   1120:   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
                   1121:   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
                   1122:   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
                   1123:   padparms[PAD_EDITING]                = 1;  /* can edit */
                   1124:   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
                   1125:   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
                   1126:   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
                   1127: }
                   1128: 
                   1129: 
                   1130: /* Set PAD parameters */
                   1131: 
                   1132: VOID
                   1133: setpad(s,n) CHAR *s; int n; {
                   1134:     int i;
                   1135:     CHAR *ps = s;
                   1136: 
                   1137:     for (i = 0; i < n; i++) {
                   1138:         if (*ps > MAXPADPARMS)
                   1139:          x29err[i+2] = *ps;
                   1140:         else
                   1141:          padparms[*ps] = *(ps+1);
                   1142:         ps += 2;
                   1143:     }
                   1144: }
                   1145: 
                   1146: /* Read PAD parameters */
                   1147: 
                   1148: VOID
                   1149: readpad(s,n,r) CHAR *s; int n; CHAR *r; {
                   1150:     int i;
                   1151:     CHAR *ps = s;
                   1152:     CHAR *pr = r;
                   1153:     
                   1154:     *pr++ = X29_PARAMETER_INDICATION;
                   1155:     for (i = 0; i < n; i++, ps++) {
                   1156:          if (*ps > MAXPADPARMS) {
                   1157:              x29err[i+2] = *ps++;
                   1158:          } else {
                   1159:              *pr++ = *ps;
                   1160:              *pr++ = padparms[*ps++];
                   1161:          }
                   1162:     }
                   1163: }
                   1164: 
                   1165: int
                   1166: qbitpkt(s,n) CHAR *s; int n; {
                   1167:     CHAR *ps = s;
                   1168:     int x29cmd = *ps;
                   1169:     CHAR *psa = s+1; 
                   1170:     CHAR x29resp[(MAXPADPARMS*2)+1];
                   1171: 
                   1172:     switch (x29cmd) {
                   1173: 
                   1174:         case X29_SET_PARMS:
                   1175:             setpad (ps+1,n/2);
                   1176:             if ((int)strlen(x29err) > 2) {
                   1177:                 ttol (x29err,(int)strlen(x29err));
                   1178:                 x29err[2] = '\0';
                   1179:             } 
                   1180:             return (-2);
                   1181:         case X29_READ_PARMS:
                   1182:             readpad (ps+1,n/2,x29resp);
                   1183:             setqbit ();
                   1184:             ttol (x29resp,n+1);
                   1185:             if ((int)strlen(x29err) > 2) {
                   1186:                 ttol (x29err,(int)strlen(x29err));
                   1187:                 x29err[2] = '\0';
                   1188:             } 
                   1189:             resetqbit();
                   1190:             break;
                   1191:         case X29_SET_AND_READ_PARMS:
                   1192:             setpad (ps+1,n/2);
                   1193:             readpad (ps+1,n/2,x29resp);
                   1194:             setqbit();
                   1195:             ttol (x29resp,n+1);
                   1196:             if ((int)strlen(x29err) > 2) {
                   1197:                 ttol (x29err,(int)strlen(x29err));
                   1198:                 x29err [2] = '\0';
                   1199:             }
                   1200:             resetqbit();
                   1201:             return (-2);
                   1202:         case X29_INVITATION_TO_CLEAR:
                   1203:             (VOID) x25clear();
                   1204:             return (-1) ;
                   1205:         case X29_INDICATION_OF_BREAK:
                   1206:            break;
                   1207:     }
                   1208:     return (0);
                   1209: }
                   1210: 
                   1211: /* PAD break action processor */
                   1212: 
                   1213: VOID
                   1214: breakact() {
                   1215:     extern char x25obuf[MAXOX25];
                   1216:     extern int obufl;
                   1217:     extern int active;
                   1218:     extern unsigned char tosend;
                   1219:     static CHAR indbrk[3] = {
                   1220:        X29_INDICATION_OF_BREAK,
                   1221:        PAD_SUPPRESSION_OF_DATA,
                   1222:        1
                   1223:     };
                   1224:     CHAR intudat, cause, diag;
                   1225: 
                   1226:     if (x25stat() < 0) return(0);   /* Ignore if no virtual call established */
                   1227: 
                   1228:     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
                   1229:         if (ttol(x25obuf,obufl) < 0) {
                   1230:             perror ("\r\nCan't send characters");
                   1231:             active = 0;
                   1232:         } else {
                   1233:             bzero (x25obuf,sizeof(x25obuf));
                   1234:             obufl = 0;
                   1235:             tosend = 0;
                   1236:         };
                   1237: 
                   1238:     switch (padparms[PAD_BREAK_ACTION]) {
                   1239: 
                   1240:        case 0 : break;                 /* do nothing */
                   1241:        case 1 : /* send interrupt packet with interrupt user data field = 1 */
                   1242:                intudat = 1;
                   1243:                 x25intr (intudat);
                   1244:                 break;
                   1245:        case 2 : /* send reset packet with cause and diag = 0 */
                   1246:                cause = diag = 0;
                   1247:                 x25reset (cause,diag); 
                   1248:                 break;
                   1249:        case 5 : /* send interrupt packet with interrupt user data field = 0 */
                   1250:                intudat = 0;
                   1251:                 x25intr (intudat) ;
                   1252:                 setqbit ();
                   1253:                /* send indication of break without a parameter field */
                   1254:                 ttoc(X29_INDICATION_OF_BREAK);
                   1255:                 resetqbit ();
                   1256:                 break;
                   1257:        case 8 : active = 0;            /* leave data transfer */
                   1258:                 conol ("\r\n");
                   1259:                 break;
                   1260:        case 21: /* send interrupt packet with interrupt user data field = 0 */
                   1261:                intudat = 0;
                   1262:                 x25intr (intudat);
                   1263:                 setpad (indbrk+1,2);   /* set pad to discard input */
                   1264:                 setqbit ();
                   1265:                /* send indication of break with parameter field */
                   1266:                 ttol (indbrk,sizeof(indbrk)); 
                   1267:                 resetqbit ();
                   1268:                 break;
                   1269:      }
                   1270: }
                   1271: 
                   1272: /* X.25 support functions */
                   1273: 
                   1274: X25_CAUSE_DIAG diag;
                   1275: 
                   1276: /*
                   1277:   Convert a null-terminated string representing an X.121 address
                   1278:   to a packed BCD form.
                   1279: */
                   1280: 
                   1281: int
                   1282: pkx121(str,bcd) char *str; CHAR *bcd; {
                   1283:     int i, j;
                   1284:     u_char c;
                   1285: 
                   1286:     i = j = 0;
                   1287:     while (str[i]) {
                   1288:         if ( i >= 15 || str [i] < '0' || str [i] > '9' )
                   1289:          return (-1);
                   1290:         c = str [i] - '0';
                   1291:         if ( i & 1 )
                   1292:          bcd [j++] |= c;
                   1293:         else
                   1294:          bcd [j] = c << 4;  
                   1295:         i++;
                   1296:     }
                   1297:     return (i);
                   1298: }
                   1299: 
                   1300: /* Reads and prints X.25 diagnostic */
                   1301: 
                   1302: int
                   1303: x25diag () {
                   1304:     int i;
                   1305: 
                   1306:     bzero ((char *)&diag,sizeof(diag));
                   1307:     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
                   1308:         perror ("Reading X.25 diagnostic");
                   1309:         return(-1); 
                   1310:     }
                   1311:     if (diag.datalen > 0) {
                   1312:         printf ("X.25 Diagnostic :");
                   1313:         for (i = 0; i < diag.datalen; i++) printf (" %02x",diag.data[i]);
                   1314:         printf ("\r\n");
                   1315:     }
                   1316:     return(0);
                   1317: }
                   1318: 
                   1319: /* X.25 Out-of-Band Signal Handler */
                   1320: 
                   1321: VOID
                   1322: x25oobh() {
                   1323:     int oobtype;
                   1324:     u_char oobdata;
                   1325: 
                   1326:     (VOID) signal(SIGURG,x25oobh);
                   1327:     do {
                   1328:         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
                   1329:             perror ("Getting signal type");
                   1330:             return;
                   1331:         }
                   1332:         switch (oobtype) {
                   1333:          case INT_DATA:
                   1334:            if (recv(ttyfd,oobdata,1,MSG_OOB) < 0) {
                   1335:                perror ("Receiving X.25 interrupt data");
                   1336:                return;
                   1337:            }
                   1338:            printf ("\r\nInterrupt received, data = %d\r\n", oobdata);
                   1339:            break;
                   1340:          case VC_RESET:
                   1341:            printf ("\r\nVirtual circuit reset\r\n");
                   1342:            x25diag ();
                   1343:            break;
                   1344:          case N_RESETS:
                   1345:            printf ("\r\nReset timeout\r\n");
                   1346:            break;
                   1347:          case N_CLEARS:
                   1348:            printf ("\r\nClear timeout\r\n");
                   1349:            break;
                   1350:          case MSG_TOO_LONG:
                   1351:            printf ("\r\nMessage discarded, too long\r\n");
                   1352:            break;
                   1353:          default:
                   1354:            if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
                   1355:            break;
                   1356:        }
                   1357:     } while (oobtype);
                   1358: }
                   1359: 
                   1360: /* Send a X.25 interrupt packet */
                   1361: 
                   1362: int
                   1363: #ifdef CK_ANSIC
                   1364: x25intr(char intr)
                   1365: #else
                   1366: x25intr(intr) char intr;
                   1367: #endif /* CK_ANSIC */
                   1368: /* x25intr */ {
                   1369:     if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
                   1370:     debug(F100,"X.25 intr","",0);
                   1371:     return(0);
                   1372: }
                   1373: 
                   1374: /* Reset X.25 virtual circuit */
                   1375: int
                   1376: #ifdef CK_ANSIC
                   1377: x25reset(char cause, char diagn)
                   1378: #else
                   1379: x25reset(cause, diagn) char cause; char diagn;
                   1380: #endif /* CK_ANSIC */
                   1381: /* x25reset */ {
                   1382:     bzero ((char *)&diag,sizeof(diag));
                   1383:     diag.flags   = 0;
                   1384:     diag.datalen = 2;
                   1385:     diag.data[0] = cause;
                   1386:     diag.data[1] = diagn;
                   1387:     if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
                   1388:       return(-1);
                   1389:     debug(F100,"X.25 reset","",0);
                   1390:     return(0);
                   1391: }
                   1392: 
                   1393: /* Clear X.25 virtual circuit */
                   1394: int
                   1395: x25clear() {
                   1396:     int i;
                   1397:     debug(F100,"X.25 clear","",0);
                   1398:     bzero ((char *)&diag,sizeof(diag));
                   1399:     diag.flags = (1 << DIAG_TYPE);
                   1400:     diag.datalen = 2;
                   1401:     diag.data[0] = 0;
                   1402:     diag.data[1] = 0;
                   1403:     ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
                   1404:     return(ttclos(0));                 /* Close socket */
                   1405: }
                   1406: 
                   1407: /* X.25 status */
                   1408: int
                   1409: x25stat() {
                   1410:     if (ttyfd < 0) return (-1);
                   1411:     return(0);
                   1412: }
                   1413: 
                   1414: /* Set Q_BIT on */
                   1415: VOID
                   1416: setqbit() {
                   1417:     static int qbiton = 1 << Q_BIT;
                   1418:     ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
                   1419: }
                   1420: 
                   1421: /* Set Q_BIT off */
                   1422: VOID
                   1423: resetqbit() {
                   1424:     static int qbitoff = 0;
                   1425:     ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
                   1426: }
                   1427: 
                   1428: /* Read n characters from X.25 circuit into buf */
                   1429: 
                   1430: int
                   1431: x25xin(n,buf) int n; CHAR *buf; {
                   1432:     register int x, c;
                   1433:     int qpkt;
                   1434: 
                   1435:     do {
                   1436:        x = read(ttyfd,buf,n);
                   1437:        if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
                   1438:            /* If return -1 : invitation to clear; -2 : PAD changes */
                   1439:            if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
                   1440:            qpkt = 1;
                   1441:        } else qpkt = 0;
                   1442:     } while (qpkt);
                   1443:     if (x > 0) buf[x] = '\0';
                   1444:     if (x < 0) x = -1;
                   1445:     return(x);
                   1446: }
                   1447: 
                   1448: /* X.25 read a line */
                   1449: 
                   1450: int
                   1451: #ifdef PARSENSE
                   1452: #ifdef CK_ANSIC
                   1453: x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
                   1454: #else
                   1455: x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
                   1456: #endif /* CK_ANSIC */
                   1457: #else /* not PARSENSE */
                   1458: #ifdef CK_ANSIC
                   1459: x25inl(CHAR *dest, int max,int timo, CHAR eol)
                   1460: #else
                   1461: x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
                   1462: #endif /* __SDTC__ */
                   1463: #endif /* PARSENSE */
                   1464: /* x25inl */ {
                   1465:     CHAR *pdest;
                   1466:     int pktype, goteol, rest, n;
                   1467:     int i, flag = 0;
                   1468:     extern int ttprty;
                   1469:     int ttpmsk;
                   1470:         
                   1471:     ttpmsk = (ttprty) ? 0177 : 0377;   /* Set parity stripping mask */
                   1472: 
                   1473:     debug(F101,"x25inl max","",max);
                   1474:     debug(F101,"x25inl eol","",eol);
                   1475:     pdest  = dest;
                   1476:     rest   = max;
                   1477:     goteol = 0;
                   1478:     do {
                   1479:        n = read(ttyfd,pdest,rest); 
                   1480:        n--;
                   1481:        pktype = *pdest & 0x7f;
                   1482:        switch (pktype) {
                   1483:          case 1 << Q_BIT:
                   1484:            if (qbitpkt(pdest+1,--n) < 0) return(-2);
                   1485:            break;
                   1486:          default:
                   1487:            if (flag == 0) { /* if not in packet, search start */
                   1488:                for (i = 1; (i < n) &&
                   1489:                     !(flag = ((dest[i] & 0x7f) == start));
                   1490:                     i++);
                   1491:                if (flag == 0) { /* not found, discard junk */
                   1492:                    debug(F101,"x25inl skipping","",n);
                   1493:                    continue;
                   1494:                } else {                /* found, discard junk before start */
                   1495:                    int k;
                   1496:                    n = n - i + 1;
                   1497:                    for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
                   1498:                }
                   1499:            }
                   1500:            for (i = 0; (i < n) && /* search for eol */
                   1501:                 !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
                   1502:                 i++,pdest++);
                   1503:            *pdest = '\0';
                   1504:            rest -= n;
                   1505:        }
                   1506:     } while ( (rest > 0) && (!goteol) );
                   1507: 
                   1508:     if (goteol) {
                   1509:        n = max - rest;
                   1510:        debug (F111,"ttinl X.25 got",(char *) dest,n);
                   1511:        if (timo) ttimoff();
                   1512:        if (ttprty == 0) {
                   1513:            if ((ttprty = parchk(dest,start,n)) > 0) {
                   1514:                int j;
                   1515:                debug(F101,"ttinl senses parity","",ttprty);
                   1516:                debug(F110,"ttinl packet before",(char *)dest,0);
                   1517:                ttpmsk = 0x7f;
                   1518:                for (j = 0; j < n; j++)
                   1519:                  dest[j] &= 0x7f; /* Strip parity from packet */
                   1520:                debug(F110,"ttinl packet after ",dest,0);
                   1521:            } else {
                   1522:                debug(F101,"parchk","",ttprty);
                   1523:                if (ttprty < 0) { ttprty = 0; n = -1; }
                   1524:            }
                   1525:        }
                   1526:        ttimoff();
                   1527:        return(n);
                   1528:     }
                   1529:     ttimoff();
                   1530:     return(-1);
                   1531: }
                   1532: #endif /* SUNX25 */
                   1533: 
                   1534: #endif /* NETCONN */

unix.superglobalmegacorp.com

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