|
 |
Descent Developer Network Descent 1/2
IPX Programming Starter's Guide
|
|
|
Purpose: I wrote this article out of guilt for not answering all those
people who ask me questions, because I didn't have the time. Also, I think this
information is really needed, as there is very little information out there on programming
for IPX. Therefore, my goal is to get enough information to get people started, so that
they can explore this protocol, and learn how easy it really is to use. I will only cover
the basic IPX functions, maybe later I will add more advanced information.
Prerequisites: This guide is written assuming that you have some
understanding of programming fundamentals, and in particular, the C language. I would
recommend getting some knowledge of networking, and network protocols in general before
trying to do any serious programming on networks.
Disclaimer: The author provides this information purely out of the
goodness of his heart, with no warranty implied. Use this information at your own risk,
because I assume no responsibility for anything that you do (good or bad) with this
information. Remember that when programming with network protocols, you have the ability
to affect all machines hooked up to the network that you are programming on, so a bug in
your code can cause problems in everyone else's computer. All example code listed is just
an example, you may need to tweak it to make it work, but for the most part, it has been
tested.
eMail author: Kevin Bentley
There are some terms that you will need to know to get
started, here is a basic (not official) definition for some of them.
Socket: Think of a machine with IPX as a power line.
As many things as you plug into it, the same powerline provides power for them all. But,
they connect to different sockets. The same concept can be used for IPX. One IPX driver
might have several applications using it, and each has it's own socket, so the
IPX driver knows who to send the data it receives to.
ECB: (Event Control Block) This is a sort of
intelligent buffer used for sending and receiving data via IPX. It specifies all the
information about the data to be sent (or data that has been received). The ECB is always
supplied by the application, and the driver fills in certain parts of it. An ECB is
defined in Table 1.
ESR: (Event Service Routine) This is a somewhat
advanced topic, but and ESR is a function that you specify for the IPX driver to call, to
notify you that a packet has arrived. Each ECB must either specify NULL, or a pointer to a
function. Unless you are writing a very high speed game, or a program where you cannot
check the status of the ECB within an idle loop, you won't need an ESR for now.
Fragment In an ECB, you may have multiple parts of a
packet in different memory locations. For example, the first fragment is always an IPX
header. The next fragment will be the actual data you want to send (or buffer to receive
data).
Application Startup
Before you do anything with IPX, you need to call IPXInitialize(). This
tells the driver you intend to use it.
Next, you need to choose a socket, and open the socket. If you are only sending
data, you can 0 for the socket number, and IPX will find a socket, and assign it to you.
Most the time, you will need to choose a socket yourself, I would recommend that you use
something higher than 0x8000. To open a socket, call IPXOpenSocket(). The return
code is the socket that was opened, or –1 in case of an error.
Sending Data
In order to send data, you need to allocate a buffer big
enough for the ECB. You will also need a buffer for the IPX header.
You need to initialize several members of the ECB, and the IPX header before you
send the packet. Refer to Table 1, you will see the required fields in boldface for the
ECB. It is important that the FragmentDescriptor[1] be filled in with the pointer to your
data that you intend to send, as well as the size of the data that you want to send.
Table 2 lists the IPX header, and again, the required fields are in boldface. Note
that the value for PacketType should almost always be 4. If you want to send a broadcast
packet (to everyone on your network) fill in the immediate address, and the destination
address with the value 0xFF in every byte of those fields. In order to get the value to
put in the ImmediateAddress field, call IPXGetLocalTarget() with the IPX address,
and a pointer to the ImmediateAddress. It will figure out the ImmediateAddress, and fill
it in for you.
Once the ECB and the packet header are complete, you can call
IPXSendPacket() with a pointer to the filled ECB. Your program can then monitor the
ECB's CompletionCode, and InUseFlag variables, to know when the packet has been
sent. It is up to the application to free this memory (or, you can re-use it for the next
send). The IPX driver will simply send the data, then change the completion codes. Tables
3 and 4 list the values for InUseFlag, and CompletionCode.

