{$B-,V-,X+}

UNIT nwSPX;

{ nwSPX unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R. Spronk }
{ NOTE: These SPX calls are not documented in this version }

INTERFACE

Uses Dos,nwMisc,nwIPX;

{ Primary SPX calls:           Subf:  Comments:

  SPXabortConnection            14
  SPXGetConnectionStatus        15
  SPXestablishConnection        11
* SPXinitialize                 10
  SPXlistenForConnection        12
  SPXlistenForSequencedPacket   17
  SPXsendSequencedPacket        16
  SPXTerminateConnection        13

  Secondary calls:

* SPXpresent

  Notes: (1) These functions use INT 21 and are not to be called from
             within an ESR.
}

Var Result:word; { unit errorcode variable }

Type TspxHeader=Record
               IPXhdr        :TipxHeader;  { SPX will set packetType to 5 }
               connControl   :byte; { rarely used, set to $00 }
                                    { ignored by SPX, but passed on to receiver:
                                      $10 End of message; $20 Attention packet }
               dataStreamType:Byte; { to be used by higher level protocols.
                                      nust be < $FE, passed on to receiver }
               sourceConnId,
               destConnId    :Word;
               sequenceNbr,
               acknowledgeNbr,
               allocationNbr :Word;
               end;
    { Fields within IPX and SPX are high-low. Byte swapping will be done
      by the IPX functions, except network and node addresses. }

Type TSPXconnectionInformation
        =record
         ConnectionState        :Byte; { all fields are returned hi-lo }
         WatchDogState          :Byte;
         LocalSPXConnectionId   :Word;
         RemoteSPXConnectionId  :Word;
         SequenceNumber         :Word;
         LocalAcknowledgeNumber :Word;
         LocalAllocationNumber  :Word;
         RemoteAcknowledgeNumber:Word;
         RemoteAllocationNumber :Word;
         LocalSocket            :Word;
         ImmediateAddress       :TnodeAddress;
         RemoteAddress          :TinterNetworkAddress;
         RetransmissionCount    :Word;
         EstimatedRoundTripDelay:Word;
         RetransmittedPackets   :Word;
         SuppressedPackets      :Word;
      end;

Function SPXpresent:boolean;
{ Determines if SPX is installed. Calls SPXInitialize. }

