Annotation of 43BSDReno/contrib/isode-beta/snmp/smux.c, revision 1.1.1.1

1.1       root        1: /* smux.c - SMUX initiator library */
                      2: 
                      3: #ifndef        lint
                      4: static char *rcsid = "$Header: /f/osi/snmp/RCS/smux.c,v 7.2 90/04/09 08:50:13 mrose Exp $";
                      5: #endif
                      6: 
                      7: /* 
                      8:  * $Header: /f/osi/snmp/RCS/smux.c,v 7.2 90/04/09 08:50:13 mrose Exp $
                      9:  *
                     10:  * Contributed by NYSERNet Inc.  This work was partially supported by the
                     11:  * U.S. Defense Advanced Research Projects Agency and the Rome Air Development
                     12:  * Center of the U.S. Air Force Systems Command under contract number
                     13:  * F30602-88-C-0016.
                     14:  *
                     15:  *
                     16:  * $Log:       smux.c,v $
                     17:  * Revision 7.2  90/04/09  08:50:13  mrose
                     18:  * update
                     19:  * 
                     20:  * Revision 7.1  90/02/19  15:38:45  mrose
                     21:  * one more time
                     22:  * 
                     23:  * Revision 7.0  90/02/17  10:36:45  mrose
                     24:  * *** empty log message ***
                     25:  * 
                     26:  */
                     27: 
                     28: /*
                     29:  *                               NOTICE
                     30:  *
                     31:  *    Acquisition, use, and distribution of this module and related
                     32:  *    materials are subject to the restrictions of a license agreement.
                     33:  *    Consult the Preface in the User's Manual for the full terms of
                     34:  *    this agreement.
                     35:  *
                     36:  */
                     37: 
                     38: 
                     39: /* LINTLIBRARY */
                     40: 
                     41: #include <stdio.h>
                     42: #include <varargs.h>
                     43: #include "smux.h"
                     44: #include "tailor.h"
                     45: 
                     46: 
                     47: #include <errno.h>
                     48: #include "internet.h"
                     49: #ifdef BSD42
                     50: #include <sys/ioctl.h>
                     51: #endif
                     52: 
                     53: /*    DATA */
                     54: 
                     55: int    smux_errno;
                     56: char    smux_info[BUFSIZ];
                     57: 
                     58: 
                     59: static int     sd = NOTOK;
                     60: static PS      ps = NULLPS;
                     61: 
                     62: static struct sockaddr_in in_socket;
                     63: 
                     64: 
                     65: static int     smux_debug = 0;
                     66: static PE      smux_pe = NULL;
                     67: static struct type_SNMP_SMUX__PDUs *smux_pdu;
                     68: static OID     smux_enterprise = NULL;
                     69: static struct type_SNMP_NetworkAddress *smux_addr = NULL;
                     70: static struct type_SNMP_TimeTicks *smux_stamp = NULL;
                     71: 
                     72: extern int     errno;
                     73: 
                     74: /*    INIT */
                     75: 
                     76: int    smux_init (debug)
                     77: int    debug;
                     78: {
                     79:     int            onoff;
                     80:     register struct sockaddr_in *isock = &in_socket;
                     81:     register struct hostent *hp;
                     82:     register struct servent *sp;
                     83:     static int inited = 0;
                     84: 
                     85:     if (!inited) {
                     86:        isodetailor ("smux", 0);
                     87: 
                     88:        inited = 1;
                     89:     }
                     90: 
                     91:     smux_debug = debug;
                     92:     if (smux_pe)
                     93:        pe_free (smux_pe), smux_pe = NULL;
                     94:     if (smux_pdu)
                     95:        free_SNMP_SMUX__PDUs (smux_pdu), smux_pdu = NULL;
                     96:     if (smux_enterprise)
                     97:        oid_free (smux_enterprise), smux_enterprise = NULL;
                     98:     if (smux_addr)
                     99:        free_SNMP_NetworkAddress (smux_addr), smux_addr = NULL;
                    100:     if (smux_stamp == NULL
                    101:            && (smux_stamp = (struct type_SNMP_TimeTicks *)
                    102:                                    calloc (1, sizeof *smux_stamp)) == NULL)
                    103:        return smuxlose (congestion, NULLCP, "out of memory");
                    104: 
                    105:     bzero ((char *) isock, sizeof *isock);
                    106:     if ((hp = gethostbystring ("127.0.0.1")) == NULL)
                    107:        return smuxlose (youLoseBig, NULLCP, "%s: unknown host", "127.0.0.1");
                    108:     isock -> sin_family = hp -> h_addrtype;
                    109:     isock -> sin_port = (sp = getservbyname ("smux", "tcp"))
                    110:                                                       ? sp -> s_port
                    111:                                                       : htons ((u_short) 199);
                    112:     inaddr_copy (hp, isock);
                    113: 
                    114:     if ((sd = start_tcp_client ((struct sockaddr_in *) NULL, 0)) == NOTOK)
                    115:        return smuxlose (systemError, "failed", "start_tcp_client");
                    116: 
                    117:     (void) ioctl (sd, FIONBIO, (onoff = 1, (char *) &onoff));
                    118: 
                    119:     if (join_tcp_server (sd, isock) == NOTOK)
                    120:        switch (errno) {
                    121:            case EINPROGRESS:
                    122:                return sd;
                    123: 
                    124:            case EISCONN:
                    125:                break;
                    126: 
                    127:            default:
                    128:                (void) smuxlose (systemError, "failed", "join_tcp_server");
                    129:                (void) close_tcp_socket (sd);
                    130:                return (sd = NOTOK);
                    131:        }
                    132: 
                    133:     if (smuxalloc () == NOTOK)
                    134:        return NOTOK;
                    135: 
                    136:     return sd;
                    137: }
                    138: 
                    139: /*  */
                    140: 
                    141: static int  smuxalloc ()
                    142: {
                    143:     int            len;
                    144: 
                    145:     if ((ps = ps_alloc (fdx_open)) == NULLPS || fdx_setup (ps, sd) == NOTOK) {
                    146:        if (ps) {
                    147:            ps_free (ps), ps = NULLPS;
                    148:            (void) smuxlose (youLoseBig, NULLCP, "fdx_setup: %s",
                    149:                             ps_error (ps -> ps_errno));
                    150:        }
                    151:        else
                    152:            (void) smuxlose (youLoseBig, NULLCP, "ps_alloc: failed");
                    153: 
                    154: you_lose: ;
                    155:        (void) close_tcp_socket (sd);
                    156:        return (sd = NOTOK);
                    157:     }
                    158: 
                    159:     if (getsockname (sd, (struct sockaddr *) &in_socket,
                    160:                     (len = sizeof in_socket, &len)) == NOTOK)
                    161:        bzero ((char *) &in_socket.sin_addr, 4);
                    162:     if ((smux_addr = str2qb ((char *) &in_socket.sin_addr, 4, 1)) == NULL) {
                    163:        (void) smuxlose (youLoseBig, NULLCP, "str2qb: failed");
                    164: 
                    165:        ps_free (ps), ps = NULLPS;
                    166:        goto you_lose;
                    167:     }
                    168: 
                    169:     return OK;
                    170: }
                    171: 
                    172: /*    SIMPLE OPEN */
                    173: 
                    174: int    smux_simple_open (identity, description, commname, commlen)
                    175: OID    identity;
                    176: char   *description;
                    177: char   *commname;
                    178: int    commlen;
                    179: {
                    180:     int            result;
                    181:     struct type_SNMP_SMUX__PDUs pdu;
                    182:     register struct type_SNMP_SimpleOpen *simple;
                    183: 
                    184:     if (identity == NULL
                    185:            || description == NULL
                    186:            || (commname == NULL && commlen != 0))
                    187:        return smuxlose (parameterMissing, NULLCP, "missing parameter");
                    188: 
                    189:     if (sd == NOTOK)
                    190:        return smuxlose (invalidOperation, NULLCP, "SMUX not inited");
                    191:     if (ps == NULLPS) {
                    192:        fd_set  mask;
                    193:        register struct sockaddr_in *isock = &in_socket;
                    194: 
                    195:        FD_ZERO (&mask);
                    196:        FD_SET (sd, &mask);
                    197:        if (xselect (sd + 1, NULLFD, &mask, NULLFD, 0) < 1)
                    198:            goto not_yet;
                    199: 
                    200:        if (join_tcp_server (sd, isock) == NOTOK)
                    201:            switch (errno) {
                    202:                case EINPROGRESS:
                    203: not_yet: ;
                    204:                    return smuxlose (inProgress, NULLCP, NULLCP);
                    205: 
                    206:            case EISCONN:
                    207:                break;
                    208: 
                    209:            default:
                    210:                (void) smuxlose (systemError, "failed", "join_tcp_server");
                    211:                (void) close_tcp_socket (sd);
                    212:                return (sd = NOTOK);
                    213:        }
                    214: 
                    215:        if (smuxalloc () == NOTOK)
                    216:            return NOTOK;
                    217:     }
                    218: 
                    219:     bzero ((char *) &pdu, sizeof pdu);
                    220: 
                    221:     if ((simple = (struct type_SNMP_SimpleOpen *) calloc (1, sizeof *simple))
                    222:        == NULL) {
                    223: no_mem: ;
                    224:         (void) smuxlose (congestion, NULLCP, "out of memory");
                    225:        if (simple)
                    226:            free_SNMP_SimpleOpen (simple);
                    227: 
                    228:        ps_free (ps), ps = NULLPS;
                    229:        (void) close_tcp_socket (sd);
                    230:        return (sd = NOTOK);
                    231:     }
                    232:     pdu.offset = type_SNMP_SMUX__PDUs_simple;
                    233:     pdu.un.simple = simple;
                    234: 
                    235:     if ((smux_enterprise = oid_cpy (identity)) == NULL)
                    236:        goto no_mem;
                    237:        
                    238:     simple -> version = int_SNMP_version_version__1;
                    239:     if ((simple -> identity = oid_cpy (identity)) == NULL
                    240:            || (simple -> description = str2qb (description,
                    241:                                                strlen (description),
                    242:                                                1)) == NULL
                    243:            || (simple -> password = str2qb (commname, commlen, 1)) == NULL)
                    244:        goto no_mem;
                    245: 
                    246:     result = smuxsend (&pdu);
                    247: 
                    248:     free_SNMP_SimpleOpen (simple);
                    249: 
                    250:     return result;
                    251: }
                    252: 
                    253: /*  */
                    254: 
                    255: static int  smuxsend (pdu)
                    256: struct type_SNMP_SMUX__PDUs *pdu;
                    257: {
                    258:     int            result;
                    259:     PE     pe;
                    260: 
                    261:     pe = NULLPE;
                    262:     if (encode_SNMP_SMUX__PDUs (&pe, 1, 0, NULLCP, pdu) == NOTOK) {
                    263:        result = smuxlose (youLoseBig, NULLCP, "encode_SNMP_SMUX__PDUs: %s",
                    264:                           PY_pepy);
                    265:        goto out;
                    266:     }
                    267: 
                    268: #ifdef DEBUG
                    269:     if (smux_debug)
                    270:        (void) print_SNMP_SMUX__PDUs (pe, 1, NULLIP, NULLVP, NULLCP);
                    271: #endif
                    272: 
                    273:     if (pe2ps (ps, pe) == NOTOK) {
                    274:        result = smuxlose (youLoseBig, NULLCP, "pe2ps: %s",
                    275:                           ps_error (ps -> ps_errno));
                    276:        goto out;
                    277:     }
                    278: 
                    279:     result = OK;
                    280: 
                    281: out: ;
                    282:     if (pe)
                    283:        pe_free (pe);
                    284: 
                    285:     if (result == NOTOK) {
                    286:        ps_free (ps), ps = NULLPS;
                    287:        (void) close_tcp_socket (sd);
                    288:        return (sd = NOTOK);
                    289:     }
                    290: 
                    291:     return OK;
                    292: }
                    293: 
                    294: /*    CLOSE */
                    295: 
                    296: int    smux_close (reason)
                    297: int    reason;
                    298: {
                    299:     int            result;
                    300:     struct type_SNMP_SMUX__PDUs pdu;
                    301:     register struct type_SNMP_ClosePDU *close;
                    302: 
                    303:     if (ps == NULLPS)
                    304:        return smuxlose (invalidOperation, NULLCP, "SMUX not opened");
                    305: 
                    306:     bzero ((char *) &pdu, sizeof pdu);
                    307: 
                    308:     if ((close = (struct type_SNMP_ClosePDU *) calloc (1, sizeof *close))
                    309:            == NULL) {
                    310:         result = smuxlose (congestion, NULLCP, "out of memory");
                    311:        if (close)
                    312:            free_SNMP_ClosePDU (close);
                    313: 
                    314:        ps_free (ps), ps = NULLPS;
                    315:        (void) close_tcp_socket (sd);
                    316:        return (sd = NOTOK);
                    317:     }
                    318:     pdu.offset = type_SNMP_SMUX__PDUs_close;
                    319:     pdu.un.close = close;
                    320: 
                    321:     close -> parm = reason;
                    322: 
                    323:     result = smuxsend (&pdu);
                    324: 
                    325:     free_SNMP_ClosePDU (close);
                    326: 
                    327:     ps_free (ps), ps = NULLPS;
                    328:     (void) close_tcp_socket (sd);
                    329:     sd = NOTOK;
                    330: 
                    331:     if (smux_pe)
                    332:        pe_free (smux_pe), smux_pe = NULL;
                    333:     if (smux_pdu)
                    334:        free_SNMP_SMUX__PDUs (smux_pdu), smux_pdu = NULL;
                    335:     if (smux_enterprise)
                    336:        oid_free (smux_enterprise), smux_enterprise = NULL;
                    337:     if (smux_addr)
                    338:        free_SNMP_NetworkAddress (smux_addr), smux_addr = NULL;
                    339: 
                    340:     return result;
                    341: }
                    342: 
                    343: /*    REGISTER */
                    344: 
                    345: int    smux_register (subtree, priority, operation)
                    346: OID    subtree;
                    347: int    priority,
                    348:        operation;
                    349: {
                    350:     int            result;
                    351:     struct type_SNMP_SMUX__PDUs pdu;
                    352:     register struct type_SNMP_RReqPDU *rreq;
                    353: 
                    354:     if (subtree == NULL)
                    355:        return smuxlose (parameterMissing, NULLCP, "missing parameter");
                    356: 
                    357:     if (ps == NULLPS)
                    358:        return smuxlose (invalidOperation, NULLCP, "SMUX not opened");
                    359: 
                    360:     bzero ((char *) &pdu, sizeof pdu);
                    361: 
                    362:     if ((rreq = (struct type_SNMP_RReqPDU *) calloc (1, sizeof *rreq))
                    363:        == NULL) {
                    364: no_mem: ;
                    365:         result = smuxlose (congestion, NULLCP, "out of memory");
                    366:        if (rreq)
                    367:            free_SNMP_RReqPDU (rreq);
                    368: 
                    369:        ps_free (ps), ps = NULLPS;
                    370:        (void) close_tcp_socket (sd);
                    371:        return (sd = NOTOK);
                    372:     }
                    373:     pdu.offset = type_SNMP_SMUX__PDUs_registerRequest;
                    374:     pdu.un.registerRequest = rreq;
                    375: 
                    376:     if ((rreq -> subtree = oid_cpy (subtree)) == NULLOID)
                    377:        goto no_mem;
                    378:     rreq -> priority = priority;
                    379:     rreq -> operation = operation;
                    380: 
                    381:     result = smuxsend (&pdu);
                    382: 
                    383:     free_SNMP_RReqPDU (rreq);
                    384: 
                    385:     return result;
                    386: }
                    387: 
                    388: /*    WAIT */
                    389: 
                    390: int    smux_wait (event, secs)
                    391: struct type_SNMP_SMUX__PDUs **event;
                    392: int    secs;
                    393: {
                    394:     fd_set  mask;
                    395:     PE     pe;
                    396: 
                    397:     if (event == NULL)
                    398:        return smuxlose (parameterMissing, NULLCP, "missing parameter");
                    399:        
                    400:     if (ps == NULLPS)
                    401:        return smuxlose (invalidOperation, NULLCP, "SMUX not opened");
                    402: 
                    403:     FD_ZERO (&mask);
                    404:     FD_SET (sd, &mask);
                    405:     if ((ps -> ps_primeP == NULLIFP || (*ps -> ps_primeP) (ps, 1) == OK)
                    406:            && xselect (sd + 1, &mask, NULLFD, NULLFD, secs) < 1) {
                    407:        errno = EWOULDBLOCK;
                    408:        return smuxlose (inProgress, NULLCP, NULLCP);
                    409:     }
                    410: 
                    411:     if ((pe = ps2pe (ps)) == NULLPE) {
                    412:        (void) smuxlose (youLoseBig, NULLCP, "pe2ps: %s",
                    413:                         ps_error (ps -> ps_errno));
                    414:        goto out;
                    415:     }
                    416: 
                    417:     if (decode_SNMP_SMUX__PDUs (pe, 1, NULLIP, NULLVP, event) == NOTOK) {
                    418:        (void) smuxlose (youLoseBig, NULLCP, "encode_SNMP_SMUX__PDUs: %s",
                    419:                         PY_pepy);
                    420:        goto out;
                    421:     }
                    422: 
                    423: #ifdef DEBUG
                    424:     if (smux_debug)
                    425:        (void) print_SNMP_SMUX__PDUs (pe, 1, NULLIP, NULLVP, NULLCP);
                    426: #endif
                    427: 
                    428:     if (smux_pe)
                    429:        pe_free (smux_pe);
                    430:     smux_pe = pe;
                    431:     if (smux_pdu)
                    432:        free_SNMP_SMUX__PDUs (smux_pdu);
                    433:     smux_pdu = *event;
                    434: 
                    435:     if (smux_pdu -> offset == type_SNMP_SMUX__PDUs_close) {
                    436:        ps_free (ps), ps = NULLPS;
                    437:        (void) close_tcp_socket (sd);
                    438:        sd = NOTOK;
                    439:     }
                    440:     return OK;
                    441: 
                    442: out: ;
                    443:     if (pe)
                    444:        pe_free (pe);
                    445: 
                    446:     ps_free (ps), ps = NULLPS;
                    447:     (void) close_tcp_socket (sd);
                    448:     return (sd = NOTOK);
                    449: }
                    450: 
                    451: /*    RESPONSE */
                    452: 
                    453: int    smux_response (event)
                    454: struct type_SNMP_GetResponse__PDU *event;
                    455: {
                    456:     struct type_SNMP_SMUX__PDUs pdu;
                    457: 
                    458:     if (event == NULL)
                    459:        return smuxlose (parameterMissing, NULLCP, "missing parameter");
                    460: 
                    461:     if (ps == NULLPS)
                    462:        return smuxlose (invalidOperation, NULLCP, "SMUX not opened");
                    463: 
                    464:     bzero ((char *) &pdu, sizeof pdu);
                    465: 
                    466:     pdu.offset = type_SNMP_SMUX__PDUs_get__response;
                    467:     pdu.un.get__response = event;
                    468: 
                    469:     return smuxsend (&pdu);
                    470: }
                    471: 
                    472: /*    TRAP */
                    473: 
                    474: int    smux_trap (generic, specific, bindings)
                    475: int    generic,
                    476:        specific;
                    477: struct type_SNMP_VarBindList *bindings;
                    478: {
                    479:     int            result;
                    480:     struct type_SNMP_SMUX__PDUs pdu;
                    481:     register struct type_SNMP_Trap__PDU *trap;
                    482: 
                    483:     if (ps == NULLPS)
                    484:        return smuxlose (invalidOperation, NULLCP, "SMUX not opened");
                    485: 
                    486:     bzero ((char *) &pdu, sizeof pdu);
                    487: 
                    488:     if ((trap = (struct type_SNMP_Trap__PDU *) calloc (1, sizeof *trap))
                    489:            == NULL) {
                    490:         result = smuxlose (congestion, NULLCP, "out of memory");
                    491:        if (trap)
                    492:            free_SNMP_Trap__PDU (trap);
                    493: 
                    494:        ps_free (ps), ps = NULLPS;
                    495:        (void) close_tcp_socket (sd);
                    496:        return (sd = NOTOK);
                    497:     }
                    498:     pdu.offset = type_SNMP_SMUX__PDUs_trap;
                    499:     pdu.un.trap = trap;
                    500: 
                    501:     trap -> enterprise = smux_enterprise;
                    502:     trap -> agent__addr = smux_addr;
                    503:     trap -> generic__trap = generic;
                    504:     trap -> specific__trap = specific;
                    505:     trap -> time__stamp = smux_stamp;
                    506:     trap -> time__stamp -> parm = uptime ();
                    507:     trap -> variable__bindings = bindings;
                    508: 
                    509:     result = smuxsend (&pdu);
                    510: 
                    511:     trap -> enterprise = NULL;
                    512:     trap -> agent__addr = NULL;
                    513:     trap -> time__stamp = NULL;
                    514:     trap -> variable__bindings = NULL;
                    515: 
                    516:     free_SNMP_Trap__PDU (trap);
                    517: 
                    518:     return result;
                    519: }
                    520: 
                    521: /*  */
                    522: 
                    523: #include <nlist.h>
                    524: #ifdef BSD42
                    525: #include <sys/file.h>
                    526: #endif
                    527: #ifdef SYS5
                    528: #include <fcntl.h>
                    529: #endif
                    530: 
                    531: 
                    532: static struct nlist nl[] = {
                    533:     { "_boottime" },
                    534:     
                    535:     NULL
                    536: };
                    537: 
                    538: 
                    539: static int  uptime ()
                    540: {
                    541:     struct timeval now;
                    542:     static int inited = 0;
                    543:     static struct timeval boottime;
                    544: 
                    545:     if (!inited) {
                    546:        int     kd;
                    547: 
                    548:        if (nlist ("/vmunix", nl) == NOTOK || nl -> n_value == 0)
                    549:            return 0;
                    550: 
                    551:        if ((kd = open ("/dev/kmem", O_RDONLY)) == NOTOK)
                    552:            return 0;
                    553: 
                    554:        if (lseek (kd, (long) nl -> n_value, L_SET) == NOTOK) {
                    555:            (void) close (kd);
                    556:            return 0;
                    557:        }
                    558: 
                    559:        if (read (kd, (char *) &boottime, sizeof boottime)
                    560:                != sizeof boottime) {
                    561:            (void) close (kd);
                    562:            return 0;
                    563:        }
                    564: 
                    565:        (void) close (kd);
                    566: 
                    567:        inited = 1;
                    568:     }
                    569: 
                    570:     if (gettimeofday (&now, (struct timezone *) 0) == NOTOK)
                    571:        return 0;
                    572: 
                    573:     return (now.tv_sec - boottime.tv_sec) * 100
                    574:                + (now.tv_usec - boottime.tv_usec);
                    575: }
                    576:     
                    577: /*    LOSE */
                    578: 
                    579: #ifndef        lint
                    580: static int  smuxlose (va_alist)
                    581: va_dcl
                    582: {
                    583:     va_list ap;
                    584: 
                    585:     va_start (ap);
                    586: 
                    587:     smux_errno = va_arg (ap, int);
                    588: 
                    589:     asprintf (smux_info, ap);
                    590: 
                    591:     va_end (ap);
                    592: 
                    593:     return NOTOK;
                    594: }
                    595: #else
                    596: /* VARARGS3 */
                    597: 
                    598: static int  smuxlose (reason, what, fmt)
                    599: int    reason;
                    600: char   *what,
                    601:        *fmt;
                    602: {
                    603:     return smuxlose (reason, what, fmt);
                    604: }
                    605: #endif
                    606: 
                    607: /*  */
                    608: 
                    609: static char *errors_up[] = {
                    610:     "goingDown",
                    611:     "unsupportedVersion",
                    612:     "packetFormat",
                    613:     "protocolError",
                    614:     "internalError",
                    615:     "authenticationFailure"
                    616: };
                    617: 
                    618: static char *errors_down[] = {
                    619:     "SMUX error 0",
                    620:     "invalidOperation",
                    621:     "parameterMissing",
                    622:     "systemError",
                    623:     "youLoseBig",
                    624:     "congestion",
                    625:     "inProgress"
                    626: };
                    627: 
                    628: char   *smux_error (i)
                    629: int    i;
                    630: {
                    631:     int            j;
                    632:     char  **ap;
                    633:     static char buffer[BUFSIZ];
                    634: 
                    635:     if (i < 0) {
                    636:        ap = errors_down, j = sizeof errors_down / sizeof errors_down[0];
                    637:        i = -i;
                    638:     }
                    639:     else
                    640:        ap = errors_up, j = sizeof errors_up / sizeof errors_up[0];
                    641:     if (0 <= i && i < j)
                    642:        return ap[i];
                    643: 
                    644:     (void) sprintf (buffer, "SMUX error %s%d", ap == errors_down ? "-" : "",i);
                    645: 
                    646:     return buffer;
                    647: }

unix.superglobalmegacorp.com

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