Receiving Data
In order to receive data, you must allocate memory for an ECB, the IPX header, and
any data that you expect to receive (FragmentDescriptor[1]) as well as the ESR (in most
cases, set the ESR to NULL). Then call IPXListenForPacket() with a pointer to the
ECB, where the IPX driver will put the received data, and fill in the IPX header.
You can now watch the CompletionCode of the ECB that you prepared, and when it is
0x00, you can retrieve the data, and reuse that ECB for the next incoming packet. For most
cases, if you are receiving much data, I find it safe to use more than one ECB to listen
for data. If you don't have an ECB available when the packet arrives, you
won't get the packet.
Cleaning up
When you are done, first use IPXCancelEvent() for any ECBs that are pending
(You called IPXListenForPacket() but it never received a packet) and then call IPXCloseSocket()
for any sockets you have opened.
Misc. IPX Information
If you want to know your own IPX address, call IPXGetInternetworkAddress(),
with pointer to a buffer, and it will fill the buffer with your own IPX address.
There are many other aspects to IPX programming, but the ones
I have mentioned should be enough to get most people going. I have written many IPX
programs using the code listed in Table 5. Feel free to use it, but you may have to tweak
it to get your compiler to accept it. It originally was written for Borland C, but should
be portable with a few modifications.
If you are programming under Windows 95, you might want to
look at using Winsock IPX. If you have ever used Winsock for TCPIP, you will find that it
is almost exactly the same using IPX as it is using TCPIP. The only difference is how you
specify the address. The Microsoft Win32 SDK has an example application that uses Winsock
IPX, take a look at it for your 32bit IPX development needs.
Please send me feedback, and if you have anything to add,
send it to me, I will be glad to post it, and give you due credit!
Send feedback to: Kevin Bentley
Table 5
//********************************************
//********************************************
//begin DOSIPX.H
//********************************************
//********************************************
#include <dos.h>
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long LONG;
union REGS regs;
struct SREGS sregs;
typedef struct IPXAddress {
BYTE Network[4]; //Big-Endian
BYTE Node[6]; //Big-Endian
BYTE Socket[2]; //Big-Endian
}IPXAddress;
typedef struct IPXHeader {
WORD CheckSum;
WORD Length;
BYTE TransportControl;
BYTE PacketType;
IPXAddress Destination;
IPXAddress Source;
}IPXHeader;
typedef struct ECB {
void far *linkAddress;
void (far *ESRAddress)();
BYTE InUseFlag;
BYTE CompletionCode;
WORD SocketNumber; //Big-Endian
BYTE IPXWorkspace[4];
BYTE DriverWorkspace[12];
BYTE ImmediateAddress[6];
WORD FragmentCount;
ECBFragment FragmentDescriptor[4];
}ECB;typedef struct ECBFragment {
void far *address;
WORD size;
}ECBFragment;
BYTE IPXInitialize (void)
{
BYTE rvalue;
asm {
mov ax,0x7a00;
int 0x2f;
mov rvalue,al;
}
return rvalue;
}
int IPXOpenSocket(short SocketNumber)
{
BYTE rvalue1;
short rvalue2;
asm {
mov bx,0;
mov al,0;
mov dx, SocketNumber;
int 0x7a;
mov rvalue1,al;
mov rvalue2,dx;
}
if (rvalue1) return -1;
else return rvalue2;
}
void IPXCloseSocket(short SocketNumber)
{
asm {
mov bx,1;
mov dx, SocketNumber;
int 0x7a;
}
}
int IPXListenForPacket(ECB *ecb)
BYTE rvalue1;
short ECBSEG,ECBOFS;
ECBSEG=FP_SEG(ecb);
ECBOFS=FP_OFF(ecb);
asm {
mov si,ECBOFS;
mov es,ECBSEG;
mov bx,4;
int 0x7a;
mov rvalue1,al;
}
if (rvalue1) return 1;
else return 0;
}
int IPXGetInternetworkAddress (BYTE far *Address)
{
short ADDRSEG,ADDROFS;
BYTE rvalue;
ADDRSEG=FP_SEG(Address);
ADDROFS=FP_OFF(Address);
asm {
mov si,ADDROFS;
mov es,ADDRSEG;
mov bx,9;
int 0x7a;
mov al,rvalue;
}
if (rvalue) return 1;
else return 0;
}
void IPXSendPacket(ECB *ecb) {
short ECBSEG,ECBOFS;
ECBSEG=FP_SEG(ecb);
ECBOFS=FP_OFF(ecb);
asm {
mov si,ECBOFS;
mov es,ECBSEG;
mov bx,3;
int 0x7a;
}
}
void IPXGetLocalTarget(BYTE far * TargetAddr,BYTE far *immediateAddress,int *XportTime)
{
short TGTADDROFS,TGTADDRSEG,IMMEDOFS;
TGTADDRSEG=FP_SEG(TargetAddr);
TGTADDROFS=FP_OFF(TargetAddr);
IMMEDOFS=FP_OFF(immediateAddress);
asm {
mov si,TGTADDROFS;
mov es,TGTADDRSEG;
mov di,IMMEDOFS;
mov bx,2;
int 0x7a;
mov *XportTime,cx;
}
return;
}
void IPXCancelEvent(ECB *ecb) {
short ECBSEG,ECBOFS;
ECBSEG=FP_SEG(ecb);
ECBOFS=FP_OFF(ecb);
asm {
mov si,ECBOFS;
mov es,ECBSEG;
mov bx,6;
int 0x7a;
}
return;
}
//********************************************
//********************************************
//end DOSIPX.H
//********************************************
//******************************************** |
|
|