{IPX/SPX: 10h}
Function SpxInitialize(Var SPXhiVer,SPXloVer:Byte;
                       Var MaxConn,AvailConn:word):boolean;
{ Determines if SPX is loaded. (this function also tests the presence of IPX, }
{ as IPX is required for running SPX. Remember: Netware 2.2 allows IPX and SPX    }
{ to be loaded seperately, so only IPX may be present. }

{IPX/SPX: 11h}
Function SPXestablishConnection(retryCount:byte; WatchdogFlag:Byte;
                         {i/o}  Var ECB:Tecb;
                         {out}  Var SPXconnectionID:Word):boolean;

{IPX/SPX: 12h}
Function SPXlistenForConnection(retryCount:Byte; WatchdogFlag: Byte;
                                Var ECB:Tecb            ):boolean;

{IPX/SPX: 15h}
Function SPXGetConnectionStatus(SPXconnectionID:word;
                            Var connInfo:TSPXconnectionInformation):boolean;

{IPX/SPX: 13h}
Function SPXTerminateConnection(SPXconnectionID:Word; ECB:Tecb):boolean;

{IPX/SPX: 14h}
Function SPXabortConnection(SPXconnectionID:Word):boolean;

{IPX/SPX: 16h}
Function SPXsendSequencedPacket(SPXconnectionID:Word; Var ECB:Tecb):boolean;

{IPX/SPX: 17h}
Function SPXlistenForSequencedPacket(Var ECB:Tecb):boolean;

{************** Secondary Procedures ***************************************}

IMPLEMENTATION {==============================================================}

CONST
    SPX_WATCHDOG_ENABLED     =1;
    SPX_WATCHDOG_DISABLED    =0;
    SPX_DEFAULT_RETRY_COUNT  =0;

    SPX_POOL_SIZE         =10;

    SPX_MAX_DATA_LENGTH  =534;

{IPX/SPX: 10 }
Function SpxInitialize(Var SPXhiVer,SPXloVer:Byte;
                       Var MaxConn,AvailConn:word):boolean;
Var Regs:registers;
begin
With regs
 do begin
    al:=$00;
    bx:=$0010;
    IpxSpxSystemCall(Regs);
    result:=regs.al;

    if AL<>$FF
     then begin
          result:=$FF;
          SpxInitialize:=false
          end
     else begin
          SPXhiVer:=BH;
          SPXloVer:=BL;
          MaxConn:=CX;
          AvailConn:=DX;
          result:=$00;
          SpxInitialize:=true;
          end;
    end; {with}
{ resultcodes: $00 successfull (SPX installed); $FF SPX not installed }
end;

Function SpxPresent:boolean;
Var SpxHi,SpxLo:Byte;
    MaxConn,AvConn:word;
begin
SpxPresent:=( IpxPresent and SpxInitialize(SpxHi,SpxLo,MaxConn,AvConn) );
end;

{IPX/SPX: 11h}
Function SPXestablishConnection(retryCount:byte; WatchdogFlag:Byte;
                         {i/o}  Var ECB:Tecb;
                         {out}  Var SPXconnectionID:Word):boolean;
Var regs:registers;
begin
With regs
 do begin
    BX:=$0011;
    AL:=retryCount;
    AH:=WatchDogFlag;
    ES:=Seg(ECB);
    SI:=ofs(ECB);
    end;
IpxSpxSystemCall(Regs);
result:=regs.AL;
SPXconnectionID:=regs.DX;
SPXestablishConnection:=(result=$00);
{ resultcodes: $00 SPX Attempting to contact destination socket;
               $EF Local connection table full;
               $FD Fragment count not 1 AND/OR Buffer size not 42;
               $FF Send Socket not open OR IPX/SPX not initialized. }
end;


{IPX/SPX: 12h}
Function SPXlistenForConnection(retryCount:Byte; WatchdogFlag: Byte;
                                Var ECB:Tecb            ):boolean;
Var regs:Registers;
begin
With regs
 do begin
    BX:=$0012;
    AL:=retryCount;
    AH:=WatchdogFlag;
    ES:=Seg(ECB);
    SI:=Ofs(ECB);
    IpxSpxSystemCall(Regs);
    result:=AL;
    if result<>$FF
     then result:=$00;
    end;
SPXlistenForConnection:=(result=$00);
end;

{IPX/SPX: 15h}
Function SPXGetConnectionStatus(SPXconnectionID:word;
                            Var connInfo:TSPXconnectionInformation):boolean;
Var regs:Registers;
begin
With regs
 do begin
    BX:=$0015;
    DX:=SPXconnectionID;
    ES:=Seg(connInfo);
    SI:=Ofs(connInfo);
    IpxSpxSystemCall(Regs);
    Result:=AL;
    end;
if result=0
 then begin
      With ConnInfo
       do begin { force all returned words lo-hi }
          LocalSPXConnectionId   :=Swap(LocalSPXconnectionID);
          RemoteSPXConnectionId  :=Swap(RemoteSPXconnectionID);
          SequenceNumber         :=swap(SequenceNumber);
          LocalAcknowledgeNumber :=swap(LocalAcknowledgeNumber);
          LocalAllocationNumber  :=swap(LocalAllocationNumber);
          RemoteAcknowledgeNumber:=swap(RemoteAcknowledgeNumber);
          RemoteAllocationNumber :=swap(RemoteAllocationNumber);
          LocalSocket            :=swap(LocalSocket);
          RemoteAddress.socket   :=swap(remoteAddress.socket);
          RetransmissionCount    :=swap(RetransmissionCount);
          EstimatedRoundTripDelay:=swap(EstimatedRoundTripDelay);
          RetransmittedPackets   :=swap(RetransmittedPackets);
          SuppressedPackets      :=swap(SuppressedPackets);
          end;
      end;
SPXGetConnectionStatus:=(result=0);
{ Resulcodes: $00 Connection is active; $EE No such connection }
end;


{IPX/SPX: 13h}
Function SPXTerminateConnection(SPXconnectionID:Word; ECB:Tecb):boolean;
Var regs:Registers;
begin
with regs
 do begin
    BX:=$0013;
    DX:=SPXconnectionID;
    ES:=seg(ECB);
    SI:=Ofs(ECB);
    end;
IpxSpxSystemCall(Regs);
result:=regs.al;
if result<>$FF
 then result:=$00;
SPXterminateConnection:=(result=0);
{resultcodes: $00 SPX attempting to break connection;
              $FF IPX/SPX not loaded.  }
end;

{IPX/SPX: 14h}
Function SPXabortConnection(SPXconnectionID:Word):boolean;
Var regs:Registers;
begin
with regs
 do begin
    BX:=$0014;
    DX:=SPXconnectionID;
    end;
IpxSpxSystemCall(Regs);
result:=regs.al;
if result<>$FF
 then result:=$00;
SPXabortConnection:=(result=0);
{resultcodes: $00 SPX trying to unilateral break the connection;
              $FF IPX/SPX not loaded. }
end;

{IPX/SPX: 16h}
Function SPXsendSequencedPacket(SPXconnectionID:Word; Var ECB:Tecb):boolean;
Var regs:Registers;
begin
with regs
 do begin
    BX:=$0016;
    DX:=SPXconnectionID;
    ES:=Seg(ECB);
    SI:=Ofs(ECB);
    end;
IpxSpxSystemCall(Regs);
result:=regs.al;
if result<>$FF
 then result:=$00;
SPXsendSequencedPacket:=(result=0);
{resultcodes: $00 SPX will attempt to send packet;
              $FF IPX/SPX not loaded. }
end;

{IPX/SPX: 17h}
Function SPXlistenForSequencedPacket(Var ECB:Tecb):boolean;
Var regs:Registers;
begin
with regs
 do begin
    BX:=$0017;
    ES:=Seg(ECB);
    SI:=Ofs(ECB);
    end;
IpxSpxSystemCall(Regs);
result:=regs.al;
if result<>$FF
 then result:=$00;
SPXlistenForSequencedPacket:=(result=0);
{resultcodes: $00 SPX waits for incoming packets;
              $FF IPX/SPX not loaded. }
end;

{************** Secondary Procedures ***************************************}

end.
