diff options
Diffstat (limited to 'appl/cmd/ip/ppp/pppdial.b')
| -rw-r--r-- | appl/cmd/ip/ppp/pppdial.b | 283 |
1 files changed, 283 insertions, 0 deletions
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; +} |
