home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 5
/
ctrom5b.zip
/
ctrom5b
/
PROGRAM
/
PASCAL
/
NWTP06
/
NWIPX.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1995-03-01
|
20KB
|
607 lines
{$B-,V-,X+}
UNIT nwIPX;
{$DEFINE ProtMode}
{$IFDEF MSDOS} {$UNDEF ProtMode} {$DEFINE RealMode} {$ENDIF}
{$IFDEF ProtMode} sorry, protected mode not supported (yet) {$ENDIF}
{ nwIPX unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
INTERFACE
Uses Dos,nwMisc;
{ Primary IPX calls: Subf: Comments:
IPXCancelEvent 6 AES
* IPXCloseSocket 1 (1)
IPXDisconnectFromTarget B (1)
* IPXGetInterNetworkaddress 9
* IPXGetIntervalMarker 8
* IPXGetLocalTarget 2
- IPXGetPacketSize D (IPX internal use only)
* IPXInitialize INT 2F
- IPXInitializeNetworkAddress C (IPX internal use only)
* IPXListenForPacket 4
* IPXOpenSocket 0
* IPXRelinquishControl A
* IPXScheduleIPXEvent 5 AES
IPXScheduleSpecialEvent 7
* IPXSendPacket 3
- IPXTerminateSockets E (IPX internal use only)
Secondary calls:
* IPXpresent
* IPXsetupSendECB
* IPXsetupListenECB
Notes: (1) These functions use INT 21 and are not to be called from
within an ESR.
}
CONST
LONG_LIVED_SOCKET = TRUE; { IPXopenSocket }
SHORT_LIVED_SOCKET = FALSE;
{*** PACKET TYPES ***}
UNKNOWN_PACKET_TYPE =0; { (basic) Unknown IPX packet }
IPX_PACKET_TYPE =0;
RIP_PACKET_TYPE =1; { Routing Information Packet }
ECHO_PACKET_TYPE =2;
ERROR_PACKET_TYPE =3;
PEP_PACKET_TYPE =4; { Packet Exchange Protocol }
SPX_PACKET_TYPE =5; { Sequenced Packet Protocol Packet }
PUP_PACKET_TYPE =12;
DOD_IP_PACKET_TYPE =13; { Internet Protocol packet Type }
NCP_PACKET_TYPE =17; { NetWare Core Protocol }
{ Experimental packet types: 20 - 37 }
{*** SOCKET NUMBERS ***}
{0001-0BB8 Registered with Xerox }
SKT_XEROX_ROUTING_INFORMATION= $0001;
SKT_ECHO_PROTOCOL = $0002;
SKT_ERROR_HANDLER = $0003;
{0020-003F Xerox : Experimental }
SKT_NW4_TIME_SYNC_SERVER = $0040; { used by OT_NW4_TIME_SYNC_SERVER }
SKT_FILE_SERVICE = $0451; { see also $8140, used by OT_RSPCX_SERVER }
SKT_SERVICE_ADVERTISING = $0452; { SAP }
SKT_ROUTING_INFORMATION = $0453; { Novell's RIP Socket }
SKT_NETBIOS = $0455;
SKT_DIAGNOSTIC = $0456;
{ 0457h ??? (appears to be related to server serial numbers) }
{0BB9-FFFF Xerox : Dynamically assignable Sockets }
{0BB9-3FFF Novell: }
SKT_NMA_AGENT =$2F90; { used by OT_NMA_AGENT (NMS) }
{4000-7FFF Novell: Dynamically assignable Sockets }
{ Use a socket in this range for your own applications. }
{ To avoid conflicts with other programs, you are advised NOT }
{ to use sockets numbers where the hi-byte equals the low-byte, }
{ C programmers mostly use those to avoid byte-order swapping. }
{ ! See the SKT_XXX file in the XIPX archive for the latest info
on socket numbers... }
{8000-FFFF Novell: Well known sockets, registered with Novell. }
SKT_EMAIL_CHAT =$8055; { Niche Corp. }
SKT_EMAIL_CHAT_2 =$8056; { Niche Corp. }
SKT_BTRIEVE =$8058;
SKT_BTRIEVE_2 =$8059;
SKT_NW_SQL =$805A;
SKT_NW_SQL_2 =$805B;
SKT_GAMESERVER =$805C;
SKT_GAMESERVER_2 =$805D;
SKT_PRINT_SERVER =$8060;
SKT_DIGITAL_CHAT =$806C; { Digital Inc. }
SKT_NW_ACCESS_SERVER =$806F;
SKT_OXXI_EMAIL_CHAT =$80C3; { Oxxi Inc. }
SKT_PRINT_SERVER_2 =$811E;
SKT_INTEL_EMAIL_CHAT =$845F; { Intel Corp. }
SKT_WINDOWS_EMAIL_CHAT =$9017;
SKT_JOB_SERVER =$9022;
Var Result:word; { unit errorcode variable }
Type TipxHeader=Record
checksum :word; { not used, set to $FFFF }
length :word; { total number of bytes }
TransportControl :byte; { used by bridges: low 4 bits= hop count }
packetType :byte; { ignored by IPX, used by higher level
protocols only. $00=unknown packet type}
destination,
source :TinternetWorkAddress;
{ if dest.network equals 0; dest
assumed on same network as sender }
{ if dest.node =$FFFFFFFFFFFF, packet
will be sent to all nodes. }
end;
{ Fields within IPX and SPX are high-low. Byte swapping will be done
by the IPX functions, except network and node addresses. }
Tfragment=record { address and size of buffer fragment. }
Address:Pointer;
Size:word;
end;
Tecb=record
Linkaddress :Pointer; { used by IPX itself }
ESRaddress :Pointer;
InUseFlag :Byte; { reset to $00 when request completed }
CompletionCode :Byte; { valid after InUseFlag becomes $00;
completionCode=$00: packet sent/received. }
SocketNumber :word;
IPXworkspace :array[1..4] of byte;
DriverWorkspace :array[1..12] of byte;
Immediateaddress:Tnodeaddress; { 6 bytes }
FragmentCount :word; { must be >0 }
Fragment :array[1..2] of Tfragment; { [1..FragmentCount] }
{ The number of fragments is unlimited.
However, most applications use 1 or 2. }
end;
Tpecb=^Tecb;
{ TAESecb=:
Offset Size Description
00h DWORD Link
04h DWORD ESR address
08h BYTE in use flag (see below)
09h 5 BYTEs AES workspace }
Function IpxPresent:boolean;
{ Determines if an IPX driver is loaded. Calls IPXInitialize. }
Function IPXinitialize:Boolean;
{ Determines if an IPX driver is loaded. }
{IPX/SPX: 09h}
Function IPXGetInternetworkAddress(Var Address:TinterNetworkAddress):boolean;
{ This call returns the network and node address of the requesting workstation. }
{ The two byte socketnumber must be appended to the end to form a full }
{ 12-Byte network address. The socketnumber will be set to 0000, indicating
that it has to be filled later with a meaningfule number. }
{IPX/SPX: 00h}
Function IPXOpenSocket(Var socket:word; PermanentSocket:boolean):boolean;
{ When an application wants to send or receive packets on a socket,
it should first open the socket. PermanentSocket should be set to TRUE
if the socket is used by a TSR. This way, the socket will only be
closed when the IPXcloseSocket function is called. Otherwise, set to FALSE. }
{IPX/SPX: 01h}
Function IPXCloseSocket(socket:word):boolean;
{ Closes the socket. TSRs should close permanent sockets before terminating. }
{IPX/SPX: 02h}
Function IPXGetLocalTarget(Address:TinternetworkAddress;
Var ImmAddr:TnodeAddress;
Var Ticks:word ):boolean;
{ Returns the nodeaddress (Immediate address) of a bridge/router that
connects the senders' network with the target-network. If the target
lies within the same network as the sender, the returned node address
is the same as the target node-address. }
{IPX/SPX: 03h}
Function IPXSendPacket(Var Ecb:Tecb):boolean;
{ After calling this function, control is immediately turned back to the
calling process, whilst in the background the IPX driver is trying to
send the packet. To check if the message has been sent, check the
ECB.InUseFlag or use a SendESR.
The ecb must be filled with appropriate values before calling this function,
the socket to send on must be open. }
{IPX/SPX: 0Fh}
Function IPXInternalSendPacket(Var Ecb:Tecb):boolean;
{IPX/SPX: 04h}
Function IPXListenForPacket(Var Ecb:Tecb):Boolean;
{ After calling this function, control is immediately turned back to the
calling process. The IPX driver will wait in the background for a packet
to be received. To check if a message has been received, check the
ECB.InUseFlag or use a ListenESR.
The ecb must be filled with appropriate values before calling this function,
the socket to receive on must be open. }
{IPX/SPX: 0Ah}
Function IPXrelinquishControl:boolean;
{ Temporarily gives away CPU time to bakcground processes. This call
improves efficeincy by informing the IPX driver that the CPU is
available. }
{IPX/SPX: 08h}
Function IPXgetIntervalMarker(Var ticks:word):boolean;
{ Gets a time marker from IPX. The difference between two known
time-markers can be used to determine if a timeout has occurred.
1 Tick = 1/18.2 second. }
{IPX/SPX: 06h}
Function IPXcancelEvent(ECB:Tecb):boolean;
{ AES call: Cancel an event.
When the event is canceled, the ECB.InUseFlag will be set to $00 and the
ECB.CompletionCode to $FC: Event Canceled. }
{IPX/SPX: 0Bh}
Function IPXdisconnectFromTarget(Address:TinternetworkAddress):boolean;
{ Informs the listening socket at the specified adress that no more
packets will be sent to the listening socket.
This function is not required in your application, it is merely used
to inform some drivers that the connection (if any) has ended. }
{IPX/SPX: 05h}
Function IPXscheduleIPXevent(ticks:word;Var ECB:Tecb):boolean;
{ AES call: schedule an event.
After calling this function, control is immediately turned back to the
calling process. After waiting the number of ticks specified
(1 tick= 1/18.2 sec.), the IPX driver activates the ECB.
This function should never be called with an ECB that is still in use
by the IPXdriver (i.e. ECB.InUseFlag should be 0 before calling)
}
{UPX: 0007}
Function IPXscheduleSpecialEvent(ticks:word;Var ECB:Tecb):boolean;
Procedure IpxSpxSystemCall(Var regs:registers);
{ Provides an entry into the INT A7 interrupt handler;
Valid only if IPXinitialize or IPXinstalled were called previously. }
{************** Secondary Procedures ***************************************}
Procedure IPXSetupListenECB(ESRptr:Pointer; ReceiveSocket:word;
BufPtr:Pointer; BufSize:word;
{out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
{ Clears IPXheader and ECB, sets values of the required fields within
the ecb and IPX header. }
Procedure IPXsetupSendECB(ESRptr:pointer; SourceSocket:Word;
DestAddr:TinterNetworkAddress;
BufPtr:pointer; BufSize:word;
{out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
{ Clears IPXheader and ECB, sets values of the required fields within
the ecb and IPX header. }
IMPLEMENTATION {==============================================================}
CONST
IPX_MAX_DATA_LENGTH =546;
Var IpxSpxCall:Procedure;
Procedure IpxSpxSystemCall(Var regs:registers); assembler;
{ This method of calling IPX/SPX is preferred by Novell. }
{ For what its' worth: this call is 48 bytes longer than the other one.. }
asm
{ check if IpxSpxCall known. If not, return error $FF in fake AL }
xor ah,ah
mov al,$FF
les di,IpxSpxCall
mov bx,es
cmp bx,$0000
je @1
{ move fake regs registers to 'real' registers }
{ AX, BX, CX, DX, SI, DI, ES only. }
les di,regs
mov ax,es:[di+16]
push ax { push new es }
mov ax,es:[di+12]
push ax { push new di }
mov ax,es:[di]
mov bx,es:[di+2]
mov cx,es:[di+4]
mov dx,es:[di+6]
mov si,es:[di+10]
pop di
pop es
{ farr call to A7 interrup handler }
push bp
CALL IpxSpxCall
pop bp
@1: { move 'real' registers to fake regs registers }
push es
push di
les di,regs
mov es:[di],ax
mov es:[di+2],bx
mov es:[di+4],cx
mov es:[di+6],dx
mov es:[di+10],si
pop ax { ax:= 'di' }
mov es:[di+12],ax
pop ax { ax:= 'es' }
mov es:[di+16],ax
end;
Function IPXinitialize:Boolean;
CONST DOS_MULTIPLEX =$2F;
Var regs:registers;
begin
Regs.AX:=$7A00;
INTR(DOS_MULTIPLEX,Regs);
if regs.AL<>$FF
then begin
Result:=IPX_NOT_INSTALLED;
IpxInitialize:=false
end
else begin
@IpxSpxCall:=Ptr(Regs.es,Regs.di);
Result:=0;
IpxInitialize:=true;
end;
end;
Function IpxPresent:boolean;
begin
IpxPresent:=IpxInitialize
end;
{IPX: 09h}
Function IPXGetInternetworkAddress(Var Address:TinterNetworkAddress):boolean;
{ This call returns the network and node address of the requesting workstation. }
{ The two byte socketnumber must be appended to the end to form a full }
{ 12-Byte network address. }
Var regs:registers;
begin
regs.bx:=$0009;
regs.es:=seg(Address);
regs.si:=ofs(Address);
IpxSpxSystemCall(Regs);
result:=regs.al;
address.socket:=$0000; { unknown, to be set later. }
if result<>$FF
then result:=$00;
IPXGetInternetworkAddress:=(result=$00);
{ possible resultcodes: $00 Successful; $FF IPX not initialized }
end;
{IPX: 00}
Function IPXOpenSocket(Var socket:word; permanentSocket:boolean):boolean;
Var regs:registers;
reqForSocket:boolean;
begin
regs.bx:=$0000;
if permanentSocket
then regs.al:=$FF
else regs.al:=$00;
regs.dx:=swap(socket); {hi-lo}
reqForSocket:=(socket=$0000);
IpxSpxSystemCall(Regs);
result:=regs.al;
if reqForSocket
then socket:=swap(regs.dx); {force lo-hi}
IPXopenSocket:=(result=0);
{ resultcodes: $00 successful; $FE Socket Table Is Full;
$FF socket already open OR IPX not initilazed. }
end;
{IPX: 01}
Function IPXCloseSocket(socket:word):boolean;
Var regs:registers;
begin
regs.bx:=$01;
regs.dx:=swap(socket);
IpxSpxSystemCall(regs);
result:=regs.al;
if result<>$FF then result:=$00;
IPXCloseSocket:=(result=$00);
{ possible resultcodes: $00 Successful; $FF IPX not initialized }
end;
{IPX: 02}
Function IPXGetLocalTarget(Address:TinternetworkAddress;
Var ImmAddr:TnodeAddress;
VAR ticks:Word ):boolean;
{ Ticks = estimated transmission time, in number of ticks (1/18 sec) }
Var reqAddr:TinternetworkAddress;
repNode:TnodeAddress;
Regs :registers;
begin
move(Address,reqAddr,10);
reqAddr.socket:=swap(Address.socket); {hi-lo}
With regs
do begin
bx:=$0002;
es:=seg(reqAddr); si:=ofs(reqAddr); di:=ofs(repNode);
IpxSpxSystemCall(regs);
ticks:=regs.cx;
result:=regs.al;
if result=0
then move(repNode,ImmAddr,6);
end;
IPXGetLocalTarget:=(result=$00);
{ resultcodes: $00 Successful; $FA No path to destination node found;
$FF IPX not initialized. }
end;
Function IPXSendPacket(Var Ecb:Tecb):boolean;
{ the ecb must be filled, before calling this function }
{ Right after this call, IPXrelinquishControl should be called Iteratively,
this allows the sending of the IPX packet. }
Var regs:Registers;
begin
regs.bx:=$0003;
regs.es:=seg(ecb);
regs.si:=ofs(ecb);
IpxSpxSystemCall(Regs);
result:=regs.al;
if result<>$FF then result:=$00;
IpxSendPacket:=(result=$00);
{ possible resultcodes: $00 Successful; $FF IPX not initialized }
end;
Function IPXInternalSendPacket(Var Ecb:Tecb):boolean;
Var regs:Registers;
begin
regs.bx:=$000F;
regs.es:=seg(ecb);
regs.si:=ofs(ecb);
IpxSpxSystemCall(Regs);
result:=regs.al;
if result<>$FF then result:=$00;
IpxInternalSendPacket:=(result=$00);
{ possible resultcodes: $00 Successful; $FF IPX not initialized }
end;
Function IPXListenForPacket(Var Ecb:Tecb):Boolean;
{ socket must be opened, ECB (partly) filled. }
Var regs:Registers;
begin
regs.bx:=$0004;
regs.es:=seg(ecb);
regs.si:=ofs(ecb);
IpxSpxSystemCall(Regs);
result:=regs.al;
if result<>$FF
then result:=$00;
IpxListenForPacket:=(result=$00);
{resultcodes: $00 Successful;
$FF Listening Socket doesn't exist OR IPX not initialized }
end;
Function IPXrelinquishControl:boolean;
Var regs:Registers;
begin
regs.bx:=$000A;
IpxSpxSystemCall(Regs);
result:=regs.al;
if result<>$FF then result:=$00;
IpxrelinquishControl:=(result=$00);
{resultcodes: $00 Successful; $FF IPX not initialized }
end;
Function IPXgetIntervalMarker(Var ticks:word):boolean;
Var regs:Registers;
begin
regs.bx:=$0008;
IpxSpxSystemCall(Regs);
ticks:=regs.ax;
result:=$00;
IPXgetIntervalMarker:=True;
end;
Function IPXcancelEvent(ECB:Tecb):boolean;
Var regs:registers;
begin
regs.bx:=$0006;
regs.es:=seg(ecb);
regs.si:=ofs(ecb);
IpxSpxSystemCall(Regs);
result:=regs.al;
IPXcancelEvent:=(result=0);
{ resultcodes: 00 Successful; F9 ECB cannot be canceled;
FF ECB not in use OR IPX not initialized. }
end;
Function IPXdisconnectFromTarget(Address:TinternetworkAddress):boolean;
VAR regs:registers;
LocAddr:TinternetworkAddress;
begin
move(Address,LocAddr,10);
LocAddr.socket:=swap(Address.socket);
regs.bx:=$000B;
regs.es:=seg(LocAddr);
regs.si:=ofs(LocAddr);
IpxSpxSystemCall(Regs);
result:=regs.al;
if result<>$FF
then result:=$00;
IPXdisconnectFromTarget:=(result=0);
{resultcodes: $00 Successful; $FF IPX not initialized }
end;
Function IPXscheduleIPXevent(ticks:word;Var ECB:Tecb):boolean;
Var regs:registers;
begin
regs.bx:=$0005;
regs.ax:=ticks;
regs.es:=seg(ECB);
regs.si:=ofs(ECB);
IpxSpxSystemCall(Regs);
if result<>$FF
then result:=$00;
IPXscheduleIPXevent:=(result=0);
{resulcodes: 00 successful; FF IPX not initialized }
end;
Function IPXscheduleSpecialEvent(ticks:word;Var ECB:Tecb):boolean;
Var regs:registers;
begin
regs.bx:=$0007;
regs.ax:=ticks;
regs.es:=seg(ECB);
regs.si:=ofs(ECB);
IpxSpxSystemCall(Regs);
if result<>$FF
then result:=$00;
IPXscheduleSpecialEvent:=(result=0);
{resulcodes: 00 successful; FF IPX not initialized }
end;
{************** Secondary Procedures ***************************************}
Procedure IPXSetupListenECB(ESRptr:Pointer;ReceiveSocket:word;
BufPtr:Pointer;BufSize:word;
{out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
{ Clears IPXheader and ECB, sets values of the required fields within
the ecb and IPX header. }
{ ECB: ESR adress field, socket number, fragment count, frag.descriptor fields }
begin
FillChar(ecb,SizeOf(Tecb),#0);
FillChar(ipxHdr,SizeOF(TipxHeader),#0);
WITH ECB
do begin
if ESRptr<>NIL
then ESRaddress:=ESRptr;
Fragmentcount:=2;
socketNumber:=swap(ReceiveSocket); {hi-lo}
Fragment[1].Address:=@ipxHdr;
Fragment[2].Address:=BufPtr;
Fragment[1].size:=SizeOf(Tipxheader);
Fragment[2].size:=BufSize;
end;
end;
Procedure IPXsetupSendECB(ESRptr:pointer; SourceSocket:word;
DestAddr:TinterNetworkAddress;
BufPtr:pointer; BufSize:word;
{out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
{ Clears IPXheader and ECB, sets values of the required fields within
the ecb and IPX header. }
Var ImmAddr:TnodeAddress;
Ticks:word;
begin
fillchar(ipxHdr,SizeOf(TipxHeader),#0);
with ipxhdr
do begin
PacketType:=IPX_PACKET_TYPE;
Move(DestAddr,Destination,10);
destination.socket:=swap(DestAddr.socket); {hi-lo}
end;
IPXGetLocalTarget(DestAddr,ImmAddr,Ticks);
fillchar(ecb,sizeOf(ecb),#0);
With ecb
do begin
if ESRptr<>NIL
then ESRaddress:=ESRptr;
socketNumber:=swap(SourceSocket); {hi-lo}
Move(ImmAddr,ImmediateAddress,6);
FragmentCount:=2;
fragment[1].Address:=@ipxhdr;
fragment[1].size:=SizeOf(TipxHeader);
fragment[2].Address:=BufPtr;
fragment[2].size:=BufSize;
end;
end;
end.