netobj/src/NetObj.m3


 Copyright 1992 Digital Equipment Corporation.               
 Distributed only by permission.                             
 NetObj.m3 
 Last modified on Tue Jan 31 08:49:10 PST 1995 by kalsow 
      modified on Fri Jun  4 11:59:57 PDT 1993 by wobber 
      modified on Thu Sep 17 16:24:24 PDT 1992 by evers  

MODULE NetObj EXPORTS NetObj, TransportRegistry;

IMPORT NetObjMon, RTParams;

IMPORT Atom, AtomList, IP, SpecialObj, Transport, NetObjInit, NetObjMonInit,
       TCPNetObj, TCPTransport, Thread;

<* PRAGMA LL *>

PROCEDURE Locate(host: TEXT) : Address
    RAISES {Invalid, Error} =
  VAR ep: IP.Endpoint;
  BEGIN
    TRY
      IF NOT IP.GetHostByName(host, ep.addr) THEN RAISE Invalid; END;
      ep.port := IP.NullPort;
    EXCEPT
    | IP.Error(ec) => RAISE Error(AtomList.Cons(CommFailure, ec));
    END;
    RETURN TCPNetObj.Locate(ep);
  END Locate;

PROCEDURE Export(name: TEXT; obj: T; where: Address := NIL)
    RAISES {Error, Thread.Alerted} =
  BEGIN
    CheckMonitorExport();
    GetSpecial(where).put(name, obj);
  END Export;

PROCEDURE Import(name: TEXT; where: Address := NIL) : T
    RAISES {Error, Thread.Alerted} =
  BEGIN
    CheckMonitorExport();
    RETURN GetSpecial(where).get(name);
  END Import;
assume this is initialized in main body no mutex is needed

CONST MaxTransports = 10;
VAR transports: ARRAY [0..MaxTransports-1] OF Transport.T;
VAR lastTransport: CARDINAL;

PROCEDURE LocationFromAdr(where: Address) : Transport.Location =
  VAR loc: Transport.Location;
  BEGIN
    IF where # NIL THEN
      FOR i := 0 TO lastTransport DO
        FOR j := 0 TO LAST(where^) DO
          loc := transports[i].fromEndpoint(where[j]);
          IF loc # NIL THEN RETURN loc; END;
        END;
      END;
    END;
    RETURN NIL;
  END LocationFromAdr;

PROCEDURE LocalAdr() : Address =
  VAR
    adr := NEW(Address, lastTransport+1);
  BEGIN
    FOR i := 0 TO lastTransport DO
      adr[i] := transports[i].toEndpoint();
    END;
    RETURN adr;
  END LocalAdr;

REVEAL
  Iterator = IteratorPublic BRANDED OBJECT
    i: CARDINAL := 0;
  OVERRIDES
    next := IteratorNext;
  END;

EXCEPTION FatalError; <* FATAL FatalError *>

PROCEDURE Iterate (): Iterator =
  BEGIN
    RETURN NEW (Iterator);
  END Iterate;

PROCEDURE IteratorNext (it: Iterator; VAR (*OUT*) tr: Transport.T): BOOLEAN =
  BEGIN
    IF it.i > lastTransport + 1 THEN
      RAISE FatalError
    ELSIF it.i = lastTransport + 1 THEN
      INC (it.i);
      RETURN FALSE;
    ELSE
      tr := transports[it.i];
      INC (it.i);
      RETURN TRUE;
    END;
  END IteratorNext;

VAR
  mu := NEW(MUTEX);
  localSpecialObj: SpecialObj.ST := NIL;

PROCEDURE GetSpecial(where: Address) : SpecialObj.ST
    RAISES {Error} =
  VAR loc: Transport.Location;
  BEGIN
    IF where = NIL THEN
      LOCK mu DO
        IF localSpecialObj # NIL THEN RETURN localSpecialObj; END;
        loc := LocationFromAdr(TCPNetObj.Locate(IP.NullEndPoint));
        <* ASSERT loc # NIL *>
        localSpecialObj := SpecialObj.New(loc);
        RETURN localSpecialObj;
      END;
    ELSE
      loc := LocationFromAdr(where);
      IF loc = NIL THEN RAISE Error(AtomList.List1(NoTransport)); END;
      RETURN SpecialObj.New(loc);
    END;
  END GetSpecial;

VAR <* LL >= {mu} *>
  exportMonitor   := RTParams.IsPresent("ngcmonitor");
  monitorExported := FALSE;

PROCEDURE CheckMonitorExport () =
  BEGIN
    LOCK mu DO
      IF exportMonitor AND NOT monitorExported THEN
      	EVAL Thread.Fork(NEW (Thread.Closure, apply := ExportMonitor));
        monitorExported := TRUE;
      END;
    END;
  END CheckMonitorExport;

PROCEDURE ExportMonitor (<*UNUSED*> cl: Thread.Closure): REFANY =
  BEGIN
    NetObjMon.Register();
      (* this export will fail silently if there is no listener on
      	 the daemon port yet *)
    RETURN NIL;
  END ExportMonitor;

BEGIN
  CommFailure := Atom.FromText("NetObj.CommFailure");
  MissingObject := Atom.FromText("NetObj.MissingObject");
  NoResources := Atom.FromText("NetObj.NoResources");
  NoTransport := Atom.FromText("NetObj.NoTransport");
  UnsupportedDataRep := Atom.FromText("NetObj.UnsupportedDataRep");
  Alerted := Atom.FromText("NetObj.Alerted");

  transports[0] := TCPTransport.New();
  lastTransport := 0;

  NetObjInit.InitAgentStubs();
  NetObjInit.InitVoucherStubs();
  NetObjMonInit.InitMonitorStubs();
  NetObjMonInit.InitRegistryStubs();

END NetObj.