home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / PNL Libraries / MyConnections.p < prev    next >
Encoding:
Text File  |  1995-11-02  |  17.3 KB  |  747 lines  |  [TEXT/CWIE]

  1. unit MyConnections;
  2.  
  3. { MyConnections © Peter N Lewis, 1993-95 }
  4.  
  5. interface
  6.  
  7.     uses
  8.         TCPTypes, MyTypes, MyTransport;
  9.  
  10.     const
  11.         tooManyConnections = -23099;
  12.         timeoutError = -23098;
  13.         failedToOpenError = -23097;
  14.  
  15. { Sequence: }
  16. { new(obj) }
  17. { oe:=obj.Create }
  18. { if oe=noErr then begin }
  19. {   do stuff}
  20. { end; }
  21. { obj.timetodie := true } { Don't call Destroy yourself }
  22.  
  23.     type
  24.         ConnectionBaseObject = object
  25.                 timetodie: boolean; { Set this to have Destroy called at the end of HandleConnection }
  26.                 connection_index: integer; { private! }
  27.                 closedone: boolean;
  28.                 heartbeat_period: longInt; { set to <=0 to disable heartbeats }
  29.                 heartbeat_time: longInt; { set to time of next heartbeat, it is automatically incrememnted by the period }
  30. { To enable heartbeats, set heartbeat_time to TickCount, and heartbeat_period to the period in ticks }
  31.                 timeout_time: longInt; { set to time to timeout TickCount }
  32.                 dnr_token: ptr;
  33.                 function Create: OSErr;
  34.                 procedure Destroy;
  35.                 procedure HeartBeat;
  36.                 procedure Failed (oe: OSErr);
  37.                 procedure Close;
  38.                 procedure HandleConnection;
  39.                 procedure SetHeartBeat(period: longint);
  40.             end;
  41.         NameSearchObject = object(ConnectionBaseObject)
  42.                 ip: longInt;
  43.                 procedure HandleConnection;
  44.                 override;
  45.                 procedure FindName (hostIP: longInt);
  46.                 procedure FoundName (name: Str255; error: OSErr);
  47.             end;
  48.         AddressSearchObject = object(ConnectionBaseObject)
  49.                 object_host: Str255;
  50.                 procedure HandleConnection;
  51.                 override;
  52.                 procedure FindAddress (hostName: Str255);
  53.                 procedure FoundAddress (ip: longInt);
  54.             end;
  55.         UDPObject = object(ConnectionBaseObject)
  56.                 tref: TransportUDPRef;
  57.                 localport: integer;
  58.                 function Create: OSErr;
  59.                 override;
  60.                 function CreatePort (buffersize: longInt; port: integer): OSErr;
  61.                 procedure Close;
  62.                 override;
  63.                 procedure Destroy;
  64.                 override;
  65.                 procedure HandleConnection;
  66.                 override;
  67.                 procedure PacketAvailable (remoteIP: longInt; remoteport: integer; datap: ptr; datalen: integer);
  68.                 procedure PacketsAvailable (count: integer);
  69.                 function SendPacket (remoteIP: longInt; remoteport: integer; datap: ptr; datalen: integer; checksum: boolean): OSErr;
  70.             end;
  71.         statusType = (CS_Opening, CS_Established, CS_Closing);
  72.         ConnectionObject = object(ConnectionBaseObject)
  73.                 tref: TransportRef;
  74.                 status: statusType;
  75.                 ourport: integer;
  76.                 input_buffer: Handle;
  77.                 output_buffer: Handle;
  78.                 transfer_error:OSStatus;
  79.                 do_send_close: Boolean;
  80.                 function Create: OSErr;
  81.                 override;
  82.                 procedure Destroy;
  83.                 override;
  84.                 procedure HandleConnection;
  85.                 override;
  86.                 procedure NewConnection (actve: boolean; buffersize: longInt; localport: integer; remotehost: Str255);
  87.                 procedure NewPassiveConnection (buffersize: longInt; localport: integer);
  88.                 procedure NewActiveConnection (buffersize: longInt; remotehost: Str255);
  89.                 procedure NewExistingConnection(newtref: TransportRef);
  90.                 procedure Close;
  91.                 override;
  92.                 procedure BeginConnection; { override these }
  93.                 procedure Established;
  94.                 procedure Closing;
  95.                 procedure CharsAvailable;
  96.                 procedure DoTransfer;
  97.                 procedure SendString (s: Str255);
  98.                 procedure SendData(datap: ptr; len: longint);
  99.             end;
  100.         LineConnectionObject = object(ConnectionObject)
  101.                 crlf: CRLFTypes;
  102.                 last_check: longInt; { last input_buffer size, dont recheck unless it changes }
  103.                 function Create: OSErr;
  104.                 override;
  105.                 procedure CharsAvailable;
  106.                 override;
  107.                 procedure SendLine (s: Str255);
  108.                 procedure LineAvailable (line: Str255);
  109.                 procedure CheckLineAvailable; { You can override this and use input_buffer yourself }
  110.             end;
  111.  
  112.     procedure StartupConnections;
  113. { You probably wont need these: }
  114.     function CanQuit: boolean;
  115.  
  116. implementation
  117.  
  118.     uses
  119.         Devices, TextUtils,
  120.         QLowLevel, 
  121.         DNR, MyStrings, MyMemory, MyMathUtils, MyStartup;
  122.  
  123.     const
  124.         TCPCMagic = 'TCPC';
  125.         TCPCBadMagic = 'badc';
  126.  
  127.     const  { Tuning parameters }
  128.         max_connections = 64;
  129.         TO_FindAddress = 40 * 60;
  130.         TO_FindName = 40 * 60;
  131.         TO_ActiveOpen = 20 * 60;
  132.         TO_Closing = longInt(2) * 60 * 60;
  133.         TO_PassiveOpen = longInt(1) * 365 * 24 * 3600 * 60;  { One years should be safe enough right? :-) }
  134.  
  135.     type
  136.         myHostInfo = record
  137.                 hi: hostInfo;
  138.                 done: signedByte;
  139.             end;
  140.         myHIP = ^myHostInfo;
  141.  
  142.     var
  143.         connections: array[1..max_connections] of ConnectionBaseObject;
  144.         quiting: boolean;
  145.  
  146.     function CanQuit: boolean;
  147.         var
  148.             i: integer;
  149.     begin
  150.         CanQuit := true;
  151.         for i := 1 to max_connections do begin
  152.             if connections[i] <> nil then begin
  153.                 CanQuit := false;
  154.                 leave;
  155.             end;
  156.         end;
  157.     end;
  158.  
  159.     function ConnectionBaseObject.Create: OSErr;
  160.         var
  161.             i: integer;
  162.             err: OSStatus;
  163.     begin
  164.         MoveHHi(handle(self));
  165.         HLock(handle(self));
  166.         dnr_token := nil;
  167.         err := noErr;
  168.         if quiting then begin
  169.             err := -12;
  170.         end;
  171.         if err = noErr then begin
  172.             err := OpenTransportSystem;
  173.         end;
  174.         if err = noErr then begin
  175.             i := 1;
  176.             while (i <= max_connections) & (connections[i] <> nil) do begin
  177.                 i := i + 1;
  178.             end;
  179.             if i <= max_connections then begin
  180.                 timetodie := false;
  181.                 connection_index := i;
  182.                 connections[i] := self;
  183.                 heartbeat_period := -1;
  184.                 heartbeat_time := 0;
  185.                 timeout_time := maxLongInt;
  186.                 closedone := false;
  187.             end else begin
  188.                 connection_index := -1;
  189.                 err := tooManyConnections;
  190.             end;
  191.         end;
  192.         Create := err;
  193.     end;
  194.  
  195.     procedure ConnectionBaseObject.Destroy;
  196.     begin
  197.         if connection_index > 0 then begin
  198.             connections[connection_index] := nil;
  199.         end;
  200.         TransportAbortDNR(dnr_token);
  201.         dispose(self);
  202.     end;
  203.  
  204.     procedure ConnectionBaseObject.HeartBeat;
  205.     begin
  206.     end;
  207.  
  208.     procedure ConnectionBaseObject.Failed (err: OSErr);
  209.     begin
  210.         err := err; { UNUSED! }
  211.         timetodie := true;
  212.     end;
  213.  
  214.     procedure ConnectionBaseObject.Close;
  215.     begin
  216.         closedone := true;
  217.     end;
  218.  
  219.     procedure ConnectionBaseObject.SetHeartBeat(period: longint);
  220.         var
  221.             time: longint;
  222.     begin
  223.         time := TickCount;
  224.         if (heartbeat_period <= 0) or (period < 0) then begin
  225.             heartbeat_time := time;
  226.         end;
  227.         heartbeat_period := period;
  228.         if heartbeat_time < time then begin
  229.             heartbeat_time := time;
  230.         end;
  231.         if (heartbeat_period > 0) & (heartbeat_time > time + heartbeat_period) then begin
  232.             heartbeat_time := time + heartbeat_period;
  233.         end;
  234.     end;
  235.  
  236.     procedure ConnectionBaseObject.HandleConnection;
  237.         var
  238.             now: longInt;
  239.     begin
  240.         now := TickCount;
  241.         if now > timeout_time then begin
  242.             timeout_time := maxLongInt;
  243.             Failed(timeoutError);
  244.         end else if (heartbeat_period > 0) & (now >= heartbeat_time) then begin
  245.             HeartBeat;
  246.             heartbeat_time := heartbeat_time + heartbeat_period;
  247.             if heartbeat_time < now then begin
  248.                 heartbeat_time := now;
  249.             end;
  250.         end;
  251.     end;
  252.  
  253.     procedure AddressSearchObject.FindAddress (hostName: Str255);
  254.         var
  255.             err: OSErr;
  256.     begin
  257.         err := Create;
  258.         if err = noErr then begin
  259.             object_host := hostName;
  260.             err := TransportNameToAddr(hostName, dnr_token);
  261.             timeout_time := TickCount + TO_FindAddress;
  262.         end;
  263.         if err <> noErr then begin
  264.             Failed(err);
  265.             timetodie := true;
  266.         end;
  267.     end;
  268.  
  269.     procedure AddressSearchObject.FoundAddress (ip: longInt);
  270.     begin
  271.         ip := ip; { UNUSED! }
  272.     end;
  273.  
  274.     procedure AddressSearchObject.HandleConnection;
  275.         var
  276.             result: OSStatus;
  277.             addr:IPAddr;
  278.     begin
  279.         inherited HandleConnection;
  280.         if not timetodie then begin
  281.             TransportGetNameToAddrResult(dnr_token, result, nil, @addr, 1);
  282.             if result = noErr then begin
  283.                 FoundAddress(addr);
  284.                 timetodie := true;
  285.             end else if result <> inProgress then begin
  286.                 Failed(result);
  287.                 timetodie := true;
  288.             end;
  289.         end;
  290.     end;
  291.  
  292.     procedure NameSearchObject.FindName (hostIP: longInt);
  293.         var
  294.             err: OSErr;
  295.     begin
  296.         ip := hostIP;
  297.         err := Create;
  298.         if err = noErr then begin
  299.             err := TransportAddrToName(hostIP, dnr_token);
  300.             timeout_time := TickCount + TO_FindName;
  301.         end;
  302.         if err <> noErr then begin
  303.             Failed(err);
  304.             timetodie := true;
  305.         end;
  306.     end;
  307.  
  308.     procedure NameSearchObject.FoundName (name: Str255; error: OSErr);
  309.     begin
  310.         name := name; { UNUSED! }
  311.         error := error; { UNUSED! }
  312.     end;
  313.  
  314.     procedure NameSearchObject.HandleConnection;
  315.         var
  316.             result: OSStatus;
  317.             name:Str255;
  318.     begin
  319.         inherited HandleConnection;
  320.         if not timetodie then begin
  321.             TransportGetAddrToNameResult(dnr_token, result, name);
  322.             if result <> inProgress then begin
  323.                 FoundName(name, result);
  324.                 timetodie := true;
  325.             end;
  326.         end;
  327.     end;
  328.  
  329.     function UDPObject.Create: OSErr;
  330.     begin
  331.         tref := nil;
  332.         localport := 0;
  333.         Create := inherited Create;
  334.     end;
  335.  
  336.     function UDPObject.CreatePort (buffersize: longInt; port: integer): OSErr;
  337.         var
  338.             err: OSErr;
  339.     begin
  340.         err := Create;
  341.         if err = noErr then begin
  342.             err := TransportUDPOpenPort(tref, port, buffersize);
  343.             localport := port;
  344.             timeout_time := maxLongInt;
  345.         end;
  346.         if err <> noErr then begin
  347.             timetodie := true;
  348.         end;
  349.         CreatePort := err;
  350.     end;
  351.  
  352.     procedure UDPObject.Close;
  353.     begin
  354.         timetodie := true;
  355.         inherited Close;
  356.     end;
  357.  
  358.     procedure UDPObject.Destroy;
  359.     begin
  360.         TransportUDPDestroy(tref);
  361.         inherited Destroy;
  362.     end;
  363.  
  364.     procedure UDPObject.PacketAvailable (remoteIP: longInt; remoteport: integer; datap: ptr; datalen: integer);
  365.     begin
  366.         remoteIP := remoteIP; { UNUSED! }
  367.         remoteport := remoteport; { UNUSED! }
  368.         datap := datap; { UNUSED! }
  369.         datalen := datalen; { UNUSED! }
  370.     end;
  371.  
  372.     procedure UDPObject.PacketsAvailable (count: integer);
  373.         var
  374.             err: OSErr;
  375.             remoteIP: longInt;
  376.             remoteport: integer;
  377.             datap: ptr;
  378.             datalen: integer;
  379.     begin
  380.         count := count; { UNUSED! }
  381.         err := TransportUDPRead (tref, remoteIP, remoteport, datap, datalen);
  382.         if err = noErr then begin
  383.             PacketAvailable(remoteIP, remoteport, datap, datalen);
  384.             err := TransportUDPReturnBuffer(tref, datap);
  385.         end;
  386.     end;
  387.  
  388.     function UDPObject.SendPacket (remoteIP: longInt; remoteport: integer; datap: ptr; datalen: integer; checksum: boolean): OSErr;
  389.     begin
  390.         SendPacket := TransportUDPWrite (tref, remoteIP, remoteport, datap, datalen, checksum);
  391.     end;
  392.  
  393.     procedure UDPObject.HandleConnection;
  394.         var
  395.             count: longInt;
  396.     begin
  397.         inherited HandleConnection;
  398.         if not timetodie & (tref <> nil) then begin
  399.             count := TransportUDPDatagramsAvailable(tref);
  400.             if count > 0 then begin
  401.                 PacketsAvailable(count);
  402.             end;
  403.         end;
  404.     end;
  405.  
  406.     procedure ConnectionObject.Established;
  407.     begin
  408.     end;
  409.  
  410.     procedure ConnectionObject.Closing;
  411.     begin
  412.         Close;
  413.     end;
  414.  
  415.     procedure ConnectionObject.CharsAvailable;
  416.     begin
  417.     end;
  418.  
  419.     function ConnectionObject.Create: OSErr;
  420.         var
  421.             err, err2:OSErr;
  422.     begin
  423.         err := inherited Create;
  424.         transfer_error := noErr;
  425.         do_send_close := false;
  426.         err2 := MNewHandle(input_buffer, 0);
  427.         if err = noErr then begin
  428.             err := err2;
  429.         end;
  430.         err2 := MNewHandle(output_buffer, 0);
  431.         if err = noErr then begin
  432.             err := err2;
  433.         end;
  434.         Create := err;
  435.     end;
  436.     
  437.     procedure ConnectionObject.Destroy;
  438.     begin
  439.         TransportDestroy(tref);
  440.         MDisposeHandle(input_buffer);
  441.         MDisposeHandle(output_buffer);
  442.         inherited Destroy;
  443.     end;
  444.  
  445.     procedure ConnectionObject.SendData(datap: ptr; len: longint);
  446.         var
  447.             err: OSErr;
  448.     begin
  449.         err := PtrAndHand(datap, output_buffer, len);
  450.         if transfer_error = noErr then begin
  451.             transfer_error := err;
  452.         end;
  453.     end;
  454.  
  455.     procedure ConnectionObject.SendString (s: Str255);
  456.     begin
  457.         SendData(@s[1], length(s));
  458.     end;
  459.  
  460.     procedure ConnectionObject.DoTransfer;
  461.         procedure SetErr(err:OSStatus);
  462.         begin
  463.             if (transfer_error = noErr) then begin
  464.                 transfer_error := err;
  465.             end;
  466.         end;
  467.         var
  468.             err: OSStatus;
  469.             count, len:longint;
  470.     begin
  471.         len := GetHandleSize(input_buffer);
  472.         count := Min(TransportCharsAvailable(tref), 10240-len);
  473.         if count > 0 then begin
  474.             err := MSetHandleSize(input_buffer, len + count);
  475.             if err = noErr then begin
  476.                 HLock(input_buffer);
  477.                 err := TransportReceive(tref, AddPtrLong(input_buffer^, len), count, count);
  478.                 HUnlock(input_buffer);
  479.                 SetErr(err);
  480.                 SetHandleSize(input_buffer, len + count);
  481.             end;
  482.         end;
  483.  
  484.         len := GetHandleSize(output_buffer);
  485.         if len > 0 then begin
  486.             HLock(output_buffer);
  487.             err := TransportSend(tref, output_buffer^, len);
  488.             HUnlock(output_buffer);
  489.             SetHandleSize(output_buffer, 0);
  490.             SetErr(err);
  491.         end else if do_send_close then begin
  492.             do_send_close := false;
  493.             TransportSendClose(tref);
  494.         end;
  495.     end;
  496.     
  497.     procedure ConnectionObject.BeginConnection;
  498.     begin
  499.     end;
  500.  
  501.     procedure ConnectionObject.NewExistingConnection(newtref: TransportRef);
  502.         var
  503.             err: OSStatus;
  504.     begin
  505.         tref := newtref;
  506.         err := Create;
  507.         if err = noErr then begin
  508.             err := TransportHandleTransfers(tref);
  509.         end;
  510.         if err = noErr then begin
  511.             status := CS_Established;
  512.             ourport := 0;
  513.             timeout_time := maxLongInt;
  514.             BeginConnection;
  515.             Established;
  516.         end else begin
  517.             Failed(err);
  518.         end;
  519.     end;
  520.     
  521.     procedure ConnectionObject.NewConnection (active: boolean; buffersize: longInt; localport: integer; remotehost: Str255);
  522.         var
  523.             err: OSErr;
  524.     begin
  525.         tref := nil;
  526.         err := Create;
  527.         if err = noErr then begin
  528.             status := CS_Opening;
  529.             ourport := localport;
  530.             if active then begin
  531.                 err := TransportOpenActiveConnection(tref, remotehost, ourport, buffersize);
  532.                 timeout_time := TickCount + TO_ActiveOpen;
  533.             end else begin
  534.                 err := TransportOpenPassiveConnection(tref, ourport, buffersize);
  535.                 timeout_time := TickCount + TO_PassiveOpen;
  536.             end;
  537.         end;
  538.         if err = noErr then begin
  539.             err := TransportHandleTransfers(tref);
  540.         end;
  541.         if err = noErr then begin
  542.             BeginConnection;
  543.         end
  544.         else begin
  545.             Failed(err);
  546.             timetodie := true;
  547.         end;
  548.     end;
  549.  
  550.     procedure ConnectionObject.NewPassiveConnection (buffersize: longInt; localport: integer);
  551.     begin
  552.         NewConnection(false, buffersize, localport, '');
  553.     end;
  554.  
  555.     procedure ConnectionObject.NewActiveConnection (buffersize: longInt; remotehost: Str255);
  556.     begin
  557.         NewConnection(true, buffersize, 0, remotehost);
  558.     end;
  559.  
  560.     procedure ConnectionObject.Close;
  561.     begin
  562.         if not closedone and (tref <> nil) then begin
  563.             if GetHandleSize(output_buffer) > 0 then begin
  564.                 do_send_close := true;
  565.             end else begin
  566.                 TransportSendClose(tref);
  567.             end;
  568.             closedone := true;
  569.         end;
  570.     end;
  571.  
  572.     procedure ConnectionObject.HandleConnection;
  573.         var
  574.             state: TCPStateType;
  575.             result: OSStatus;
  576.     begin
  577.         inherited HandleConnection;
  578.         if not timetodie then begin
  579.             case status of
  580.                 CS_Opening:  begin
  581.                     TransportGetOpenResult(tref, result);
  582.                     if result = noErr then begin
  583.                         Established;
  584.                         status := CS_Established;
  585.                         timeout_time := maxLongInt;
  586.                     end else if result <> inProgress then begin
  587.                         Failed(result);
  588.                         timetodie := true;
  589.                     end;
  590.                 end;
  591.                 CS_Established:  begin
  592.                     DoTransfer;
  593.                     state := TransportGetConnectionState(tref);
  594.                     case state of
  595.                         T_Established:  begin
  596.                             if GetHandleSize(input_buffer) > 0 then begin
  597.                                 CharsAvailable;
  598.                             end;
  599.                         end;
  600.                         T_PleaseClose, T_Closing:  begin
  601.                             if GetHandleSize(input_buffer) > 0 then begin
  602.                                 CharsAvailable;
  603.                             end else begin
  604.                                 Closing;
  605.                                 status := CS_Closing;
  606.                                 timeout_time := TickCount + TO_Closing;
  607.                             end;
  608.                         end;
  609.                         T_Dead, T_Bored:  begin
  610.                             Closing;
  611.                             status := CS_Closing;
  612.                             timeout_time := TickCount + TO_Closing;
  613.                         end;
  614.                         otherwise
  615.                             ;
  616.                     end;
  617.                 end;
  618.                 CS_Closing:  begin
  619.                     DoTransfer;
  620.                     state := TransportGetConnectionState(tref);
  621.                     case state of
  622.                         T_PleaseClose, T_Closing, T_Established:  begin
  623.                             if GetHandleSize(input_buffer) > 0 then begin
  624.                                 CharsAvailable;
  625.                             end;
  626.                         end;
  627.                         T_Dead, T_Bored:  begin
  628.                             timetodie := true;
  629.                         end;
  630.                         otherwise
  631.                             ;
  632.                     end;
  633.                 end;
  634.                 otherwise
  635.                     ;
  636.             end;
  637.         end;
  638.     end;
  639.  
  640.     function LineConnectionObject.Create: OSErr;
  641.     begin
  642.         crlf := CL_CRLF;
  643.         last_check := -1;
  644.         Create := inherited Create;
  645.     end;
  646.  
  647.     procedure LineConnectionObject.SendLine (s: Str255);
  648.     begin
  649.         if crlf <> CL_LF then begin
  650.             s := concat(s, cr);
  651.         end;
  652.         if crlf <> CL_CR then begin
  653.             s := concat(s, lf);
  654.         end;
  655.         SendData(@s[1], length(s));
  656.     end;
  657.  
  658.     procedure LineConnectionObject.LineAvailable (line: Str255);
  659.     begin
  660.         line := line; { UNUSED! }
  661.     end;
  662.  
  663.     procedure LineConnectionObject.CharsAvailable;
  664.     begin
  665.         CheckLineAvailable;
  666.     end;
  667.  
  668.     procedure LineConnectionObject.CheckLineAvailable;
  669.         var
  670.             len, inbuf, junk_long: longInt;
  671.             p: ptr;
  672.             s: Str255;
  673.     begin
  674.         while true do begin
  675.             inbuf := GetHandleSize(input_buffer);
  676.             if (inbuf = 0) | (inbuf = last_check) then begin
  677.                 leave;
  678.             end;
  679.             p := input_buffer^;
  680.             len := 0;
  681.             while (len < inbuf) & (len < 255) & (p^ <> ord(lf)) & (p^ <> ord(cr)) do begin
  682.                 p := ptr(ord(p) + 1);
  683.                 len := len + 1;
  684.             end;
  685.             if (len = 255) | ((len < inbuf) & ((p^ = ord(lf)) | (p^ = ord(cr)))) then begin
  686. {$PUSH}
  687. {$R-}
  688.                 s[0] := chr(len);
  689.                 BlockMoveData(input_buffer^, @s[1], len);
  690. {$POP}
  691.                 if (len < inbuf) & (p^ = ord(cr)) then begin
  692.                     p := ptr(ord(p) + 1);
  693.                     len := len + 1;
  694.                 end;
  695.                 if (len < inbuf) & (p^ = ord(lf)) then begin
  696.                     p := ptr(ord(p) + 1);
  697.                     len := len + 1;
  698.                 end;
  699.                 junk_long := Munger(input_buffer, 0, nil, len, @len, 0);
  700.                 LineAvailable(s);
  701.                 last_check := -1;
  702.             end else begin
  703.                 last_check := inbuf;
  704.             end;
  705.         end;
  706.     end;
  707.  
  708.     procedure IdleConnections;
  709.         var
  710.             i: integer;
  711.     begin
  712.         for i := 1 to max_connections do begin
  713.             if connections[i] <> nil then begin
  714.                 if not connections[i].timetodie then begin
  715.                     connections[i].HandleConnection;
  716.                 end;
  717.                 if connections[i].timetodie then begin
  718.                     connections[i].Destroy;
  719.                 end;
  720.             end;
  721.         end;
  722.     end;
  723.  
  724.     procedure FinishConnections;
  725.         var
  726.             i: integer;
  727.     begin
  728.         for i := 1 to max_connections do begin
  729.             if connections[i] <> nil then begin
  730.                 connections[i].Destroy;
  731.             end;
  732.         end;
  733.     end;
  734.  
  735.     procedure StartupConnections;
  736.         var
  737.             i: integer;
  738.     begin
  739.         quiting := false;
  740.         for i := 1 to max_connections do begin
  741.             connections[i] := nil;
  742.         end;
  743.         StartupTransport;
  744.         SetStartup(nil, IdleConnections, 0, FinishConnections);
  745.     end;
  746.  
  747. end.