Contents of the IPX.DOC file
I have been working on a NetWare space-war game (for up to six players) for
the past few months, and one of the programming requirements was to be able
to send and receive IPX packets. Since the project is in QuickBASIC 4.0, I
had to write my own IPX routines (I have routines in Pascal and "C").
I am releasing my IPX routines into the public domain so that you need not
have to write your own. I am taking a lot of time here doing this to meet a
need. If I put forth effort now, it may save dozens of folks time by them not
having to figure it out themselves.
This document is intended to highlight some of the information you will need
to know about IPX. It is NOT intended to replace better information.
To begin. . . . .
There should have been seven files in the ZIP/PAK/LZH/ZOO/ARJ/ARC file you
downloaded. The file files should be:
IPX.BAS All routines in one file
IPXS.BAS Sample IPX Send Code
IPXS.EXE Sample Executable IPX Send
IPXR.BAS Sample IPX Receive Code
IPXR.EXE Sample Executable IPX Receive
CHAT.BAS A Chat program using these routines
IPX.DOC This Document
If you do not have all of these files, and would like a copy of them all,
call me, David Rice, at 714-458-6000. You may also leave a message at Fido
Node 102/902 (The Skeptic Tank).
These two routines are NOT included with the QuickBASIC NetWare Function
Library I wrote previously. That library may be found on various BBSs by the
name QBNW-20.ZIP, which includes Print Queues, connection information,
network address retrieval, etc. If you downloaded this file thinking you were
getting QBNW-20, well, this ain't it.
Note that the routines here are IPX and =not= SPX. I chose to use IPX for
several reasons. The first is, it's faster than SPX. Another is, IPX packets
have a slightly larger datagram area, and can thus carry more information.
The third is, IPX is a "connectionless" packet protocol whereas SPX requires
a connection before a packet may be sent and received. With IPX, the user
need not be logged onto the network: she or he need only load IPX.COM.
IPX does NOT guarantee delivery, as SPX does. When an IPX packet is received,
its header will contain the address of the computer that sent it. This means
that even though IPX does not guarantee delivery, the program you write to
send and receive the packets can do the checking itself. For example:
Computers A and B are running your program.
Computer A sends a packet to Computer B and then checks the
packet's INUSE flag. When that flag turns to zero (0),
Computer A goes into listen mode. If the INUSE flag stays non-
zero for five or ten seconds (you decide), there may be an
error, and your program may handle that error as you the
programmer sees fit.
So now Computer B finishes whatever it was doing, and goes
into listen mode. It says, "Hey! I have a packet here." It
reads the packet, setting the INUSE flag to zero (see how it
works?). It should then go into Send mode, and send an
acknowledgment to Computer A, saying "Got it, thanks a bunch!"
It will know which computer to send it to, because the packet
it received has the address in the header.
Though I suspect you may send multiple IPX packets without checking to see if
the first arrived before sending the second, there is a good reason to wait
for the confirmation. IPX packets are not sequenced, as SPX ones are. The
computer doing the "Listening" may very well receive the second packet before
it receives the first! We wouldn't want the space ship to blow up before the
torpedo hits it, now would we?! Of course not!
I suggest you use the first four bytes of the Datagram (the area that holds
the packets' data) as a sequence field. Every time a computer sends a packet,
add 1 to this counter. This way, the receiving computer will know that it has
missed a packet when it reads the Datagram's sequence value and notices that
it incremented by 2 (or more) instead of 1.
If you do use a Sequence field, the size of your Datagram will go from 546
bytes to 542 bytes.
IPX packets may be fragmented. This means that if you have data that is in
logical chunks, you may specify those chunks within the ECB structure. Your
size limit is still 546 bytes. Why do multible fragments? Suppose you wish to
send in one packet several different variables, such as A$, B$, C$, and D$.
You could define five fragments: one for the 30-byte header, and four for the
four variables. Behold:
LinkAddressOff AS Integer
FragAddOfs1 AS INTEGER
FragAddSeg1 As INTEGER
FragSize1 AS INTEGER
FragAddOfs2 AS INTEGER
FragAddSeg2 AS INTEGER
FragSize2 AS INTEGER
FragAddOfs5 AS INTEGER
FragAddSeg5 AS INTEGER
FragSize5 AS INTEGER
DIM ECBS AS ECBStructure
ECBS.FragAddOfs1 = VARPTR(IPXS)
ECBS.FragAddSeg1 = VARGEG(IPXS)
ECBS.FragSize1 = 30
ECBS.FragAddOfs2 = VARPTR(A$)
ECBS.FragAddSeg2 = VARSEG(A$)
ECBS.FragSize2 = LEN(A$)
ECBS.FragAddOfs5 = VARPTR(D$)
ECBS.FragAddSeg5 = VARSEG(D$)
ECBS.FragSize5 = LEN(D$)
In the send sample IPXS, the Destination Network was set to four zeros. See
the code, IPXS.DestNode. This means that the IPX packet will be distributed
on the default network: the one that the computer is hard cabled to--- if you
are sending packets across bridges or otherwise to another network, YOU MUST
KNOW THAT NETWORK'S ADDRESS AND PUT IT IN THIS FIELD.
In the send sample, IPXS, the Destination Node Address was set to six FFs.
This means the packet will be "broadcast" to all computers. If you wish to
send a packet to a specific computer, you must place that computer's address
Enhanced Program Flow:
Computer A sends a broadcast packet to DestNode FFFFFFFFFFFF, saying
"Anyone out there?"
Computer B receives the broadcast packet and sends an acknowledgment
to Computer A. "Yep, I'm here. What of it?"
Computer A receives the acknowledgment packet, and MAKES A NOTE OF
ITS ADDRESS. From then on, it sends only specifically addressed
Along comes Computer C. It sends a broadcast packet (on
FFFFFFFFFFFF) Saying "Anyone out there?"
Both Computer A and Computer B send acknowledgment packets to
Both Computer A and Computer B make a note of Computer C's address.
Computer C makes a note of Computer A's and Computer B's address.
Now all computers know each others' address, and none need broadcast
on FFFFFFFFFFFF. If a fourth computer, Computer D, comes along, it
makes a broadcast on FFFFFFFFFFFF, and all computers make a note of
the new computer's address, and the new computer makes a note of the
other computers' address.
It's not difficult to keep track of all this. Just REDIM an array to hold all
of the Network Addresses (IPXS.DestNet) and another to hold the Network Node
Addresses (IPXS.DestNode), and keep track of how many computers are running
your computer. This is called a Distribution List.
If you're a bright lass or lad, you will have noticed something wrong with
sending packets out as broadcasts (FFFFFFFFFFFF). If a computer sends a
packet on a socket, it may very well be the only one to receive it! In other
words, it can, and will, be talking to itself. The solution, of course, is to
use two sockets: one to send, one to listen. However, that makes yet another
Your program sends on Socket 1, and listens on Socket 2. THAT'S the
problem! Any other computer running your program will be doing the
same damn thing; listening on a socket that none send on but all
listen to, and sending on a socket all send on but none listen to.
That's no way to strike up a meaningful conversation.
If you try and be smart, and say "I'll listen and send on both,"
you'll just end up talking to yourself again, and that's where we
came into this house of mirrors!
The solution? If you must broadcast, check ALL received packets for
the source node, and if it came from one's own computer, ignore it!
That is, even though you're talking to yourself, you don't have to
listen, let alone talk back.
Suppose a computer runs your program, and it is the only one at the moment
running it. This computer must wait for other computers to run your program.
You could have the computer send and receive on the same socket: send a
packet then listen for a packet. When the computer receives a packet that is
not self-addressed (Node number), that means a new computer has started
running your program.
For the same scenario above, but using two sockets (which is a better idea),
your computer could send on one socket and listen on another. After the
computer listens for 3 or 5 seconds, have your program SWITCH SOCKETS, but
AFTER your program issues an IXPCancelS call on the original SEND. See the
If one computer wants to quit the program (for instance, his or her space
ship gets blasted to hell-an-gone), it is deemed proper etiquette for that
computer to send a packet to all of the other computers, so that they may
remove that computer from their distribution list.
However, you may wish to have one of the computers running your program to
act as a "server." That is, the first computer to run your program would
respond to new computer's broadcasts by sending the new computer ALL OF THE
OTHER COMPUTERS' ADDRESSES. All other computers would ignore broadcasts. This
is how my space wars game tells a new computer which other computers are
playing the game. When that player exits the game, the job of server is
passed on to another computer still playing the game.
(The above description does not describe a SAP (Service Advertising
Protocol). SAPs are different animals completely. A SAP is much like an IPX
packet, but it is sent every 60 seconds, and it adds its name to every
Bindery on every file server on the network, even over bridges and routers.)
Your program should also keep track of unsent packets. If a packet is not
sent within 30 seconds (give or take), you may assume that there is a
problem: the destination computer may have exited the program. When a packet
has not been delivered, your program should automatically remove it from the
distribution list--- assume the user quit the program.
You may also want to have a "user time-out." If the program detects that the
user has done nothing for ten minutes, have her or his computer send a "I'm
Quitting This Program" message to all of the other users, so that they may
remove that computer from their distribution list. Then have her or his
In the sample programs, the Datagram size was set to 546 bytes. You may
actually send from 0 to 546 bytes. I just set it to 546 bytes in the sample
as the default.
Why would someone send a zero-byte Datagram? Suppose in the program flow
above, Computer A sends a broadcast on FFFFFFFFFFFF. All this computer is
interested in is telling the other computers currently using your program
that it is running your program: the IPX header holds Computer A's address,
and Computer A has no need to send any data in the Datagram. Likewise, the
acknowledgment packets need not send any data in the Datagram, because they
are only telling Computer A their addresses, which is contained in their IPX
If the packet does not send any data, set the variable ECBS.FragSize to 30
(which is the size of the header). Likewise, if the size of the data you wish
to send is, for instance, 30 bytes, set ECBS.FragSize to 60 (30 bytes for the
header, and 30 bytes for the Datagram). There is no reason to send a 546 byte
packet when you do not need to.
Packet type is important. There are eight type ranges defined:
0 Unknown Type
1 Routing Information Packet
2 Echo Packet
3 Error Packet
4 Packet Exchange Packet (PXP or PEP)
5 Sequenced Packet Protocol Packet (SPX)
17 NetWare Core Protocol
For IPX, you must use type 0 or 4.
The sockets you use is also very important. You cannot use just any sockets,
because there very well may be programs your networks are using that already
use that socket for their processes. There are several known sockets you do
NOT want to use. These are (in HEX):
1 Routing information
1-0BB8 Xerox's usage
0BB9-- Dynamically assignable
0451 Novell File Server
0452 Novell Service Advertising Packet
0453 Novell Routing
0455 Novell NetBIOS
0456 Novell Diagnostic
If you call Novell, they will assign you socket numbers, above &H8000. Tell
them how many you need, and your program's name. You do not want to
inadvertently step on someone else's sockets. You may wish to ask for one
more than you think you'll need, to be on the safe side.
However, there's a much better way to choose a socket. Let IPX do it for you!
If you set your socket to zero, IPX will assign a random socket number to
You may also arbitrarily assign a socket number from within the "dynamically
assignable" range, such as I did in IPXS and IPXR (&H5555). This is a range
from &H4000 to &H7FFF.
It is a good idea to set up SEVERAL ECBs, one for each process your program
will perform. That is, one for Sending, one for Listening, one for
Broadcasts, one for each specific process your program will do.
You may build a packet and send it at a predetermined time by using the
IPXSchedule call. You pass to this routine the number of clock ticks
(approximately 1/18 of a second each tick) to delay. When the delay time
counts down to zero, the packet is sent, no matter what your program happens
to be doing at the time. This can be handy for performing repetitive packet
You may cancel an event, whether it be a Scheduled, Send, or Listen, by
calling IPXCancel. If the event has already occurred, you can't cancel it
Want to know how long an IPX event took? Call IPXMarker before and then after
performing a send or listen, then subtract the first result from the second.
The time will be in 1/18 of seconds, from 0 to 65,535.
You may use the call GETMYADDRESS to get the computer's network address. It
will return the Network and Node address, in Binary and Hex.
It is considered proper to send IPX Disconnects to computers you are finished
talking to. This will tell the other computer's network driver to abandon all
services it was performing FOR YOU; it will continue to perform all other
When you set an address variable, the routines expect it to be a String, in
Binary. For instance, if the address is A0000F18, use the FUNCTION called
HexToBinary$("A0000F18") to convert from Hex to String Binary. To go in the
opposite direction, i.e. to convert a String of Binary, use TurnToHex.
The first step in sending or receiving an IPX packet is to determine if
IPX.COM has been loaded. If IPX.COM is not loaded, and you try to send a
packet, the computer will probably lock up. EMM386.EXE will give you a GPE
(General Protection Error). If this happens, you must reboot the machine.
Use the FUNCTION IPXInstalled% to see if IPX.COM is installed. It returns a
zero if it is =NOT= installed.
Your computer may open many sockets at once. You could have your program send
packets on one socket, and receive packets on another socket. If you call
OPENSOCKET and receive a Status other than 0 or FF, do not attempt to send a
packet on that socket--- see the Novell documentation on SHELL.CFG on how to
increase the default socket count.
After the socket is opened, you may send packets.
After each SENDPACKET call, your program "should" also call
RELENQUISHCONTROL. This allows your computer to give up some CPU time to the
IPX handler. This is NOT required, however (unless your computer program is
acting as a server, or multi-tasking). It is just good packet etiquette.
When you are finished with a socket, please close it with CLOSESOCKET. The
routines will close a socket for you when the program terminates, but it is
still good practice to close it specifically in the program.
Please note that in the IPXS (send) sample, the packet is sent only once, and
then a loop to check the InUseFlag is entered. Do =NOT= place the call to
SENDPACKET within the loop.
Also note in the IPXR (receive) sample, the call to SOCKETLISTEN is =NOT= in
Once your computer program issues a Send or Listen, IPX.COM will handle the
packet. IPX.COM will modify the state of the ECB (Event Control Block)
depending on the status of the packet. All you need do is monitor the ECB,
while IPX.COM does its best to deliver the packet, or receive the packet.
If you plan on writing a multi-user game, you may wish to look into SAPs,
where one computer playing the game acts as the game's server, and all the
other computers send information to this server. The server would then
distribute this information to all computers playing the game: this way, a
host game-playing computer need only send and receive IPX packets from one
computer (the server), while the server sends to all computers in the game.
Take the SAP approach for your game one step further. Suppose your program
periodically checks each player's computer to determine the fastest computer
playing. Your program could assign that computer as the server. Then when a
faster computer starts to play your game, the server could switch. If the
server quits, the next fastest computer could act as the server.
Use the IPXMarker routine to determine which computer is the fastest in IPX
event handling: the 80486 50Mhz machine might be the fastest machine, but if
it is on another network, over a bridge, gateway, or router, it may well be
the slowest in delivering packets!
There is much more to IPX and SPX use. However, I only went through the very
basics in this document.
Finally, any information in this document could be completely wrong; also,
the programs I wrote could also be wrong. I take no responsibility, and no
blame, if you find that these routines fail to work, wreak havoc with your
network or love life, or get you fired from your job because your boss says
"That idiot programmer crashed the system again!" one too many times.
July 24, 1992