[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

whois.b



For a first crack at inferno network programming, I've written a simple
whois.  It's actually useful on Microsoft platforms.  The code calls
a SysVian getopt module I've posted (new dog, old trick).

- Steve

# whois.b
#                      "...and afterward
# The wind was into such a voice converted:
# 'With brevity shall be replied to you...'" Inf. 13.093

implement Whois;

include "sys.m";
sys: Sys;
    FD, fprint, fildes: import sys;
    stdout, stderr: ref FD;
    
include "draw.m";
    Context: import Draw;

include "lib.m";
    str: String;
        
include "getopts.m";
    op: GetOpts;
    opts: import op;        
    o: ref opts;

Whois: module
{
    init: fn(ctxt: ref Context, argv: list of string);
};

init(ctxt: ref Context, argv: list of string)
{
    str = load String String->PATH;
    sys = load Sys Sys->PATH;
    stdout = fildes(1);
    stderr = fildes(2);
    
    op = load GetOpts GetOpts->PATH;
    o = op->init(argv, "h:");
    
    rshost := "rs.internic.net";
    
    c: int;
    while((c = o.getopt()) != 0)
        case c {
            '?' =>
                usage();
            'h' =>
                rshost = o.optarg;
        }
    if(o.optind != o.argc - 1)
        usage();
    pat := o.argv[o.optind];

    whois(rshost, pat);
}

whois(rshost, pat: string)
{
    tc := chan of int;
    spawn timer(tc, 10000);
    tpid := <-tc;

    qc := chan of string;   
    spawn query(qc, rshost, pat);
    (qpid,s) := str->toint(<-qc, 10);

    alt {
    <-tc =>
        errmsg("timed out");
        killpid(qpid);
    r := <-qc =>
        if(r != "OK")
            errmsg(r);
        killpid(tpid);
    }
}

timer(tc: chan of int, ms: int)
{
    tc <-=sys->pctl(0, nil);
    sys->sleep(ms);
    tc <-=1;
}

query(qc: chan of string, rshost, pat: string)
{
    npat := array of byte (pat + "\r\n");
    
    qc <-= string sys->pctl(0, nil);

    (ok, cn) := sys->dial("tcp!" + rshost + "!43", nil); 
    if(ok < 0)
        qc <-= "dial";
    else if(sys->write(cn.dfd, npat, len npat) != len npat)
        qc <-= "write";
    else{
        n := sys->stream(cn.dfd, stdout, 1024);
        if(n <= 0)
            qc <-= "stream";
        else
            qc <-= "OK";
    }
}

# stolen from virgil.b
# The found comment below is important;  variations I tested corrupted
# the shell namespace.
  
killpid(pid: int)
{
    # Fork namespace to avoid perturbing /prog for relatives.
    sys->pctl(sys->FORKNS, nil);
    sys->bind("#p", "/prog", sys->MREPL);

    fd := sys->open("/prog/"+(string pid)+"/ctl", sys->OWRITE);
    if(fd == nil)
        return;
    sys->write(fd, array of byte "kill", 4);
}

usage()
{
    fprint(stderr, "usage: %s [ -h host ] name\n", o.argv[0]);
    exit;
}

errmsg(s: string)
{
    fprint(stderr, "%s error: %s %r\n", o.argv[0], s);
}