-- Transport Mechanism Mail Server - Miscellaneous socket communication --

-- [Ivy]<DMS>MS>MiscSoc.mesa

-- Randy Gobbel		29-May-81 14:44:13 --
-- Andrew Birrell	13-Jan-81 11:15:27 --
-- Mark Johnson		May 28, 1981  2:29 PM --

DIRECTORY
BodyDefs	USING[ maxRNameLength, RName ],
BufferDefs,
Inline		USING[ LongCOPY ],
MailboxDefs	USING[ Poll ],
PolicyDefs	USING[ ProdServersPause ],
Process		USING[ Detach ],
ProtocolDefs	USING[ Init, mailServerPollingSocket ],
PupDefs		USING[ GetFreePupBuffer, GetPupContentsBytes, PupBuffer,
		       PupRouterSendThis, PupSocket, PupSocketMake,
		       ReturnFreePupBuffer, SetPupContentsWords,
		       SwapPupSourceAndDest, veryLongWait ],
PupTypes	USING[ echoSoc, fillInSocketID, PupAddress,
		       PupType ],
RestartDefs, --EXPORT only--
ServerDefs	USING[ EnumerateAll, NoSuchServer, ServerAddr, ServerHandle,
		       ServerNotUp, ServerUp, UpServer ],
SiteCacheDefs	USING[ SingleFlush ],
Storage		USING[ FreeString, String ],
String		USING[ WordsForString];

MiscSoc: MONITOR
   IMPORTS Inline, MailboxDefs, PolicyDefs, Process, ProtocolDefs,
           PupDefs, ServerDefs, SiteCacheDefs, Storage, String
   EXPORTS RestartDefs--PROGRAM-- =

BEGIN


poll: PupDefs.PupSocket = PupDefs.PupSocketMake[
             ProtocolDefs.mailServerPollingSocket, , PupDefs.veryLongWait ];
prod: PupDefs.PupSocket = PupDefs.PupSocketMake[
             PupTypes.fillInSocketID, , PupDefs.veryLongWait ];
echo: PupDefs.PupSocket = PupDefs.PupSocketMake[
             PupTypes.echoSoc, , PupDefs.veryLongWait ];

UnexpectedTimeout: ERROR = CODE;

AcceptPoll: PROCEDURE =
   BEGIN
   DO BEGIN
      b: PupDefs.PupBuffer = poll.get[];
      IF b = NIL THEN ERROR UnexpectedTimeout[];
      SELECT b.pupType FROM
         mailCheckLaurel =>
           BEGIN
           client: BodyDefs.RName = [BodyDefs.maxRNameLength];
           pLength: CARDINAL = PupDefs.GetPupContentsBytes[b];
           IF pLength > BodyDefs.maxRNameLength
           THEN b.pupType ← mailNotNew
           ELSE BEGIN
                Inline.LongCOPY[from: @(b.pupString), to: @(client.text),
                                nwords: (1+pLength)/2 ];
                client.length ← pLength;
                b.pupType ← IF MailboxDefs.Poll[client]
                            THEN mailIsNew
                            ELSE mailNotNew;
                END;
           PupDefs.SwapPupSourceAndDest[b];
           PupDefs.SetPupContentsWords[b,0];
           PupDefs.PupRouterSendThis[b];
           END;
         echoMe =>
           BEGIN
           PupDefs.SwapPupSourceAndDest[b];
           b.pupType ← iAmEcho;
           PupDefs.PupRouterSendThis[b];
           END;
         LOOPHOLE[215B] => -- LOOPHOLE to get around difference in Pilot/Alto PupTypes --
           BEGIN-- cache-flush request from other M-Server --
           nameString: LONG STRING =
	     IF SIZE[PupDefs.PupBuffer] = 1 THEN LONG[LOOPHOLE[@(b.pupWords)]]
	     ELSE LOOPHOLE[@(b.pupWords)];
	   name: BodyDefs.RName = Storage.String[nameString.length];
	   Inline.LongCOPY[from: nameString, to: name, nwords: String.WordsForString[name.length]];
           IF name.length <= BodyDefs.maxRNameLength
           THEN SiteCacheDefs.SingleFlush[name];
           PupDefs.ReturnFreePupBuffer[b];
	   Storage.FreeString[name];
           END;
      ENDCASE => PupDefs.ReturnFreePupBuffer[b];
      END;
   ENDLOOP;
   END;

PollForUpServer: PROCEDURE[ server: ServerDefs.ServerHandle ] =
   BEGIN
   ENABLE
      BEGIN
      ServerDefs.NoSuchServer => GOTO notFound;
      ServerDefs.ServerNotUp => GOTO notUp;
      END;
   IF NOT ServerDefs.ServerUp[server]
   THEN BEGIN
        dest: PupTypes.PupAddress ← ServerDefs.ServerAddr[server];
        b: PupDefs.PupBuffer ← PupDefs.GetFreePupBuffer[];
        PupDefs.SetPupContentsWords[b, 0];
        b.pupType ← echoMe;
        b.pupID ← [a: LOOPHOLE[server], b: 0];
        dest.socket ← SELECT server.type FROM
                        mail => ProtocolDefs.mailServerPollingSocket,
                        foreign => PupTypes.echoSoc,
                      ENDCASE => ERROR;
        prod.setRemoteAddress[dest];
        prod.put[b];
        END;
   EXITS
      notFound => -- no such server -- NULL;
      notUp => -- R-Servers not up, etc -- NULL;
   END;

ProdServers: PROC =
   BEGIN
   DO PolicyDefs.ProdServersPause[];
      ServerDefs.EnumerateAll[PollForUpServer];
   ENDLOOP;
   END;
   
ProdReply: PROCEDURE =
   BEGIN
   DO BEGIN
      b: PupDefs.PupBuffer = prod.get[];
      IF b = NIL THEN ERROR UnexpectedTimeout[];
      SELECT b.pupType FROM
         iAmEcho, --MTP (IFS doesn't echo)-- error =>
           BEGIN
           maybe: ServerDefs.ServerHandle = LOOPHOLE[b.pupID.a];
           Work: PROCEDURE[ really: ServerDefs.ServerHandle ] =
              BEGIN
              IF really = maybe
              AND( b.pupType = iAmEcho OR really.type = foreign )
              THEN ServerDefs.UpServer[really];
              END;
           PupDefs.ReturnFreePupBuffer[b];
           ServerDefs.EnumerateAll[Work];
           END;
      ENDCASE => PupDefs.ReturnFreePupBuffer[b];
      END;
   ENDLOOP;
   END;

Echo: PROCEDURE =
   BEGIN
   DO BEGIN
      b: PupDefs.PupBuffer = echo.get[];
      IF b = NIL THEN ERROR UnexpectedTimeout[];
      SELECT b.pupType FROM
         echoMe =>
           BEGIN
           PupDefs.SwapPupSourceAndDest[b];
           b.pupType ← iAmEcho;
           PupDefs.PupRouterSendThis[b];
           END;
      ENDCASE => PupDefs.ReturnFreePupBuffer[b];
      END;
   ENDLOOP;
   END;


ProtocolDefs.Init[];
Process.Detach[ FORK AcceptPoll[] ];
Process.Detach[ FORK ProdReply[] ];
Process.Detach[ FORK Echo[] ];
Process.Detach[ FORK ProdServers[] ];


END.