diff options
Diffstat (limited to 'appl/cmd/ip/ppp')
| -rw-r--r-- | appl/cmd/ip/ppp/mkfile | 27 | ||||
| -rw-r--r-- | appl/cmd/ip/ppp/modem.b | 468 | ||||
| -rw-r--r-- | appl/cmd/ip/ppp/modem.m | 41 | ||||
| -rw-r--r-- | appl/cmd/ip/ppp/pppclient.b | 216 | ||||
| -rw-r--r-- | appl/cmd/ip/ppp/pppclient.m | 31 | ||||
| -rw-r--r-- | appl/cmd/ip/ppp/pppdial.b | 283 | ||||
| -rw-r--r-- | appl/cmd/ip/ppp/pppgui.b | 373 | ||||
| -rw-r--r-- | appl/cmd/ip/ppp/pppgui.m | 21 | ||||
| -rw-r--r-- | appl/cmd/ip/ppp/ppptest.b | 86 | ||||
| -rw-r--r-- | appl/cmd/ip/ppp/script.b | 168 | ||||
| -rw-r--r-- | appl/cmd/ip/ppp/script.m | 14 |
11 files changed, 1728 insertions, 0 deletions
diff --git a/appl/cmd/ip/ppp/mkfile b/appl/cmd/ip/ppp/mkfile new file mode 100644 index 00000000..193b8faf --- /dev/null +++ b/appl/cmd/ip/ppp/mkfile @@ -0,0 +1,27 @@ +<../../../../mkconfig + +TARG=\ + pppclient.dis\ + pppdial.dis\ + pppgui.dis\ + ppptest.dis\ + modem.dis\ + script.dis\ + +MODULES=\ + modem.m\ + pppclient.m\ + pppgui.m\ + script.m\ + +SYSMODULES=\ + sys.m\ + draw.m\ + tk.m\ + dict.m\ + string.m\ + lock.m\ + +DISBIN=$ROOT/dis/ip/ppp + +<$ROOT/mkfiles/mkdis diff --git a/appl/cmd/ip/ppp/modem.b b/appl/cmd/ip/ppp/modem.b new file mode 100644 index 00000000..6085524a --- /dev/null +++ b/appl/cmd/ip/ppp/modem.b @@ -0,0 +1,468 @@ +implement Modem; + +include "sys.m"; + sys: Sys; + +include "lock.m"; + lock: Lock; + Semaphore: import lock; + +include "draw.m"; + +include "modem.m"; + +hangupcmd := "ATH0"; # was ATZH0 but some modem versions on Umec hung on ATZ (BUG: should be in modeminfo) + +# modem return codes +Ok, Success, Failure, Abort, Noise, Found: con iota; + +maxspeed: con 115200; + +# +# modem return messages +# +Msg: adt { + text: string; + code: int; +}; + +msgs: array of Msg = array [] of { + ("OK", Ok), + ("NO CARRIER", Failure), + ("ERROR", Failure), + ("NO DIALTONE", Failure), + ("BUSY", Failure), + ("NO ANSWER", Failure), + ("CONNECT", Success), +}; + +kill(pid: int) +{ + fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE); + if(fd == nil || sys->fprint(fd, "kill") < 0) + sys->print("modem: can't kill %d: %r\n", pid); +} + +# +# prepare a modem port +# +openserial(d: ref Device) +{ + if (d==nil) { + raise "fail: device not initialized"; + return; + } + + d.data = nil; + d.ctl = nil; + + d.data = sys->open(d.local, Sys->ORDWR); + if(d.data == nil) { + raise "fail: can't open "+d.local; + return; + } + + d.ctl = sys->open(d.local+"ctl", Sys->ORDWR); + if(d.ctl == nil) { + raise "can't open "+d.local+"ctl"; + return; + } + + d.speed = maxspeed; + d.avail = nil; +} + +# +# shut down the monitor (if any) and return the connection +# + +close(m: ref Device): ref Sys->Connection +{ + if(m == nil) + return nil; + if(m.pid != 0){ + kill(m.pid); + m.pid = 0; + } + if(m.data == nil) + return nil; + mc := ref sys->Connection(m.data, m.ctl, nil); + m.ctl = nil; + m.data = nil; + return mc; +} + +# +# Send a string to the modem +# + +send(d: ref Device, x: string): int +{ + if (d == nil) + return -1; + + a := array of byte x; + f := sys->write(d.data, a, len a); + if (f < 0) { + # let's attempt to close & reopen the modem + close(d); + openserial(d); + f = sys->write(d.data,a, len a); + } + sys->print("->%s\n",x); + return f; +} + +# +# apply a string of commands to modem & look for a response +# + +apply(d: ref Device, s: string, substr: string, secs: int): int +{ + m := Ok; + buf := ""; + for(i := 0; i < len s; i++){ + c := s[i]; + buf[len buf] = c; # assume no Unicode + if(c == '\r' || i == (len s -1)){ + if(c != '\r') + buf[len buf] = '\r'; + if(send(d, buf) < 0) + return Abort; + (m, nil) = readmsg(d, secs, substr); + buf = ""; + } + } + return m; +} + +# +# get modem into command mode if it isn't already +# +GUARDTIME: con 1100; # usual default for S12=50 in units of 1/50 sec; allow 100ms fuzz + +attention(d: ref Device): int +{ + for(i := 0; i < 3; i++){ + if(apply(d, hangupcmd, nil, 2) == Ok) + return Ok; + sys->sleep(GUARDTIME); + if(send(d, "+++") < 0) + return Abort; + sys->sleep(GUARDTIME); + (nil, msg) := readmsg(d, 0, nil); + if(msg != nil) + sys->print("status: %s\n", msg); + } + return Failure; +} + +# +# apply a command type +# + +applyspecial(d: ref Device, cmd: string): int +{ + if(cmd == nil) + return Failure; + return apply(d, cmd, nil, 2); +} + +# +# hang up any connections in progress and close the device +# +onhook(d: ref Device) +{ + if(d == nil) + return; + + # hang up the modem + monitoring(d); + if(attention(d) != Ok) + sys->print("modem: no attention\n"); + + # hangup the stream (eg, for ppp) and toggle the lines to the modem + if(d.ctl != nil) { + sys->fprint(d.ctl,"d0\n"); + sys->fprint(d.ctl,"r0\n"); + sys->fprint(d.ctl, "h\n"); # hangup on native serial + sys->sleep(250); + sys->fprint(d.ctl,"r1\n"); + sys->fprint(d.ctl,"d1\n"); + } + + close(d); +} + +# +# does string s contain t anywhere? +# + +contains(s, t: string): int +{ + if(t == nil) + return 1; + if(s == nil) + return 0; + n := len t; + for(i := 0; i+n <= len s; i++) + if(s[i:i+n] == t) + return 1; + return 0; +} + +# +# read till we see a message or we time out +# +readmsg(d: ref Device, secs: int, substr: string): (int, string) +{ + if (d == nil) + return (Abort, "device not initialized"); + found := 0; + secs *= 1000; + limit := 1000; # pretty arbitrary + s := ""; + + for(start := sys->millisec(); sys->millisec() <= start+secs;){ + a := getinput(d,1); + if(len a == 0){ + if(limit){ + sys->sleep(1); + continue; + } + break; + } + if(a[0] == byte '\n' || a[0] == byte '\r' || limit == 0){ + if (len s) { + if (s[(len s)-1] == '\r') + s[(len s)-1] = '\n'; + sys->print("<-%s\n",s); + } + if(substr != nil && contains(s, substr)) + found = 1; + for(k := 0; k < len msgs; k++) + if(len s >= len msgs[k].text && + s[0:len msgs[k].text] == msgs[k].text){ + if(found) + return (Found, s); + return (msgs[k].code, s); + } + start = sys->millisec(); + s = ""; + continue; + } + s[len s] = int a[0]; + limit--; + } + s = "No response from modem"; + if(found) + return (Found, s); + + return (Noise, s); +} + +# +# get baud rate from a connect message +# + +getspeed(msg: string, speed: int): int +{ + p := msg[7:]; # skip "CONNECT" + while(p[0] == ' ' || p[0] == '\t') + p = p[1:]; + s := int p; + if(s <= 0) + return speed; + else + return s; +} + +# +# set speed and RTS/CTS modem flow control +# + +setspeed(d: ref Device, baud: int) +{ + if(d != nil && d.ctl != nil){ + sys->fprint(d.ctl, "b%d", baud); + sys->fprint(d.ctl, "m1"); + } +} + +dumpa(a: array of byte): string +{ + s := ""; + for(i:=0; i<len a; i++){ + b := int a[i]; + if(b >= ' ' && b < 16r7f) + s[len s] = b; + else + s += sys->sprint("\\%.2x", b); + } + return s; +} + +monitoring(d: ref Device) +{ + # if no monitor then spawn one + if(d.pid == 0) { + pidc := chan of int; + spawn monitor(d, pidc); + d.pid = <-pidc; + } +} + +# +# a process to read input from a modem. +# +monitor(d: ref Device, pidc: chan of int) +{ + openserial(d); + pidc <-= sys->pctl(0, nil); # pidc can be written once only. + a := array[Sys->ATOMICIO] of byte; + for(;;) { + d.lock.obtain(); + d.status = "Idle"; + d.remote = ""; + setspeed(d, d.speed); + d.lock.release(); + # shuttle bytes + while((n := sys->read(d.data, a, len a)) > 0){ + d.lock.obtain(); + if (len d.avail < Sys->ATOMICIO) { + na := array[len d.avail + n] of byte; + na[0:] = d.avail[0:]; + na[len d.avail:] = a[0:n]; + d.avail = na; + } + d.lock.release(); + } + # on an error, try reopening the device + d.data = nil; + d.ctl = nil; + openserial(d); + } +} + +# +# return up to n bytes read from the modem by monitor() +# +getinput(d: ref Device, n: int): array of byte +{ + if(d==nil || n <= 0) + return nil; + a: array of byte; + d.lock.obtain(); + if(len d.avail != 0){ + if(n > len d.avail) + n = len d.avail; + a = d.avail[0:n]; + d.avail = d.avail[n:]; + } + d.lock.release(); + return a; +} + +getc(m: ref Device, timo: int): int +{ + start := sys->millisec(); + while((b := getinput(m, 1)) == nil) { + if (timo && sys->millisec() > start+timo) + return 0; + sys->sleep(1); + } + return int b[0]; +} + +init(modeminfo: ref ModemInfo): ref Device +{ + if (sys == nil) { + sys = load Sys Sys->PATH; + lock = load Lock Lock->PATH; + if (lock == nil) { + raise "fail: Couldn't load lock module"; + return nil; + } + lock->init(); + } + + newdev := ref Device; + newdev.lock = Semaphore.new(); + newdev.local = modeminfo.path; + newdev.pid = 0; + newdev.t = modeminfo; + + return newdev; +} + + +# +# dial a number +# +dial(d: ref Device, number: string) +{ + if (d==nil) { + raise "fail: Device not initialized"; + return; + } + + monitoring(d); + + # modem type should already be established, but just in case + sys->print("Attention\n"); + x := attention(d); + if (x != Ok) + sys->print("Attention failed\n"); + # + # extended Hayes commands, meaning depends on modem (VGA all over again) + # + sys->print("Init\n"); + if(d.t.country != nil) + applyspecial(d, d.t.country); + + if(d.t.init != nil) + applyspecial(d, d.t.init); + + if(d.t.other != nil) + applyspecial(d, d.t.other); + + applyspecial(d, d.t.errorcorrection); + + compress := Abort; + if(d.t.mnponly != nil) + compress = applyspecial(d, d.t.mnponly); + if(d.t.compression != nil) + compress = applyspecial(d, d.t.compression); + + rateadjust := Abort; + if(compress != Ok) + rateadjust = applyspecial(d, d.t.rateadjust); + applyspecial(d, d.t.flowctl); + + # finally, dialout + sys->print("Dialing\n"); + if((dt := d.t.dialtype) == nil) + dt = "ATDT"; + if(send(d, sys->sprint("%s%s\r", dt, number)) < 0) { + raise "can't dial "+number; + return; + } + + (i, msg) := readmsg(d, 120, nil); + if(i != Success) { + raise "fail: "+msg; + return; + } + + connectspeed := getspeed(msg, d.speed); + + # change line rate if not compressing + if(rateadjust == Ok) + setspeed(d, connectspeed); + + if(d.ctl != nil){ + if(d != nil) + sys->fprint(d.ctl, "s%d", connectspeed); # set DCE speed (if device implements it) + sys->fprint(d.ctl, "c1"); # enable CD monitoring + } +} diff --git a/appl/cmd/ip/ppp/modem.m b/appl/cmd/ip/ppp/modem.m new file mode 100644 index 00000000..9a99acf8 --- /dev/null +++ b/appl/cmd/ip/ppp/modem.m @@ -0,0 +1,41 @@ +Modem: module +{ + PATH: con "/dis/ip/ppp/modem.dis"; + + ModemInfo: adt { + path: string; + init: string; + country: string; + other: string; + errorcorrection:string; + compression: string; + flowctl: string; + rateadjust: string; + mnponly: string; + dialtype: string; + }; + + Device: adt { + lock: ref Lock->Semaphore; + # modem stuff + ctl: ref Sys->FD; + data: ref Sys->FD; + + local: string; + remote: string; + status: string; + speed: int; + t: ref ModemInfo; + # input reader + avail: array of byte; + pid: int; + }; + + init: fn(i: ref ModemInfo): ref Device; + dial: fn( m: ref Device, number: string); + getc: fn(m: ref Device, timout: int): int; + getinput: fn(m: ref Device, n: int ): array of byte; + send: fn(m: ref Device, x: string): int; + close: fn(m: ref Device): ref Sys->Connection; + onhook: fn(m: ref Device); +}; diff --git a/appl/cmd/ip/ppp/pppclient.b b/appl/cmd/ip/ppp/pppclient.b new file mode 100644 index 00000000..be321b59 --- /dev/null +++ b/appl/cmd/ip/ppp/pppclient.b @@ -0,0 +1,216 @@ +implement PPPClient; + + +include "sys.m"; + sys : Sys; +include "draw.m"; + +include "lock.m"; +include "modem.m"; +include "script.m"; + +include "pppclient.m"; + +include "translate.m"; + translate : Translate; + Dict : import translate; + dict : ref Dict; + +# +# Globals (these will have to be removed if we are going multithreaded) +# + +pid := 0; +modeminfo: ref Modem->ModemInfo; +pppdir: string; + +ppplog(log: chan of int, errfile: string, pidc: chan of int) +{ + pidc <-= sys->pctl(0, nil); # set reset pid to our pid + src := sys->open(errfile, Sys->OREAD); + if (src == nil) + raise sys->sprint("fail: Couldn't open %s: %r", errfile); + + LOGBUFMAX: con 1024; + buf := array[LOGBUFMAX] of byte; + connected := 0; + + while ((count := sys->read(src, buf, LOGBUFMAX)) > 0) { + (n, toklist) := sys->tokenize(string buf[:count],"\n"); + for (;toklist != nil;toklist = tl toklist) { + case hd toklist { + "no error" => + log <-= s_SuccessPPP; + lasterror = nil; + connected = 1; + "permission denied" => + lasterror = X("Username or Password Incorrect"); + log <-= s_Error; + "write to hungup channel" => + lasterror = X("Remote Host Hung Up"); + log <-= s_Error; + * => + lasterror = X(hd toklist); + log <-= s_Error; + } + } + } + if(count == 0 && connected && lasterror == nil){ # should change ip/pppmedium.c instead? + lasterror = X("Lost Connection"); + log <-= s_Error; + } +} + +startppp(logchan: chan of int, pppinfo: ref PPPInfo) +{ + ifd := sys->open("/net/ipifc/clone", Sys->ORDWR); + if (ifd == nil) + raise "fail: Couldn't open /net/ipifc/clone"; + + buf := array[32] of byte; + n := sys->read(ifd, buf, len buf); + if(n <= 0) + raise "fail: can't read from /net/ipifc/clone"; + + pppdir = "/net/ipifc/" + string buf[0:n]; + pidc := chan of int; + spawn ppplog(logchan, pppdir + "/err", pidc); + pid = <-pidc; + logchan <-= s_StartPPP; + + if (pppinfo.ipaddr == nil) + pppinfo.ipaddr = "-"; +# if (pppinfo.ipmask == nil) +# pppinfo.ipmask = "255.255.255.255"; + if (pppinfo.peeraddr == nil) + pppinfo.peeraddr = "-"; + if (pppinfo.maxmtu == nil) + pppinfo.maxmtu = "512"; + if (pppinfo.username == nil) + pppinfo.username = "-"; + if (pppinfo.password == nil) + pppinfo.password = "-"; + framing := "1"; + + ifc := "bind ppp "+modeminfo.path+" "+ pppinfo.ipaddr+" "+pppinfo.peeraddr+" "+pppinfo.maxmtu + +" "+framing+" "+pppinfo.username+" "+pppinfo.password; + + # send the add command + if (sys->fprint(ifd, "%s", ifc) < 0) { + sys->print("pppclient: couldn't write %s/ctl: %r\n", pppdir); + raise "fail: Couldn't write /net/ipifc"; + return; + } +} + +connect(mi: ref Modem->ModemInfo, number: string, + scriptinfo: ref Script->ScriptInfo, pppinfo: ref PPPInfo, logchan: chan of int) +{ + sys = load Sys Sys->PATH; + + translate = load Translate Translate->PATH; + if (translate != nil) { + translate->init(); + dictname := translate->mkdictname("", "pppclient"); + (dict, nil) = translate->opendict(dictname); + } + if (pid != 0) # yikes we are already running + reset(); + + # create a new process group + pid = sys->pctl( Sys->NEWPGRP, nil); + + { + logchan <-= s_Initialized; + + # open & init the modem + modeminfo = mi; + modem := load Modem Modem->PATH; + if (modem == nil) { + raise "fail: Couldn't load modem module"; + return; + } + + modemdev := modem->init(modeminfo); + logchan <-= s_StartModem; + modem->dial(modemdev, number); + logchan <-= s_SuccessModem; + + # if script + if (scriptinfo != nil) { + script := load Script Script->PATH; + if (script == nil) { + raise "fail: Couldn't load script module"; + return; + } + logchan <-= s_StartScript; + script->execute(modem, modemdev, scriptinfo); + logchan <-= s_SuccessScript; + } + + mc := modem->close(modemdev); # keep connection open for ppp mode + modemdev = nil; + modem = nil; # unload modem module + + # if ppp + if (pppinfo != nil) + startppp(logchan, pppinfo); + else + logchan <-= s_Done; + } + exception e{ + "fail*" => + lasterror = e; + sys->print("PPPclient: fatal exception: %s\n", e); + logchan <-= s_Error; + kill(pid, "killgrp"); + exit; + } +} + +reset() +{ + sys->print("reset..."); + if(pid != 0){ + kill(pid, "killgrp"); + pid = 0; + } + + if(pppdir != nil){ # shut down the PPP link + fd := sys->open(pppdir + "/ctl", Sys->OWRITE); + if(fd == nil || sys->fprint(fd, "unbind") < 0) + sys->print("pppclient: can't unbind: %r\n"); + fd = nil; + pppdir = nil; + } + + modem := load Modem Modem->PATH; + if (modem == nil) { + raise "fail: Couldn't load modem module"; + return; + } + modemdev := modem->init(modeminfo); + if(modemdev != nil) + modem->onhook(modemdev); + modem = nil; + + # clear error buffer + lasterror = nil; +} + +kill(pid: int, msg: string) +{ + a := array of byte msg; + fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE); + if(fd == nil || sys->write(fd, a, len a) < 0) + sys->print("pppclient: can't %s %d: %r\n", msg, pid); +} + +# Translate a string + +X(s : string) : string +{ + if (dict== nil) return s; + return dict.xlate(s); +} + diff --git a/appl/cmd/ip/ppp/pppclient.m b/appl/cmd/ip/ppp/pppclient.m new file mode 100644 index 00000000..23396af4 --- /dev/null +++ b/appl/cmd/ip/ppp/pppclient.m @@ -0,0 +1,31 @@ + +PPPClient: module { + PATH: con "/dis/ip/ppp/pppclient.dis"; + + PPPInfo: adt { + ipaddr: string; + ipmask: string; + peeraddr: string; + maxmtu: string; + username: string; + password: string; + }; + + connect: fn( mi: ref Modem->ModemInfo, number: string, + scriptinfo: ref Script->ScriptInfo, + pppinfo: ref PPPInfo, logchan: chan of int); + reset: fn(); + + lasterror :string; + + s_Error: con -666; + s_Initialized, # Module Initialized + s_StartModem, # Modem Initialized + s_SuccessModem, # Modem Connected + s_StartScript, # Script Executing + s_SuccessScript, # Script Executed Sucessfully + s_StartPPP, # PPP Started + s_LoginPPP, # CHAP/PAP Authentication + s_SuccessPPP, # PPP Session Established + s_Done: con iota; # PPPClient Cleaningup & Exiting +}; diff --git a/appl/cmd/ip/ppp/pppdial.b b/appl/cmd/ip/ppp/pppdial.b new file mode 100644 index 00000000..ec689dc1 --- /dev/null +++ b/appl/cmd/ip/ppp/pppdial.b @@ -0,0 +1,283 @@ +implement PPPdial; + +# +# Module: ispservice +# Purpose: Simple PPP Dial-on-Demand +# Author: Eric Van Hensbergen (ericvh@lucent.com) +# +# Copyright © 1998-1999 Lucent Technologies Inc. All rights reserved. +# Revisions copyright © 2000-2003 Vita Nuova Holdings Limited. All rights reserved. +# + +include "sys.m"; + sys: Sys; +include "draw.m"; + draw: Draw; + +include "cfgfile.m"; + cfg: CfgFile; + ConfigFile: import cfg; + +include "lock.m"; +include "modem.m"; +include "script.m"; +include "pppclient.m"; + ppp: PPPClient; +include "pppgui.m"; + +PPPdial: module +{ + init: fn(nil: ref Draw->Context): string; + connect: fn(): string; +}; + +context: ref Draw->Context; +modeminfo: ref Modem->ModemInfo; +pppinfo: ref PPPClient->PPPInfo; +scriptinfo: ref Script->ScriptInfo; +isp_number: string; # should be part of pppinfo +lastCdir: ref Sys->Dir; # state of file when last read + +DEFAULT_ISP_DB_PATH: con "/services/ppp/isp.cfg"; # contains pppinfo & scriptinfo +DEFAULT_MODEM_DB_PATH: con "/services/ppp/modem.cfg"; # contains modeminfo +MODEM_DB_PATH: con "/usr/inferno/config/modem.cfg"; # contains modeminfo +ISP_DB_PATH: con "/usr/inferno/config/isp.cfg"; # contains pppinfo & scriptinfo +ISP_RETRIES: con 5; + +getcfgstring(c: ref ConfigFile, key: string) :string +{ + l := c.getcfg(key); + if (l == nil) + return nil; + for(ret := ""; l != nil; l = tl l) + ret+= " " + hd l; + + return ret[1:]; # trim the first space +} + +configinit() +{ + mi: Modem->ModemInfo; + pppi: PPPClient->PPPInfo; + info: list of string; + + cfg = load CfgFile CfgFile->PATH; + if (cfg == nil) + raise "fail: load CfgFile"; + + # Modem Configuration + + cfg->verify(DEFAULT_MODEM_DB_PATH, MODEM_DB_PATH); + modemcfg := cfg->init(MODEM_DB_PATH); + if (modemcfg == nil) + raise "fail: read: "+MODEM_DB_PATH; + modeminfo = ref mi; + + modeminfo.path = getcfgstring(modemcfg, "PATH"); + modeminfo.init = getcfgstring(modemcfg, "INIT"); + modeminfo.country = getcfgstring(modemcfg, "COUNTRY"); + modeminfo.other = getcfgstring(modemcfg, "OTHER"); + modeminfo.errorcorrection = getcfgstring(modemcfg,"CORRECT"); + modeminfo.compression = getcfgstring(modemcfg,"COMPRESS"); + modeminfo.flowctl = getcfgstring(modemcfg,"FLOWCTL"); + modeminfo.rateadjust = getcfgstring(modemcfg,"RATEADJ"); + modeminfo.mnponly = getcfgstring(modemcfg,"MNPONLY"); + modeminfo.dialtype = getcfgstring(modemcfg,"DIALING"); + if(modeminfo.dialtype!="ATDP") + modeminfo.dialtype="ATDT"; + + cfg->verify(DEFAULT_ISP_DB_PATH, ISP_DB_PATH); + (ok, stat) := sys->stat(ISP_DB_PATH); + if(ok >= 0) + lastCdir = ref stat; + sys->print("cfg->init(%s)\n", ISP_DB_PATH); + + # ISP Configuration + pppcfg := cfg->init(ISP_DB_PATH); + if (pppcfg == nil) + raise "fail: Couldn't load ISP configuration file: "+ISP_DB_PATH; + pppinfo = ref pppi; + isp_number = getcfgstring(pppcfg, "NUMBER"); + pppinfo.ipaddr = getcfgstring(pppcfg,"IPADDR"); + pppinfo.ipmask = getcfgstring(pppcfg,"IPMASK"); + pppinfo.peeraddr = getcfgstring(pppcfg,"PEERADDR"); + pppinfo.maxmtu = getcfgstring(pppcfg,"MAXMTU"); + pppinfo.username = getcfgstring(pppcfg,"USERNAME"); + pppinfo.password = getcfgstring(pppcfg,"PASSWORD"); + + info = pppcfg.getcfg("SCRIPT"); + if (info != nil) { + scriptinfo = ref Script->ScriptInfo; + scriptinfo.path = hd info; + scriptinfo.username = pppinfo.username; + scriptinfo.password = pppinfo.password; + } else + scriptinfo = nil; + + info = pppcfg.getcfg("TIMEOUT"); + if (info != nil) + scriptinfo.timeout = int (hd info); + + cfg = nil; # might as well unload it +} + +# +# Parts of the following two functions could be generalized +# + +isipaddr(a: string): int +{ + i, c, ac, np: int = 0; + + for(i = 0; i < len a; i++) { + c = a[i]; + if(c >= '0' && c <= '9') { + np = 10*np + c - '0'; + continue; + } + if (c == '.' && np) { + ac++; + if (np > 255) + return 0; + np = 0; + continue; + } + return 0; + } + return np && np < 256 && ac == 3; +} + +# check if there is an existing PPP connection +connected(): int +{ + ifd := sys->open("/net/ipifc", Sys->OREAD); + if(ifd == nil) + return 0; + + buf := array[1024] of byte; + + for(;;) { + (n, d) := sys->dirread(ifd); + if (n <= 0) + return 0; + for(i := 0; i < n; i++) + if(d[i].name[0] <= '9') { + sfd := sys->open("/net/ipifc/"+d[i].name+"/status", Sys->OREAD); + if (sfd == nil) + continue; + ns := sys->read(sfd, buf, len buf); + if (ns <= 0) + continue; + (nflds, flds) := sys->tokenize(string buf[0:ns], " \t\r\n"); + if(nflds < 4) + continue; + if (isipaddr(hd tl tl flds)) + return 1; + } + } +} + +# +# called once when loaded +# +init(ctxt: ref Draw->Context): string +{ + sys = load Sys Sys->PATH; + { + ppp = load PPPClient PPPClient->PATH; + if (ppp == nil) + raise "fail: Couldn't load ppp module"; + + # Contruct Config Tables During Init - may want to change later + # for multiple configs (Software Download Server versus ISP) + configinit(); + context = ctxt; + }exception e { + "fail:*" => + return e; + } + return nil; +} + +dialup_cancelled := 0; +connecting := 0; + +# +# called each time a translation is needed, to check that we're on line(!) +# eventually this will be replaced by a packet interface that does dial-on-demand +# +connect(): string +{ + { + dialup_cancelled = 0; + (ok, stat) := sys->stat(ISP_DB_PATH); + if (ok < 0 || lastCdir == nil || !samefile(*lastCdir, stat)) + configinit(); + errc := chan of string; + while(!connected()){ + if(!connecting) { + connecting = 1; + sync := chan of int; + spawn pppconnect(errc, sync); + <- sync; + return <-errc; + }else{ + sys->sleep(2500); + if (dialup_cancelled) + return "fail: dialup cancelled"; + } + } + }exception e{ + "fail:*" => + return e; + "*" => + sys->print("pppdial: caught exception: %s\n", e); + return "fail: internal error: "+e; + } + return nil; +} + +pppconnect(errc: chan of string, sync: chan of int) +{ + connecting = 1; + sys->pctl(Sys->NEWPGRP, nil); + sync <-= 0; + resp_chan: chan of int; + logger := chan of int; + pppgui := load PPPGUI PPPGUI->PATH; + for (count :=0; count < ISP_RETRIES; count++) { + resp_chan = pppgui->init(context, logger, ppp, nil); + spawn ppp->connect(modeminfo, isp_number, scriptinfo, pppinfo, logger); + x := <-resp_chan; + if (x > 0) { + if (x == 1) { + # alt needed in case calling process has been killed + alt { + errc <-= nil => ; + * => ; + } + } else { # user cancelled dial-in + dialup_cancelled = 1; + alt { + errc <-= "fail: dialup cancelled" => ; + * => ; + } + } + connecting = 0; + return; + } + # else connect failed, go around loop to try again + } + alt { + errc <-= "fail: dialup failed" => ; + * => ; + } + connecting = 0; +} + +samefile(d1, d2: Sys->Dir): int +{ + return d1.dev==d2.dev && d1.dtype==d2.dtype && + d1.qid.path==d2.qid.path && d1.qid.vers==d2.qid.vers && + d1.mtime==d2.mtime; +} diff --git a/appl/cmd/ip/ppp/pppgui.b b/appl/cmd/ip/ppp/pppgui.b new file mode 100644 index 00000000..40e7e3b4 --- /dev/null +++ b/appl/cmd/ip/ppp/pppgui.b @@ -0,0 +1,373 @@ +# +# Copyright © 1998 Lucent Technologies Inc. All rights reserved. +# Revisions copyright © 2000,2001 Vita Nuova Holdings Limited. All rights reserved. +# +# Originally Written by N. W. Knauft +# Adapted by E. V. Hensbergen (ericvh@lucent.com) +# Further adapted by Vita Nuova +# + +implement PPPGUI; + +include "sys.m"; + sys: Sys; + +include "draw.m"; + draw: Draw; + +include "tk.m"; + tk: Tk; + +include "tkclient.m"; + tkclient: Tkclient; + +include "translate.m"; + translate: Translate; + Dict: import translate; + dict: ref Dict; + +include "lock.m"; +include "modem.m"; +include "script.m"; +include "pppclient.m"; + ppp: PPPClient; + +include "pppgui.m"; + +#Screen constants +BBG: con "#C0C0C0"; # Background color for button +PBG: con "#808080"; # Background color for progress bar +LTGRN: con "#00FF80"; # Color for progress bar +BARW: con 216; # Progress bar width +BARH: con " 9"; # Progress bar height +INCR: con 30; # Progress bar increment size +N_INCR: con 7; # Number of increments in progress bar width +BSIZE: con 25; # Icon button size +ISIZE: con BSIZE + 4; # Icon window size +DIALQUANTA : con 1000; +ICONQUANTA : con 5000; + +#Globals +pppquanta := DIALQUANTA; + +#Font +FONT: con "/fonts/lucidasans/unicode.6.font"; + +#Messages +stat_msgs := array[] of { + "Initializing Modem", + "Dialling Service Provider", + "Logging Into Network", + "Executing Login Script", + "Script Execution Complete", + "Logging Into Network", + "Verifying Password", + "Connected", + "", +}; + +config_icon := array[] of { + "button .btn -text X -width "+string BSIZE+" -height "+string BSIZE+" -command {send tsk open} -bg "+BBG, + "pack .btn", + + "pack propagate . no", + ". configure -bd 0", + ". unmap", + "update", +}; + + +# Create internet connect window, spawn event handler +init(ctxt: ref Draw->Context, stat: chan of int, pppmod: PPPClient, args: list of string): chan of int +{ + sys = load Sys Sys->PATH; + draw = load Draw Draw->PATH; + tk = load Tk Tk->PATH; + tkclient = load Tkclient Tkclient->PATH; + + if (draw == nil || tk == nil || tkclient == nil) { + sys->fprint(sys->fildes(2), "pppgui: can't load Draw or Tk: %r\n"); + return nil; + } + + translate = load Translate Translate->PATH; + if(translate != nil) { + translate->init(); + dictname := translate->mkdictname("", "pppgui"); + dicterr: string; + (dict, dicterr) = translate->opendict(dictname); + if(dicterr != nil) + sys->fprint(sys->fildes(2), "pppgui: can't open %s: %s\n", dictname, dicterr); + }else + sys->fprint(sys->fildes(2), "pppgui: can't load %s: %r\n", Translate->PATH); + ppp = pppmod; # set the global + + tkargs := ""; + + if (args != nil) { + tkargs = hd args; + args = tl args; + } else + tkargs="-x 340 -y 4"; + + tkclient->init(); + + (t, wmctl) := tkclient->toplevel(ctxt, tkargs, "PPP", Tkclient->Plain); + + config_win := array[] of { + "frame .f", + "frame .fprog", + + "canvas .cprog -bg "+PBG+" -bd 2 -width "+string BARW+" -height "+BARH+" -relief ridge", + "pack .cprog -in .fprog -pady 6", + + "label .stat -text {"+X("Initializing connection...")+"} -width 164 -font "+FONT, + "pack .stat -in .f -side left -fill y -anchor w", + + "button .done -text {"+X("Cancel")+"} -width 60 -command {send cmd cancel} -bg "+BBG+" -font "+FONT, + "pack .fprog -side bottom -expand 1 -fill x", + "pack .done -side right -padx 1 -pady 1 -fill y -anchor e", + "pack .f -side left -expand 1 -padx 5 -pady 3 -fill both -anchor w", + + "pack propagate . no", + ". configure -bd 2 -relief raised -width "+string WIDTH, + "update", + }; + + for(i := 0; i < len config_win; i++) + tk->cmd(t, config_win[i]); + + itkargs := ""; + if (args != nil) { + itkargs = hd args; + args = tl args; + } + tkclient->onscreen(t, nil); + tkclient->startinput(t, "ptr" :: nil); + + if (itkargs == "") { + x := int tk->cmd(t, ". cget x"); + y := int tk->cmd(t, ". cget y"); + x += WIDTH - ISIZE; + itkargs = "-x "+string x+" -y "+string y; + } + + (ticon, iconctl) := tkclient->toplevel(ctxt, itkargs, "PPP", Tkclient->Plain); + + for( i = 0; i < len config_icon; i++) + tk->cmd(ticon, config_icon[i]); + + tk->cmd(ticon, "image create bitmap Network -file network.bit -maskfile network.bit"); + tk->cmd(ticon, ".btn configure -image Network"); + tkclient->startinput(ticon, "ptr"::nil); + + chn := chan of int; + spawn handle_events(t, wmctl, ticon, iconctl, stat, chn); + return chn; +} + +ppp_timer(sync: chan of int, stat: chan of int) +{ + for(;;) { + sys->sleep(pppquanta); + alt { + <-sync => + return; + stat <-= -1 => + ; + } + } +} + +send(cmd: chan of string, msg: string) +{ + cmd <-= msg; +} + +# Process events and pass disconnect cmd to calling app +handle_events(t: ref Tk->Toplevel, wmctl: chan of string, ticon: ref Tk->Toplevel, iconctl: chan of string, stat, chn: chan of int) +{ + sys->pctl(Sys->NEWPGRP, nil); + cmd := chan of string; + tk->namechan(t, cmd, "cmd"); + + tsk := chan of string; + tk->namechan(ticon, tsk, "tsk"); + + connected := 0; + winmapped := 1; + timecount := 0; + xmin := 0; + x := 0; + + iocmd := sys->file2chan("/chan", "pppgui"); + if (iocmd == nil) { + sys->print("fail: pppgui: file2chan: /chan/pppgui: %r\n"); + return; + } + + pppquanta = DIALQUANTA; + sync_chan := chan of int; + spawn ppp_timer(sync_chan, stat); + +Work: + for(;;) alt { + s := <-t.ctxt.kbd => + tk->keyboard(t, s); + + s := <-t.ctxt.ptr => + tk->pointer(t, *s); + + s := <-t.ctxt.ctl or + s = <-t.wreq or + s = <-wmctl => + tkclient->wmctl(t, s); + + s := <-ticon.ctxt.kbd => + tk->keyboard(ticon, s); + s := <-ticon.ctxt.ptr => + tk->pointer(ticon, *s); + s := <-ticon.ctxt.ctl or + s = <-ticon.wreq or + s = <-iconctl => + tkclient->wmctl(ticon, s); + + (off, data, fid, wc) := <-iocmd.write => # remote io control + if (wc == nil) + break; + spawn send(cmd, string data[0:len data]); + wc <-= (len data, nil); + + (nil, nbytes, fid, rc) := <-iocmd.read => + if (rc != nil) + rc <-= (nil, "not readable"); + + press := <-cmd => + case press { + "cancel" or "disconnect" => + tk->cmd(t, ".stat configure -text 'Disconnecting..."); + tk->cmd(t, "update"); + ppp->reset(); + if (!connected) { + # other end may have gone away + alt { + chn <-= 666 => ; + * => ; + } + } + break Work; + * => ; + } + + prs := <-tsk => + case prs { + "open" => + tk->cmd(ticon, ". unmap; update"); + tk->cmd(t, ". map; raise .; update"); + winmapped = 1; + timecount = 0; + * => ; + } + + s := <-stat => + if (s == -1) { # just an update event + if(winmapped){ + if(!connected) { # increment status bar + if (x < xmin+INCR) { + x++; + tk->cmd(t, ".cprog create rectangle 0 0 "+string x + BARH+" -fill "+LTGRN); + } + }else{ + timecount++; + if(timecount > 1){ + winmapped = 0; + timecount = 0; + tk->cmd(t, ". unmap; update"); + tk->cmd(ticon, ". map; raise .; update"); + continue; + } + } + tk->cmd(t, "raise .; update"); + } else { + tk->cmd(ticon, "raise .; update"); + timecount = 0; + } + continue; + } + if (s == ppp->s_Error) { + tk->cmd(t, ".stat configure -text '"+ppp->lasterror); + if (!winmapped) { + tk->cmd(ticon, ". unmap; update"); + tk->cmd(t, ". map; raise ."); + } + tk->cmd(t, "update"); + sys->sleep(3000); + ppp->reset(); + if (!connected) + chn <-= 0; # Failure + break Work; + } + + if (s == ppp->s_Initialized) + tk->cmd(t,".cprog create rectangle 0 0 "+string BARW + BARH+" -fill "+PBG); + + x = xmin = s * INCR; + if (xmin > BARW) + xmin = BARW; + tk->cmd(t, ".cprog create rectangle 0 0 "+string xmin + BARH+" -fill "+LTGRN); + tk->cmd(t, "raise .; update"); + tk->cmd(t, ".stat configure -text '"+X(stat_msgs[s])); + + if (s == ppp->s_SuccessPPP || s == ppp->s_Done) { + if(!connected){ + chn <-= 1; + connected = 1; + } + pppquanta = ICONQUANTA; + + # find and display connection speed + speed := findrate("/dev/modemstat", "rcvrate" :: "baud" :: nil); + if(speed != nil) + tk->cmd(t, ".stat configure -text {"+X(stat_msgs[s])+" "+speed+" bps}"); + else + tk->cmd(t, ".stat configure -text {"+X(stat_msgs[s])+"}"); + tk->cmd(t, ".done configure -text Disconnect -command 'send cmd disconnect"); + tk->cmd(t, "update"); + sys->sleep(2000); + tk->cmd(t, ". unmap; pack forget .fprog; update"); + winmapped = 0; + tk->cmd(ticon, ". map; raise .; update"); + } + + tk->cmd(t, "update"); + } + sync_chan <-= 1; # stop ppp_timer +} + +findrate(file: string, opt: list of string): string +{ + fd := sys->open(file, sys->OREAD); + if(fd == nil) + return nil; + buf := array [1024] of byte; + n := sys->read(fd, buf, len buf); + if(n <= 1) + return nil; + (nil, flds) := sys->tokenize(string buf[0:n], " \t\r\n"); + for(; flds != nil; flds = tl flds) + for(l := opt; l != nil; l = tl l) + if (hd flds == hd l) + return hd tl flds; + return nil; +} + + + +# Translate a string + +X(s : string) : string +{ + if (dict== nil) return s; + return dict.xlate(s); +} + diff --git a/appl/cmd/ip/ppp/pppgui.m b/appl/cmd/ip/ppp/pppgui.m new file mode 100644 index 00000000..af9ec574 --- /dev/null +++ b/appl/cmd/ip/ppp/pppgui.m @@ -0,0 +1,21 @@ +# +# Copyright © 1998 Lucent Technologies Inc. All rights reserved. +# Revisions copyright © 2000,2001 Vita Nuova Holdings Limited. All rights reserved. +# +# Originally Written by N. W. Knauft +# Adapted by E. V. Hensbergen (ericvh@lucent.com) +# Further adapted by Vita Nuova +# + +PPPGUI: module +{ + PATH: con "/dis/ip/ppp/pppgui.dis"; + + # Dimension constant for ISP Connect window + WIDTH: con 300; + HEIGHT: con 58; + + init: fn(ctxt: ref Draw->Context, stat: chan of int, + ppp: PPPClient, args: list of string): chan of int; +}; + diff --git a/appl/cmd/ip/ppp/ppptest.b b/appl/cmd/ip/ppp/ppptest.b new file mode 100644 index 00000000..e5dfced0 --- /dev/null +++ b/appl/cmd/ip/ppp/ppptest.b @@ -0,0 +1,86 @@ +# Last change: R 24 May 2001 11:05 am +implement PPPTest; + +include "sys.m"; + sys: Sys; +include "draw.m"; + +include "lock.m"; +include "modem.m"; +include "script.m"; +include "pppclient.m"; +include "pppgui.m"; + +PPPTest: module { + init: fn(nil: ref Draw->Context, args: list of string); +}; +usage() +{ + sys->print("ppptest device modem_init tel user password \n"); + sys->print("Example: ppptest /dev/modem atw2 4125678 rome xxxxxxxx\n"); + exit; + +} +init( ctxt: ref Draw->Context, argv: list of string ) +{ + sys = load Sys Sys->PATH; + + mi: Modem->ModemInfo; + pi: PPPClient->PPPInfo; + tel : string; +# si: Script->ScriptInfo; + argv = tl argv; + if(argv == nil) + usage(); + else + mi.path = hd argv; + + argv = tl argv; + if(argv == nil) + usage(); + else + mi.init = hd argv; + argv = tl argv; + if(argv == nil) + usage(); + else + tel = hd argv; + argv = tl argv; + if(argv == nil) + usage(); + else + pi.username = hd argv; + argv = tl argv; + if(argv==nil) + usage(); + else + pi.password = hd argv; + + + #si.path = "rdid.script"; + #si.username = "ericvh"; + #si.password = "foobar"; + #si.timeout = 60; + + + ppp := load PPPClient PPPClient->PATH; + + logger := chan of int; + + spawn ppp->connect( ref mi, tel, nil, ref pi, logger ); + + pppgui := load PPPGUI PPPGUI->PATH; + respchan := pppgui->init( ctxt, logger,ppp, nil); + + event := 0; + while (1) { + event =<- respchan; + sys->print("GUI event received: %d\n",event); + if (event) { + sys->print("success"); + exit; + } else { + raise "fail: Couldn't connect to ISP"; + } + } +} diff --git a/appl/cmd/ip/ppp/script.b b/appl/cmd/ip/ppp/script.b new file mode 100644 index 00000000..8be184a4 --- /dev/null +++ b/appl/cmd/ip/ppp/script.b @@ -0,0 +1,168 @@ +implement Script; + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "string.m"; + str: String; + +include "lock.m"; +include "modem.m"; + modem: Modem; + +include "script.m"; + +delim: con "-"; # expect-send delimiter +BUFSIZE: con (1024 * 32); + +execute( modmod: Modem, m: ref Modem->Device, scriptinfo: ref ScriptInfo ) +{ + sys= load Sys Sys->PATH; + str= load String String->PATH; + if (str == nil) { + raise "fail: couldn't load string module"; + return; + } + modem = modmod; + + if (scriptinfo.path != nil) { + sys->print("Executing Script %s\n",scriptinfo.path); + # load the script + scriptinfo.content = scriptload(scriptinfo.path); + } else { + sys->print("Executing Inline Script\n"); + } + + # Check for timeout variable + + if (scriptinfo.timeout == 0) + scriptinfo.timeout = 20; + + tend := sys->millisec() + 1000*scriptinfo.timeout; + + conv := scriptinfo.content; + + while (conv != nil) { + e, s: string = nil; + p := hd conv; + conv = tl conv; + if (len p == 0) + continue; + sys->print("script: %s\n",p); + if (p[0] == '-') { # just send + if (len p == 1) + continue; + s = p[1:]; + } else { + (n, esl) := sys->tokenize(p, delim); + if (n > 0) { + e = hd esl; + esl = tl esl; + if (n > 1) + s = hd esl; + } + } + if (e != nil) { + if (match(m, special(e,scriptinfo), tend-sys->millisec()) == 0) { + sys->print("script: match failed\n"); + raise "fail: Script Failed"; + return; + } + } + if (s != nil) + modem->send(m, special(s, scriptinfo)); + } + + sys->print("script: done!\n"); +} + +match(m: ref Modem->Device, s: string, timo: int): int +{ + for(;;) { + c := modem->getc(m, timo); + if (c == '\r') + c = '\n'; + sys->print("%c",c); + if (c == 0) + return 0; + head: + while(c == s[0]) { + i := 1; + while(i < len s) { + c = modem->getc(m, timo); + if (c == '\r') + c = '\n'; + sys->print("%c",c); + if(c == 0) + return 0; + if(c != s[i]) + continue head; + i++; + } + return 1; + } + if(c == '~') + return 1; # assume PPP for now + } +} + +# +# Expand special script sequences +# +special(s: string, scriptinfo: ref ScriptInfo ): string +{ + if (s == "$username") # special variable + s = scriptinfo.username; + else if (s == "$password") + s = scriptinfo.password; + + return deparse(s); +} + +deparse(s : string) : string +{ + r: string = ""; + for(i:=0; i < len s; i++) { + c := s[i]; + if (c == '\\' && i+1 < len s) { + c = s[++i]; + case c { + 't' => c = '\t'; + 'n' => c = '\n'; + 'r' => c = '\r'; + 'b' => c = '\b'; + 'a' => c = '\a'; + 'v' => c = '\v'; + '0' => c = '\0'; + '$' => c = '$'; + 'u' => + if (i+4 < len s) { + i++; + (c, nil) = str->toint(s[i:i+4], 16); + i+=3; + } + } + } + r[len r] = c; + } + return r; +} + +scriptload( path: string) :list of string +{ + dfd := sys->open(path, Sys->OREAD); + if (dfd == nil) { + raise "fail: Script file ("+path+") not found"; + return nil; + } + + scriptbuf := array[BUFSIZE] of byte; + scriptlen := sys->read(dfd, scriptbuf, len scriptbuf); + if(scriptlen < 0) + raise "fail: can't read script: "+sys->sprint("%r"); + + (nil, scriptlist) := sys->tokenize(string scriptbuf[0:scriptlen], "\n"); + return scriptlist; +} diff --git a/appl/cmd/ip/ppp/script.m b/appl/cmd/ip/ppp/script.m new file mode 100644 index 00000000..342d4d79 --- /dev/null +++ b/appl/cmd/ip/ppp/script.m @@ -0,0 +1,14 @@ +Script: module { + PATH: con "/dis/ip/ppp/script.dis"; + + ScriptInfo: adt { + path: string; + content: list of string; + timeout: int; + username: string; + password: string; + }; + + execute: fn( modem: Modem, m: ref Modem->Device, + scriptinfo: ref ScriptInfo ); +}; |
