; LANLIB.TXT -- Documentation for LANLIB ; Copyright (c) 1994 by Allen Brunson version 1.00 06/30/94 ****************************************************************************** * * *** Trademarks *** * * ****************************************************************************** Borland is a registered trademark of Borland International, Inc. Microsoft and MS-DOS are registered trademarks and Windows is a trademark of Microsoft Corporation. Netware and Novell are registered trademarks and IPX is a trademark of Novell, Inc. ****************************************************************************** * * *** Introduction *** * * ****************************************************************************** LANLIB is a library of routines written in assembler for communication amongst multiple PCs using the IPX protocol, the low-level language spoken by Novell's NetWare. It is designed to be called from C, but if you know what you're doing, you can get it to work with assembler, C++, Pascal, or any other language that can be made to support the C calling convention and works with standard object file formats. Since LANLIB is written in assembler, its impact on the size of your program is minimal; it has only 2.8k of code and requires about 12k of memory for communication buffers. IPX is a fast and very low-level protocol, designed for maximum speed. It does not guarantee delivery, but Novell claims IPX packets properly arrive at their destinations about 95 percent of the time. IPX can be quite cumbersome to use. Given its orientation, a great many details of NetWare networks must be known by the programmer to use it properly. This library takes care of almost all of those details, allowing you to concentrate on your program's main function rather than worrying about IPX specifics. This library is geared towards the needs of smaller projects, where perhaps up to 20 or so PCs will be exchanging data. Larger projects would probably be best served if the programmer were to learn how to make IPX calls directly or by some other product. This library does not offer any NetWare-related services, such as logging in, logging out, copying files, getting lists of logged-on users, and so on. Its only purpose is to allow programs running on multiple PCs to share data. This document covers issues specific to using LANLIB. It assumes that you are familiar with NetWare and IPX concepts. It would be a good idea to read NETWORK.TXT before tackling this file. The file LANTEST.TXT explains the LANLIB demo program, LANTEST. LANTEST uses every LANLIB routine, so it is a good reference for implementation details. Shareware Version Restrictions ------------------------------ The shareware version of LANLIB does everything that the registered version does, with one exception: the procedure ipxRouteFind() has been removed, so the shareware version is limited to only one network segment. The shareware version is provided for evaluation purposes only. You are NOT free to distribute programs you create with it. ****************************************************************************** * * *** Adding LANLIB To Your Program *** * * ****************************************************************************** LANLIB has been tested with both Microsoft and Borland C++ compilers. One small snag is that the Microsoft C++ compiler won't be able to use the Tiny model version of LANLIB; its linker reports that far segment accesses are not allowed in that model. Other compilers will probably work if they can deal with standard object files. LANLIB's use is limited to real-mode DOS executables. I am working on a version for the Watcom 32-bit compiler, but at this writing I don't have a release date. Novell's documented method for determining the presence of IPX requires the use of the DOS multiplex interrupt, which was introduced with DOS version 3.0. Therefore, LANLIB will not work with any DOS version earlier than 3.0. Special note for users of Microsoft compilers: Microsoft C defaults to two-byte (one word) structure member alignment. This will NOT WORK with LANLIB, which uses one-byte aligned structures. (It HAS to; IPX itself uses one-byte aligned structures.) You must set the compiler to one-byte structure alignment for it to work with LANLIB. LANLIB is contained in one of four .LIB files, depending on your chosen memory model: LANLIBT.LIB Tiny model LANLIBSC.LIB Small and Compact models LANLIBML.LIB Medium and Large models LANLIBH.LIB Huge model Include one of these .LIB files in your project. LANLIB always uses far pointers for passed data parameters, so there's no distinction between Small and Compact (near code calls) or between Medium and Large (far code calls). The Tiny model code never makes direct references to the data segment, so a program built with LANLIBT.LIB can be turned into a .COM file. The Huge memory model has special considerations for the data segment register, so it requires its own .LIB file. Include the file LANLIB.H in any module that will be calling the LANLIB routines. It is important that you follow this rule: LANLIB routines all take far pointers to data structures, and pointers in the small data memory models are by default near, so messy crashes will result if you don't perform this step. Defines in LANCFG.H are used to set the number of send and receive packet buffers, the number of bytes per packet, the socket number, and the number of networks to allow. Make a copy of this file for each program that will use LANLIB and then include LANCFG.H in each source file that will call LANLIB routines. See a later section called "Configuring LANLIB With Defines in LANCFG.H" for more details. The routines in LANUTIL.C can be used to work with IPXADDRFULL structures. While I was writing the demo program I had to manage the addresses of many PCs; each requires an IPXADDRFULL structure. Since this is a large hunk of data with several unwieldy fields, I wrote routines to copy one address to another, convert an address to a string, compare two addresses for equality, and so on. LANUTIL.C is the result. See a later section in this file for reference. ****************************************************************************** * * *** Calling LANLIB from Assembler *** * * ****************************************************************************** While LANLIB was being beta-tested, I was contacted by a programmer who was interested in using it with a pure assembler program. This is entirely possible; LANLIB is written in assembler itself. I've included the file LANLIB.INC, which contains the same defines as LANLIB.H but in assembler format, and LANCFG.INC, which duplicates LANCFG.H. All the LANLIB procedures use the C calling convention so you must do the same when calling them from assembler. Each procedure's arguments are pushed on the stack in right-to-left order; after the call, you must get rid of them by POPing them off (or by adding a value to SP, the stack pointer). If a procedure returns a value, it will be in AX on return (this is standard C procedure). Since C compilers don't require procedures to save many registers, the LANLIB procedures trash most of them. All registers except BP, SP, SI, DI, SS, and DS might be trashed. You won't be able to use the utility routines in LANUTIL.C in an assembler program, of course. But their use is optional; you may discover you don't need them; and if you do, they are all quite simple and easy to port to assembler. ****************************************************************************** * * *** An Overview Of LANLIB Structures *** * * ****************************************************************************** You don't need to know a whole lot about IPX structures to use LANLIB; it pretty much takes care of the details for you. However, a general overview of the seven structures defined in LANLIB.H (and LANLIB.INC) seems appropriate. struct IPXADDR: This is the network, node, and socket number for a PC. It is enough to uniquely identify a process on a PC, but not enough info to be able to send a packet to any process on any PC anywhere on an internetwork. Note that the socket field is high-low (Motorola) format. This structure is defined only for inclusion in the IPXPKTHDR structure. struct IPXADDRFULL: This is a superset of the IPXADDR structure, adding an immediate address field. Therefore it contains enough address info to send a packet anywhere. I kind of "made up" this structure; nowhere in "official" IPX do you find all four of these fields grouped together; however it seems quite convenient for storing the addresses of other PCs you wish to communicate with. LANTEST uses a group of these structures to keep track of all other LANTEST users; it is assumed that LANLIB users will employ a similar scheme. Keep in mind that the socket field MUST be maintained in high-low byte order or sends and receives will not complete properly. Routines for manipulating IPXADDRFULLs are given in LANUTIL.C. struct IPXDIAG: This is the structure of the data portion of the IPX diagnostic packet. It is used by ipxRouteFind() to locate other network segments. struct IPXDIAGREPLY: This is the format of the data portion of IPX diagnostic reply packets received in response to diagnostic requests; again, it is used by ipxRouteFind(). struct IPXEVENT: This is another structure I "made up." LANLIB contains two ESRs (Event Service Routines), one which IPX calls when a send is completed, the other when a receive is completed. Each of these ESRs maintains a queue of events that it has been notified of (except that the send ESR simply throws away events if the send completed without errors). Each event is stored in a queue of IPXEVENT structures. These queues are maintained and processed entirely by internal LANLIB functions. struct IPXPKTHDR: This is the 30-byte packet header that all IPX packets must have. You don't need to directly concern yourself with it; LANLIB will fill out the fields in IPX packet headers where necessary. struct ECB: This is the standard IPX Event Control Block. It contains pointers to two "fragments," the packet header and the packet data. An ECB can actually have fields for any number of "fragments," but LANLIB always uses two, one for the header and one for the data. Again, LANLIB will take care of filling out ECB fields, so you don't have to worry about them. ****************************************************************************** * * *** Configuring LANLIB with Defines In LANCFG.H *** * * ****************************************************************************** LANLIB is tailored to the needs of your program by setting the defines in LANCFG.H (or LANCFG.INC for assembly programmers). In this way, you determine how many ECB/packet pairs are available for sending and receiving, the size of the packets, the socket number, and the maximum number of network segments allowed. (These defines are then used as parameters to ipxStart() and ipxRouteFind(), described below.) You will also indirectly be setting how much memory the communication data will take. Set IPXSOCKET to the socket number you want your program to use. This value will be passed as a parameter to ipxStart(). Novell states that "dynamic" socket numbers, that is, ones not officially reserved, start at 4000h and end at 7FFFh. The default socket number is 51E7h, but you should open up the file and change it right now, because everybody else who uses LANLIB will also be getting that as the default, and two programs running on the same network with the same socket number will bump heads. See the file NETWORK.TXT for more information on socket numbers. Set IPXNETCNT to the maximum number of network segments you will want LANLIB to be aware of. The default is 10. Most NetWare networks have six or fewer segments. Setting it to higher numbers means that networks further away will be found, but communicating with PCs farther away will take longer and will require a bigger structure for managing network segment addresses. The shareware version of LANLIB is effectively limited to 1 regardless of what you set this value to. LANLIB imposes no upper limit on this value, but generally speaking, setting it higher than 300 seems pointless. Set IPXRECVCNT to the total number of ECB/packet pairs you wish to make available for receiving incoming packets. The default is 30. The minimum value is 0; the maximum is 250. If you are planning to use ipxRouteFind() to locate other network segments, then the minimum is 30. It is passed as a parameter to ipxStart() and is used to set the number of receive ECBs, packet headers, packet data buffers, and the receive event queue size. You can make your program completely "deaf" to incoming packets by setting this value to 0. If your program will only receive packets infrequently and you're prepared to retrieve them quickly, you might get by with setting this value to 1. If you anticipate receiving lots of data and your program's main loop might not get around to processing incoming packets for several seconds, set this value to a high number, perhaps as high as 200. It's far better to set this number too high than too low, because if a data packet arrives and all the ECBs are already full, IPX will simply throw it away without so much as an error. Each ECB/packet pair requires one ECB (48 bytes), one packet header (30 bytes), one entry in the receive event queue (4 bytes), and one packet buffer, the size of which is set by IPXDATASIZE (see below). Set IPXSENDCNT to the total number of ECB/packet pairs you wish to use for sending packets. The default is 8. The minimum value is 0; the maximum is 250. If you're going to use ipxRouteFind(), the minimum is 2. It is passed as a parameter to ipxStart(). It is used to set the number of send ECBs, send packet headers, send packet buffers, and the size of the send event queue. You can make your program listen-only by setting this value to 0. Generally this number can be lower than IPXRECVCNT because most network programs send less data than they receive and send requests are usually carried out very quickly. Even if all send ECBs are in use when you want to do another send, you'll simply get an error; you're free to retry the send a few milliseconds later. Setting this value to 1 is plenty enough for programs with light send needs. Even if your program does nothing but sit in a loop sending packets, you probably shouldn't need more than 20. Each send ECB/packet pair takes the same number of bytes as a receive ECB/packet pair (see above). Set IPXDATASIZE to the number of bytes of data you want to be able to send (and receive) in each packet. Don't take the 30-byte IPX packet header into account here; this number is only for data bytes. The default is 256. The minimum size is 0; the maximum is 546. If you're going to use ipxRouteFind(), the minimum is 256. It's entirely possible to send packets with zero data bytes; the receiver will know nothing more than the sender's address, but in some contexts this might be enough. If you'll be sending lots of little packets, set IPXDATASIZE to a small number; big streams of data would be better-served by large packet sizes (but this will require more memory). It's possible to send packets that are smaller than IPXDATASIZE, but it's never possible to send one that's bigger than this value. The amount of memory taken up by this setting depends on the values of IPXRECVCNT and IPXSENDCNT; each ECB/packet pair used for both sending and receiving will have one buffer of this size. ****************************************************************************** * * *** Dealing with Network Segments *** * * ****************************************************************************** Network segments involve some of the most difficult concepts of IPX programming, and therefore also some of the most difficult concepts in LANLIB programming. There are two general approaches you can take: Operate only on one segment, or operate with many or all accessible segments. Naturally there are advantages and disadvantages to each approach. If ROUTE is not defined (in LANTEST.H), then LANTEST will be a single-segment program. If ROUTE is defined, then it will function as a multiple-segment program (after ipxRouteFind() has been called, which is accomplished with the R command). Look for the conditional compile directive "#ifdef ROUTE" which appears in several places in NETWORK.C to see what's different for each approach. The Single Segment Approach --------------------------- Operating on only one segment is easiest, fastest, and simplest to manage, and the only mode available for LANLIB programs if you're using the shareware version. There are no worries about finding other network segments. Since no routers will be involved, you can rest assured that packets will arrive as quickly as possible. Every IPX-aware game I've ever seen operates in this manner (excepting games in development using LANLIB, of course). When you need to broadcast packets to find potential users in single segment mode, you merely call ipxAddrLocal() with a pointer to an IPXADDRFULL structure, then pass that structure to ipxAddrBrd() to set it up as a broadcast address, then pass that address to ipxSendPkt() for the broadcast. You don't need to concern yourself further with the concept of network segments. The Multiple Segment Approach ----------------------------- Operating with multiple segments is more complicated to manage and potentially slower if more than a few routers are involved, but far more flexible, and also better in tune with the size and scope of today's networks. I've installed and managed NetWare networks for many years now, and I can say for certain that networks with multiple segments are far more common than single-segment networks. It doesn't seem particularly sporting to restrict users from interacting with each other via your program simply because their PCs are attached to different network segments. The method for discovering network segments other than your own in NetWare environments is accomplished through "NetWare diagnostics." It's an interesting bit of trivia that NetWare file servers, routers, and PCs running NetWare's shell TSRs keep quite a few statistics on their performance, and are willing to give up this information (via SPX diagnostics) to anyone on the network who requests it, with absolutely no security checks whatever. You don't even have to be logged in to gather NetWare statistics. Another use for the statistics functions is to gather network segment information. When an IPX diagnostic request is broadcast on a network segment, PCs will respond with a simple list of "components" installed: IPX/SPX, shell, shell driver, and so on. Routers will return this information as well, but will also give information about all network segments they are attached to. Then the diagnostic request can be rebroadcast on these newly discovered segments, which will probably turn up more routers with information on more segments, and so on. This method is used by ipxRouteFind() to locate network segments. ipxRouteFind() is called with a structure of two or more IPXADDRFULLs. (If you were only interested in knowing about one network segment, you wouldn't need ipxRouteFind().) It sets up the first of these structures to be a broadcast address suitable for use on the local segment; it will have its node and immediate address fields set to FFFFFFFFFFFFh. In other words, it will be set up exactly as you would set it up yourself in a single segment program with a call to ipxAddrLocal() and then ipxAddrBrd(). This first broadcast address is used to send a diagnostic request on the local segment. PCs will respond with their diagnostic information, but they are ignored, and in fact subsequent diagnostic packets are filled with a list of "exclusion addresses," or nodes that should not respond to the request; all known PC addresses are added to this list. ipxRouteFind() only cares about routers. If there are routers on the segment, they will respond with more network segment numbers. These segments are all added to the table of network addresses; the node address fields will all be set to FFFFFFFFFFFh, suitable for broadcasting, and the immediate address fields will be filled in with a call to ipxAddrImmed(), which is the officially sanctioned method of determining the "correct" immediate address to use. Remember that packets sent to other network segments must first be sent to a router, which in turn sends the packet on its way towards its destination. The immediate address indicates the node number on the local segment of the router that will do the first part of the routing. Each new broadcast address set up in this fashion is used to send a diagnostic request on that segment. Newly discovered segments will continue to be added. ipxRouteFind() works its way through the list with the aid of two pointers: one that indicates the network segment currently being investigated and another that indicates the first free slot in the table for storing a newly discovered address. When the two pointers point to the same location, router-finding is finished; all known network segments have been investigated. So, when it's time to broadcast queries looking for other users of your program, you do not send out a request only on your network segment, as you would in a single-segment program. You send out a request on all segments in all the IPXADDRFULL structures you passed to ipxRouteFind(), using those addresses as the address parameter to ipxSendPkt(). You can use the sending addresses of received replies just as you would in a single- segment program, even though some will probably contain network numbers other than your own. If you want to allow your program to work with a few segments for flexibility, but not a huge number so as to keep the speed up, you can limit the number of IPXADDRFULL structures you pass to ipxRouteFind(). You could even save this number as a run-time variable and let the user change it according to his or her needs (obviously the user would have to be rather technically astute to understand this option, however). You could perhaps set a reasonable default, or maybe have two radio buttons in your "network options" dialogue, one labeled "favor speed" which would allow up to six network segments, the other labeled "find all possible users" which would allow up to 60. "Virtual" Network Segments -------------------------- It is likely that at least one of the segments that ipxRouteFind() locates for you will be a "virtual" segment. Starting with NetWare v3.0, servers must be assigned something called an "IPX Internal Network Number;" this is normally set in the server's AUTOEXEC.NCF command file with the command "IPX Internal Net xxxxxxxx". Internal network numbers are eight hexadecimal digits long, just like "real" network numbers. The server always makes itself node address 000000000001 on this network. This is its "official" network address and there will be no other nodes on the virtual network. Prior to version 3.x, a NetWare server's address was the network and node address of the first NIC installed in it (the one referred to as "LAN A"). Network information returned from routers has one byte that indicates the type of each known network, and so virtual networks can be distinguished from "real" networks. It would at first seem logical for ipxRouteFind() to throw away information on these virtual networks, but there are two catches that make this a bad idea. First is the fact that there is another type of "virtual" network. Servers running version 2.x of non-dedicated NetWare all have a virtual network segment that is used for the DOS side of the server itself. (Non-dedicated servers function as both a file server and as a normal DOS PC through the magic of multitasking.) Therefore this type of virtual network will have a PC on it that you might want to communicate with. From the standpoint of NetWare diagnostics, this type of virtual network is indistinguishable from a NetWare v3.x server's virtual network. Second is the fact that one possible use of LANLIB is to poke around inside NetWare itself. Filtering out the server's network segment would make it impossible to send requests directly to a NetWare file server. NetWare Diagnostics Cautions ---------------------------- In testing LANLIB, I have noticed that if lots of PCs are running diagnostic searches at the same time, one or more may end up with incomplete network information. I ran LANTEST on 16 PCs attached to a two-segment Ethernet network with one NetWare v3.12 server acting as the router. I sent a command to all PCs to start diagnostics at the exact same moment. Seven ended up with incomplete network information; they knew about their own network segment (of course), but did not find the second one or the server's "virtual" segment. Since each PC sends three diagnostic requests on each segment, and the server exists on all three segments, it had to (try to) send nine diagnostic replies to each PC. My guess is that the IPX drivers at each workstation were so busy sending and receiving diagnostic requests and replies that some were lost, or the server/router could not keep up with the demand. (Almost all the PCs were 486s; there were only two 386s.) Obviously this is a worst case scenario, but it's not unlikely that several people could start up your program at the same time. A possible option would be to allow the user to re-scan if all expected users do not appear, or perhaps to have a secondary diagnostic phase where all copies of your program ask all other known copies for their network info; if even one PC on a segment got all the information, then it could pass it on to all others whose knowledge might be incomplete. "Diagnostic inundation" is not the only reason that using NetWare diagnostics to locate network segments is not totally foolproof. It will work reliably almost all of the time in small- to medium-sized networks, where the only type of routers in use are probably NetWare file servers. Larger environments can be trickier. Some standalone routers may route NetWare packets from segment to segment and yet not respond to standard NetWare diagnostic requests. Given my resources, there's no way I can support non-standard routers in LANLIB. There is another method that can be used for locating network segments: the list of logged-in users (the "connection list") on a NetWare file server can be examined. This method has a big disadvantage, however: it requires that everybody who will use the program must be logged in to a file server. Ad hoc networks can spring up solely for the purpose of running a favorite network-aware game; many of these networks may be too small to even have a file server, so this would not be a good approach in those situations. Still, if a LANLIB user tells me that ipxRouteFind() isn't working in a particular environment she wants to support, I would probably write a secondary ipxRouteFind()-like procedure that operated via a server's connection list that could be used in troublesome environments. ****************************************************************************** * * *** ECB Usage Statistics *** * * ****************************************************************************** While I was writing LANTEST, I found myself wondering how many ECBs the program was actually using. It had the default total of 8 send ECBs, but was there ever a time when that many were in use? The LANLIB procedure for sending packets will report an error if there are no send ECBs free, but that doesn't tell you much. Receive ECBs are even harder to gauge; if you run out, IPX simply starts throwing away packets. That's when I built ECB usage statistics into LANLIB. It keeps track of how many receive and send ECBs are in use at any given moment in variables, and makes two other word-sized variables available to your program, "ipxRecvMax" and "ipxSendMax," that contain the maximum number of receive and send ECBs that have been in use so far. For the purposes of the statistics, a send ECB is considered "in use" between the time when you post it to IPX and the time that IPX notifies LANLIB that it has been sent; a receive ECB is considered "in use" beginning at the moment when IPX uses it to receive a packet and is no longer in use once you collect that packet and the ECB is put back into service. All the LANLIB procedures update these variables dynamically as packets are sent and received, when the Event Service Routines are notified that sends and receives have completed, and so on, so they will always be correct. You can reset the values of "ipxRecvMax" and "ipxSendMax" to zeroes at any time you like to start over again. I ran LANTEST with "flurry mode" turned on (which means it continually sends out packets as fast as it can) and checked the statistics. What I discovered is that it is very rare for LANTEST to need more than one send ECB. If the main loop is jiggered to favor sends over receives, then it might need as many as four, but not usually. Receive ECBs are a different matter. I discovered that normally the program gets along just fine with four or fewer receive ECBs in "flurry mode," but that every now and then some event will steal time normally used for processing incoming packets, like dealing with a lot of keyboard input, and the max receive ECB value will spike up to a value as high as 50 or 60. In fact, no matter how high I set the receive value, I could eventually get the program into a jam bad enough that it would use every last one of its receive ECBs. That's bad news, because it almost certainly means that there were at least one or two more packets that were lost. This is a good argument for writing your program to send acknowledges for all packet transactions. ****************************************************************************** * * *** LANLIB Error Values *** * * ****************************************************************************** LANLIB routines generally return zero to indicate no error or some positive error value otherwise (some routines take a pointer to a word-sized variable and return errors there). Possible error values are defined in LANLIB.H and LANLIB.INC along with a brief description for each. All defines begin with the letters "ipxe", or "IPX Error." ipxeNOERR is defined as 0; other values begin at 2 and head upward from there. Further treatment of the error values is given in the descriptions of the LANLIB routines. It is strongly recommended that you use the error defines in your program rather than the numerical values of the defines, because I reserve the right to change the numerical values in future versions of LANLIB. It was my original intention to use IPX's own error return values, but this proved to be unworkable. Almost every IPX call can return the error code FFh, for instance, but it means something different in every case. I wanted one set of error codes that always meant the same thing, so procedures in LANLIB all "translate" IPX's errors into one of the LANLIB error values. Note that, in some very rare cases, you may get an error return value other than the ones listed in LANLIB.H. Novell has released many, many different versions of the IPX TSRs over the years, and I wouldn't be surprised if some of them return error values not given in Novell's documentation. Naturally LANLIB can only translate error values that it knows about. It is programmed so that if IPX returns an unrecognized error value, it will pass the unknown value straight through to your program untranslated. Chances are good that such an error would be in the E0h to FDh range; IPX calls tend to return high-numbered errors. If you get such an error value, I'd be interested in hearing about it so I can incorporate it into future versions of LANLIB. ****************************************************************************** * * *** Using The Routines in LANLIB *** * * ****************************************************************************** The following is a reference guide for all the routines in LANLIB that your program can use. This is NOT the place to start if you don't understand the concepts involved. Begin by reading NETWORK.TXT, then the earlier parts of this file. Use this section as a day-to-day reference for the routines. ipxAddrImmed() -------------- Prototype: word ipxAddrImmed(struct IPXADDRFULL far *ipxAddr, word far *ticks); This procedure calls the IPX routine known as IPX Get Local Target to get the preferred immediate address for a network address. At minimum, the network and node address fields in "ipxAddr" should be filled in before calling this procedure. If successful, it will fill in the immediate address field. If the address is on the same network segment, then the immediate address will be the same as the node address; if it's on a different segment, then the immediate address will be that of the router that is best suited for the task. Parameters: * struct IPXADDRFULL far *ipxAddr: A pointer to an address containing a network number and node number which are known to be valid. It's okay if the node number is FFFFFFFFFFFFh (a broadcast address). * word far *ticks: A pointer to a word to receive the estimated time of arrival to this destination address, in IBM PC clock ticks (approximately 1/18th of a second). This time is only an estimate; actual transport time will vary depending on network traffic. Return values: * ipxeNOERR (FALSE): The immediate address was filled in without errors. * ipxeIPXNOTSTARTED: ipxStart() hasn't yet been called. * ipxeNOPATHFOUND: No path to the destination address could be found; the immediate address field hasn't been set. You should use this procedure only once for each address, rather than before each send, because it requires IPX to do some spelunking out on the network, which can create network traffic as well as take time. Generally speaking, use of this procedure is optional, because there is a more direct method for determining the immediate address for a network address: When a packet is received, simply save the full address of the sender, including the immediate address, and use that. However, there are some occasions where this procedure comes in useful. Since there can be more than one route to a given destination, there can be more than one immediate address that will work for a given address. When this procedure is used, IPX tries to determine the "best" route, taking network traffic and hop distance into account. This procedure is also useful if you know the network and node address of a PC you want to talk to but don't also know the immediate address. Finally, its estimate of time necessary to reach an address can be helpful if transport speed is important to your program. ipxRouteFind() uses this procedure to determine the best immediate address to use for each network address that it finds. ipxAddrLocal() -------------- Prototype: word ipxAddrLocal(struct IPXADDRFULL far *ipxAddr); This procedure gets the IPX address of the PC that your program is running on. It fills in every field of the IPXADDRFULL structure. The immediate address will be the same as the node address. Parameters: * struct IPXADDRFULL far *ipxAddr: A pointer to a structure to receive the address. It doesn't have to be initialized in any way, as every field will be filled in. Return values: * ipxeNOERR (FALSE): The address was collected without errors. * ipxeIPXNOTSTARTED: ipxStart() has not yet been called; the local address can't be retrieved until it is. ipxLibVer() ----------- Prototype: word ipxLibVer(void); This procedure gets the version number of LANLIB. It is the only LANLIB function that can be called before ipxStart() or after ipxStop(). The major version number is returned in the high byte and the minor version in the low byte. For example, a return value of 0100h would mean major version 1, minor version 0, or 1.0. ipxRecvChk() ------------ Prototype: word ipxRecvChk(void); This procedure checks to see if any packets have been received and are waiting to be picked up. If there are, you can retrieve them with ipxRecvPkt(). Return values: * FALSE: No packets are waiting. * TRUE: At least one packet is waiting. * ipxeIPXNOTSTARTED: ipxStart() hasn't been called; it isn't possible to check for packets yet. If IPXRECVCNT is 0, then this procedure will always indicate that no packets are waiting. ipxRecvPkt() ------------ Prototype: word ipxRecvPkt(void far *data, word dataSize, struct IPXADDRFULL far *ipxAddr, word far *pktSize, word far *error); This procedure checks to see if a packet has arrived, and if it has, it passes the data in the packet and the IPX address of the PC it was received from to your program. Parameters: * void far *data: A pointer to your buffer for receiving the data. * word dataSize: The size, in bytes, of your buffer. * struct IPXADDRFULL far *ipxAddr: A structure for receiving the address of the sending PC. * word far *pktSize: The address of a word that will receive the total size of the data in the packet. * word far *error: The address of a word that will receive the error code associated with this packet. Return values: * FALSE: No packets are waiting and nothing was copied to your data buffer or ipxAddr structure. "pktSize" is zero. "error" is also zero, unless ipxStart() hasn't yet been called. * TRUE: A packet has been received. The sending address has been copied to ipxAddr and "error" has been set accordingly. If "error" is set to ipxeNOERR (zero) or ipxeSOCKETNOTOPEN, a packet has been copied to your buffer and "pktSize" has been set to the number of data bytes received. If "error" has some other nonzero value, no packet data has been copied and "pktSize" is set to zero. Return values for "error:" * ipxeNOERR (FALSE): A packet was received and copied to your buffer without any errors. * ipxeIPXNOTSTARTED: ipxStart() has not been called so no packets can be received. * ipxeRECVPKTTOOBIG: A packet was received but it was too big to fit in the buffer associated with the ECB (in other words, it was larger than IPXDATASIZE), so IPX threw it away. No data was copied to your buffer, but your IPXADDRFULL structure has been filled in with the sender's address. * ipxeRECVCANCEL: IPX reports that the receive event was canceled. No packet data was copied. The sender's address has been copied, but is probably meaningless in this case. This should never happen under normal circumstances. * ipxeSOCKETNOTOPEN: The packet was received okay and has been copied to your buffer, as well as the sender's address. While LANLIB was attempting to put the ECB back into service to receive more packets, IPX reported that the socket referenced by the ECB is not open. This should never happen under normal circumstances. If the size of your buffer isn't large enough to hold all the received data (this can only happen if your buffer is smaller than IPXDATASIZE), then as much data as would fit was copied (and no error will be returned). You can tell this has happened if the value of "pktSize" is greater than the value you passed as "dataSize." If IPXRECVCNT is 0, then this procedure will always indicate that no packets have been received. ipxRouteFind() -------------- Prototype: word ipxRouteFind(struct IPXADDRFULL far *network, word netCnt, word (*ipxWaitProc)(word netsFound), word far *netsFound); This is a complicated procedure which finds other network segments in the internetwork. It fills in a structure of IPXADDRFULLs with broadcast addresses for all the segments it finds, including the network segment the program is running on. See the earlier section "Dealing with Network Segments" for details on using this information. This procedure is not available in the shareware version of LANLIB. Parameters: * struct IPXADDRFULL far *network: A pointer to at least two IPXADDRFULL structures. It is suggested that you use the define IPXNETCNT from LANCFG.H when determining how big to make this structure (or how much memory to allocate for it), rather than using a fixed number. * word netCnt: The total number of IPXADDRFULLs pointed to by "network." It is suggested that you use the define IPXNETCNT rather than a fixed number. * word (*ipxWaitProc)(word netsFound): A pointer to a procedure that will be called repeatedly while the router-finding is taking place. This will be a near pointer in small code models and a far pointer in large code models. Since ipxRouteFind() might conceivably take quite a long time to do its work, this gives you a chance to display something on the screen to let the user know the program hasn't crashed and to allow an opportunity to abort the procedure, if need be. See the description for ipxWaitProc() for details. If this pointer is NULL, then no external procedure will be called. * word far *netsFound: A pointer to a word that will receive the number of network segments that were located. Return values: * ipxeNOERR (FALSE): The procedure completed without errors. "network" has been filled in with all known networks, and the total count has been placed in "netsFound." * TRUE (1): A send error occurred either at some point before ipxRouteFind() was called or while sending out diagnostic requests. The send error(s) are still waiting to be picked up via calls to ipxSendErr(). * ipxeNETOVERFLOW: The procedure aborted because it found at least one more network segment than would fit in the "network" structure that was passed to it. This is not really an "error" per se; you might purposefully wish to keep the number of networks your program will work with to a minimum to ensure fast response. * ipxeBADCOMMPARMS: "netCnt" is less than two, or one or more of the values IPXRECVCNT, IPXSENDCNT, or IPXDATASIZE passed to ipxStart() are too small to allow the procedure to run. See below for details. * ipxeNOFREESENDECB: While trying to send out a diagnostic request, ipxSendPkt() reported that there were no free send ECBs. If you get this error during testing, you should increase the value of IPXSENDCNT. * ipxeROUTEFINDABORT: The procedure was aborted because "ipxWaitProc()" returned TRUE. See below for details. * ipxeIPXNOTSTARTED: ipxStart() has not yet been called. * ipxeNOPATHFOUND: When ipxRouteFind() called ipxAddrImmed() to get the immediate address for a discovered network, ipxAddrImmed() returned this value. This shouldn't happen under normal circumstances. * ipxeRECVPKTTOOBIG: While receiving diagnostic replies, ipxRecvPkt() reported this error. See ipxRecvPkt() for more details. * ipxeRECVCANCEL: See explanation for ipxeRECVPKTTOOBIG above. * ipxeSOCKETNOTOPEN: See explanation for ipxeRECVPKTTOOBIG above. If the procedure returns with some value other than FALSE, the network information in the "network" structure and the "netCnt" variable will be accurate but not necessarily complete; the procedure might not have found all networks before it had to abort. If the value returned is ipxeBADCOMMPARMS or ipxeIPXNOTSTARTED, then "network" will contain no network information at all. ipxRouteFind() performs the following steps: * It calls ipxAddrLocal() to fill in the first IPXADDRFULL structure pointed to by "network" with the network address of the network that it is running on. Then it sets the node and immediate address fields of this first structure to all F's, making the address suitable for broadcasting. * It calls ipxSendChk() to make sure there are no send errors in the send queue. If there are, it aborts and returns to your program, leaving the send errors in the queue. * It calls ipxSendPkt() to send out a diagnostic request on the local network segment. * It calls ipxRecvPkt() repeatedly to get diagnostic replies. Packets from anything that routes packets to other segments (standalone routers or file servers) are examined for other network segments. Replies from other PCs are ignored. Non-diagnostic packets are also ignored (this is determined by examining the socket that the packet came from). The addresses of other networks discovered are saved, and ipxAddrImmed() is called for each to fill in the best immediate address. To avoid clogging the network with diagnostic replies, each node will wait for a period of time up to half a second before sending a diagnostic response, so this procedure will wait at least that long to give all nodes a chance to respond. It only checks the elapsed time when no replies are coming in, so the actual time used might be greater than half a second. * If a pointer to a procedure of type ipxWaitProc() was given, it is called at this point. * The cycle is repeated twice more, starting with the call to ipxSendChk(), to ensure that all routers are heard from and to allow enough time to receive responses from routers that might take longer than half a second to arrive. Therefore, about 1.5 seconds are spent analyzing the network segment from start to finish, and ipxWaitProc() will be called three times. * The entire 1.5 second three-cycle ordeal is repeated for each new segment that is discovered. It is possible that late replies from earlier diagnostic requests on other segments might arrive during this time; if so, they will be properly processed as well. This process continues until all segments have been discovered and analyzed or until a new segment is discovered and the structure for saving the segment information is full, whichever comes first. * After all discovered segments have been analyzed, the procedure waits one more full second to see if any more late diagnostic responses will arrive. If one or more such responses arrive, and they contain the addresses of one or more new network segments, then the 1.5 second analysis procedure is again run for those segments and the full second final wait will be repeated. Since ipxRouteFind() is basically a small LANLIB-using application unto itself, it has certain requirements that must be met for it to be used: IPXRECVCNT must be at least 30, IPXSENDCNT must be at least 2, and IPXDATASIZE must be at least 256. If these conditions aren't met, then ipxRouteFind() will return ipxeBADCOMMPARMS, no network segment data will be copied to "network," and "netsFound" will be zero. If a procedure was given as "ipxWaitProc()", then ipxRouteFind() will call it at the end of each send/receive cycle, approximately every half second. The procedure is called with one word-sized parameter, netsFound, which indicates the number of networks found so far. This number will not be incremented on every call to "ipxWaitProc()". If the ipxWaitProc() procedure returns FALSE, then router-finding continues; if it returns TRUE, then ipxRouteFind() will abort and return ipxeROUTEFINDABORT. See ipxWaitProc() for more details. You shouldn't have any "conversations" with other PCs going on when you call this procedure, because it will "eat" any and all packets that are received while it is running and throw away any that aren't diagnostic responses. It's okay to call this procedure more than once during the run of a program; for instance, it might need to be called a second time with a higher number for netCnt if a particular expected address was not found or ipxeNETOVERFLOW was returned. It is possible but unlikely that your program will receive a late diagnostic response at some point after ipxRouteFind() completes. You can check for this condition by examining the socket number in the sending address; diagnostic replies come from socket 0456h. If this happens consistently, let me know; it probably means that I need to tweak the code inside ipxRouteFind() to wait a little longer for replies to arrive. If a router does not respond to standard NetWare diagnostic requests, then this procedure won't recognize it and won't be able to access the networks it knows about. I am told that routers like this exist in some NetWare environments. Routers of this type are not supported by LANLIB. If a router claims to be attached to more than 32 networks, its information is ignored. Values higher than 32 probably indicate an error of some sort. Since it must take real time into account, ipxRouteFind() examines the word at 0040:006Ch in the BIOS data segment, which is the least significant word of the number of timer ticks that have elapsed since midnight. This procedure uses almost 1k of stack space for temporary variables, so you should ensure that this much is available. ipxSendChk() ------------ Prototype: word ipxSendChk(void); This procedure checks to see if any errors were encountered while trying to send packets, and therefore whether those packets are waiting around for you to pick them up. If there are unsent packets, you can pick them up with ipxSendErr(). This should be done periodically, because ECB/packet pairs that were used for unsuccessful sends are unusable until retrieved with ipxSendErr(). Return values: * FALSE: No undelivered packets are waiting. * TRUE: At least one undelivered packet is waiting. * ipxeIPXNOTSTARTED: ipxStart() hasn't been called; it isn't possible to check for send packet errors yet. If IPXSENDCNT is 0, then this procedure will always indicate that no send errors are waiting. ipxSendErr() ------------ Prototype: word ipxSendErr(void far *data, word dataSize, struct IPXADDRFULL far *ipxAddr, word far *pktSize, word far *error); This procedure checks for IPX send errors. It is unlikely that you'll get any, but if you do, this routine in effect gives your packet back to you so you can retry the send or take other steps as necessary. It should be called every now and then even if you don't want to process send errors, because a send ECB/packet pair that had an error is taken out of service indefinitely until you call ipxSendErr() to free it up. If all send ECBs are taken out of service due to errors, then you won't be able to send any more data. Parameters: * void far *data: A pointer to your buffer that will receive the packet that couldn't be sent (if an error is reported). * word dataSize: The size of your buffer, in bytes. * struct IPXADDRFULL far *ipxAddr: A structure to receive the address of the PC that the packet should have been sent to. * word far *pktSize: A pointer to a word to receive the size of the data that is being returned. * word far *error: A pointer to a word to receive the error value associated with the packet. Return values: * FALSE: No undelivered packets are waiting. "error" will be set to ipxeNOERR (zero) unless ipxStart() hasn't been called. * TRUE: An undelivered packet has been copied to your buffer, the total size has been set in "pktSize," and the intended recipient's address has been copied to "ipxAddr." The ECB with the error is returned to service, ready to be used for the next send request. Return values for "error:" * ipxeNOERR (FALSE): There are no undelivered packets to be processed. * ipxeIPXNOTSTARTED: ipxStart() has not been called. * ipxeSENDBADROUTE: The packet was undeliverable. This can happen if you send a packet to yourself (broadcasts count as "sending a packet to yourself") and there are no free receive ECBs. If the packet was to another PC, then IPX could not find a route to the destination node; this probably indicates a problem with the immediate address. * ipxeSENDCANCEL: IPX reported that the send event was canceled. This shouldn't happen under normal circumstances. * ipxeSENDPKTBAD: The packet was "malformed," to use Novell's term. It was either too short, too long, or the fragment count was wrong. LANLIB takes care of all this, so this error should never be returned under normal circumstances. * ipxeSENDNETFAIL: IPX reports that the local network hardware or the network itself has failed. If IPXSENDCNT is 0, then this procedure will always indicate that no send errors are waiting. ipxSendPkt() ------------ Prototype: word ipxSendPkt(void far *data, word dataSize, struct IPXADDRFULL far *ipxAddr); This procedure posts a send request with IPX. No error associated with the send will be returned, because ipxSendPkt() will return before IPX has actually sent the packet. Parameters: * void far *data: A pointer to your buffer filled with packet data to be sent. * word dataSize: The number of bytes in your buffer to be sent. This does not have to be the same as the size of the buffer, if you want to send fewer bytes. * struct IPXADDRFULL far *ipxAddr: The full IPX address of the PC to send the packet to. If you set the node address to FFFFFFFFFFFFh, the packet will be sent to all nodes on the selected network segment. Return values: * ipxeNOERR (FALSE): The request was posted without errors. This DOES NOT mean that the packet has been sent. * ipxeIPXNOTSTARTED: ipxStart() has not been called. * ipxeNOFREESENDECB: All send ECBs are currently in use, waiting to be sent by IPX (or else IPXSENDCNT is set to 0, which shouldn't be true if your program ever sends any packets). You can retry the send at some point later in time. If you get this error during testing, you can increase the number of send ECBs by setting the define IPXSENDCNT in LANCFG.H to a higher value. If the value of "dataSize" given is bigger than the value of IPXDATASIZE, then you've given more data than the procedure can send; the number of bytes sent will be truncated to IPXDATASIZE and no error will be returned. The procedure ipxSendErr() should be called occasionally to check for send errors. If all packets are sent successfully, then ipxSendErr() will return nothing, but keep in mind that this does NOT mean that the packet was successfully received; it could have been lost in transit. IPX does not guarantee that all packets sent will be received. IPX allows you to "send packets to yourself," so to speak. You could call ipxSendPkt() to send some data, setting "ipxAddr" to your own IPX address, and then receive that same packet with ipxRecvPkt(). IPX is smart enough to figure out that the packet doesn't have to go out onto the network and merely copies it in memory. This can be useful for debugging. If a program "broadcasts" a packet to all addresses on its own network segment by sending to node address FFFFFFFFFFFFh, then the program will receive a copy of its own sent packet. ipxStart() ---------- Prototype: word ipxStart(word recvCnt, word sendCnt, word dataSize, word socket, void far *memPtr, word memSize); Call this as the very first IPX-related routine in your program. No other IPX functions except ipxLibVer() may be used until ipxStart() has been called. It performs the following functions: * It checks all parameters for validity except "socket." It also checks to make sure that the amount of memory given is large enough to hold everything. * It checks to make sure that the IPX driver is loaded. If not, it returns with an error code. If IPX is available, it saves the entry point used to make far calls to the IPX driver, which is needed by all other LANLIB routines except ipxLibVer(). * It opens the IPX socket number given as the parameter "socket" for sending and receiving packets. * It registers all receive ECBs and their associated packet buffers with IPX, making them available to receive incoming data packets. Parameters: * word recvCnt: The number of receive ECB/buffer pairs to use. Legal values are 0 to 250. The minimum is 30 if ipxRouteFind() will be used. It is suggested that you use the define IPXRECVCNT from LANCFG.H rather than passing a number directly. Each receive ECB/buffer pair will require IPXCOMMSIZE bytes (a define in LANLIB.H). * word sendCnt: The number of send ECB/buffer pairs to use. Legal values are 0 to 250. The minimum is 2 if ipxRouteFind() will be used. It is suggested that you use the define IPXSENDCNT from LANCFG.H rather than passing a number directly. Each send ECB/buffer pair will require IPXCOMMSIZE bytes. * dataSize: The maximum number of data bytes per packet. Legal values are 0 to 546. The minimum is 256 if ipxRouteFind() will be used. It is suggested that you use the define IPXDATASIZE in LANCFG.H rather than passing a number directly. * void far *memPtr: This is a far pointer to an allocated block of memory that LANLIB will use for ECBs, buffers, queues, and so on. This can be memory allocated from the near heap with malloc() or from the far heap with farmalloc(), memory obtained with a direct call to DOS, a pointer to a block of memory in an initialized or uninitialized data segment, or just about anything else, just so long as it's big enough to hold everything (see below). It doesn't have to be set to all zeroes; LANLIB does that itself. The memory block must be less than 64k. * word memSize: The size of the memory block pointed to by memPtr, in bytes. This value can be calculated by using the define IPXMEMSIZE located in LANLIB.H. Return values: * ipxeNOERR (FALSE): All operations were completed without errors. * ipxeNOIPX: The IPX driver TSR (or TSRs) are not loaded. IPX communication is not possible. * ipxeIPXSTARTED: ipxStart() has already been called. It should not be called twice. * ipxeBADCOMMPARMS: One of the communication parameters given was set to an illegal value. All are checked for validity except "socket." This value will be returned if "memPtr" is NULL. * ipxeMEMTOOSMALL: The value of memSize indicates that the memory block given is not big enough to hold all the communication data (see below). * ipxeMEMABOVE64K: The amount of memory required for all requested ECBs and buffers would exceed 64k. This is not allowed (see below). * ipxeSOCKETTABLEFULL: The selected socket cannot be opened because the IPX driver's socket table is full. IPX defaults to allowing up to 20 open sockets. To increase this amount, add the line "IPX SOCKETS = xx" to the NET.CFG file, where "xx" is the number of sockets required. Sockets use some of the PC's memory, so don't increase the number any higher than necessary. * ipxeSOCKETOPEN: The requested socket was already open; ipxStart() did not complete. Some other program is probably using the socket. This can also happen if the user "crashes out" of your program, so ipxStop() was never called and the socket was left open, and then the user tries to start it again. In this case, a reboot will fix the trouble. * ipxeSOCKETNOTOPEN: While setting up the listen ECBs to receive incoming packets, IPX reported that the selected socket was not open, despite the fact that the socket was opened earlier with no error. It is extremely unlikely that this error will be reported under normal circumstances. The formula for determining how much memory to pass to ipxStart() is as follows (and is also defined as IPXMEMSIZE in LANLIB.H): (IPXRECVCNT + IPXSENDCNT) * IPXCOMMSIZE This is the total number of send and receive ECB/buffer pairs times the amount of memory for each, IPXCOMMSIZE. This is the total overhead bytes for each plus IPXDATASIZE. IPXCOMMSIZE is defined in LANLIB.H. The user must ensure that the total amount of memory needed is less than 64k. If it's greater, reduce the size of one or all of IPXRECVCNT, IPXSENDCNT, or IPXDATASIZE, defined in LANCFG.H, until the required size is less than 64k. There is no point in passing more memory than the amount given by this formula. LANLIB will not use any excess memory. ipxStop() --------- Prototype: word ipxStop(void); Call this as the last IPX function in your program. If you end your program without calling it, your computer may well crash later on when IPX tries to store an incoming packet in a memory buffer that no longer belongs to you. ipxStop() performs the following function: * It closes the IPX socket passed to ipxStart() as the parameter "socket." This has the effect of canceling any pending send requests and all receive ECBs. The IPX close socket function never returns an error, so no form of IPX error will be passed to your program. Return values: * ipxeNOERR (FALSE): The procedure completed without errors. * ipxeIPXNOTSTARTED: ipxStart() was never called, so there is nothing to stop. If memory was allocated for ipxStart() (as opposed to passing a pointer to an area of a data segment), then the memory should be freed after the call to ipxStop(). ipxWaitProc() ------------- Prototype: word ipxWaitProc(word netsFound); This is not a procedure in LANLIB, but rather one that can exist in your program. Since ipxRouteFind() takes about 1.5 seconds to process each network segment, and an internetwork might well contain 20 or more segments, it would be easy for a user of your program to assume that it had crashed and reboot the PC. To get around this problem, ipxRouteFind() takes as one of its parameters a pointer to a procedure of this type that it will call approximately every half second. Your procedure will receive one word-sized variable, netsFound, which will be the number of network segments discovered so far. This number will never be less than one, since the network segment that your program is running on is counted, and it is "discovered" before your procedure is called the first time. This value might be two or higher on the very first call to your procedure since one diagnostic cycle will have been completed at that point. Your procedure must return one word-sized variable that indicates whether or not ipxRouteFind() should continue. If your procedure returns FALSE (0), then ipxRouteFind() will continue. If it returns any other value then ipxRouteFind() will abort. This procedure is not subject to the restrictions imposed on interrupt service routines. At the time it is called the PC is in a stable state. The procedure can call other procedures in the program, collect keyboard or mouse input, call DOS and perform file I/O if need be, display information on the screen (perhaps the running total of networks it was called with), and take as long as it likes to complete; any amount of time up to a second or so is reasonable. It should not call any LANLIB procedures, however (or call other procedures that call LANLIB); ipxRouteFind() is using LANLIB at the moment; LANLIB calls should wait until after ipxRouteFind() has finished. This procedure can be written in any language, but it must follow the C calling convention. Its lone parameter will be on the stack at the time it is called, it must put its return value in the AX register, and ipxRouteFind() will clean up the stack afterwards. It doesn't have to save any registers except SP, BP, SI, DI, DS, and SS. This is all according to the standard C calling convention. ipxRouteFind() will access it with a near call in small code models and with a far call in large code models, so it must use the default return type (near or far) for the current memory model. The LANLIB demo program LANTEST contains a procedure of this type, called routeWait(), in the file NETWORK.C. ****************************************************************************** * * *** LANUTIL Routines *** * * ****************************************************************************** Programs using LANLIB will almost certainly have to keep track of at least a few other PCs out on the network. This requires keeping track of those PC's IPX addresses, which are best kept in IPXADDRFULL structures. You might have to copy one address to another, compare two addresses to see if they're the same or to sort a list, or print an address to the screen. Since an IPXADDRFULL structure is large and complicated, these sorts of tasks are made more difficult. This is exactly the problem I found myself up against when I wrote LANTEST. The LANUTIL routines are the solution I came up with. The LANUTIL routines are written in C and the source code is included in the file LANUTIL.C. You can use or modify this code as you see fit. ipxAddrBrd() ------------ Prototype: struct IPXADDRFULL *ipxAddrBrd(struct IPXADDRFULL *ipxAddr); This procedure sets the node address and immediate address fields in an IPXADDR structure to FFFFFFFFFFFFh, which makes the address suitable for broadcasting packets to all PCs on the local network segment. It does nothing at all to the network and socket fields, so those values should already be set before performing this call. A convenient way to set up an IPXADDRFULL structure suitable for broadcasting packets on your local segment is to first get your local address from the LANLIB procedure ipxAddrLocal(), then pass that address to ipxAddrBrd() to set the node and immediate address fields. Note that if you broadcast a packet to all PCs on your network segment, you yourself will also get a copy of that packet. This procedure returns a pointer to the IPXADDRFULL structure. ipxAddrCmp() ------------ Prototype: int ipxAddrCmp(struct IPXADDRFULL *ipxAddr1, struct IPXADDRFULL *ipxAddr2) This procedure compares the network, node, and socket numbers of two IPXADDRFULL structures. It can be used to sort addresses into numerical order or simply to determine if two addresses are identical. It returns -1 if the first address is less than the second, 0 if the addresses are the same, or 1 if the first address is greater than the second. ipxAddrCpy() ------------ Prototype: struct IPXADDRFULL *ipxAddrCpy(struct IPXADDRFULL *ipxAddrDst, struct IPXADDRFULL *ipxAddrSrc) This procedure copies the entire contents of one IPXADDRFULL structure to another. It returns a pointer to the destination address. ipxAddrSocket() --------------- Prototype: struct IPXADDRFULL *ipxAddrSocket(struct IPXADDRFULL *ipxAddr, word socket) This procedure accepts a pointer to an IPXADDRFULL structure and a socket number in normal Intel low-high format. It flips the socket number to high-low format, as required by IPX, and puts it in the structure. It returns a pointer to the structure. ipxAddrStr() ------------ Prototype: char *ipxAddrStr(char *str, struct IPXADDRFULL *ipxAddr) This procedure creates a string representation of the network and node address in an IPXADDRFULL structure in the string pointed to by "str" in the format xxxxxxxx:yyyyyyyyyyyy, where the x's are the network number and the y's are the node number. The string given as "str" must contain at least 22 bytes. The network and node are all that's needed to uniquely identify one PC from any other, so many of NetWare's own utilites use this format for displaying addresses. It returns a pointer to the string. ipxAddrStrLong() ---------------- Prototype: char *ipxAddrStrLong(char *str, struct IPXADDRFULL *ipxAddr) This procedure creates a string representation of all four components of the IPXADDRFULL structure, all separated by colons. The string given as "str" must contain at least 40 bytes. This is probably not too useful for production programs, but it sometimes comes in handy for debugging. It returns a pointer to the string. ipxByteSwap() ------------- Prototype: word ipxByteSwap(word socket) This procedure takes a word parameter (typically a socket number), swaps its high byte with its low byte, and returns the modified value. This will convert a socket number in low-high Intel format to high-low Motorola format, or vice versa. This can be useful because IPX requires that the socket field of IPXADDRFULLs be maintained in high-low (Motorola) format. ****************************************************************************** * * *** The Future of LANLIB *** * * ****************************************************************************** I am planning to do a 32-bit version of LANLIB compatible with the Watcom 32-bit compiler. I expect to eventually do a NetBIOS library as well, devise a common API layer that both the NetBIOS version and LANLIB will share, and figure out a way that a program can load one or the other but not both at runtime. Eventually I might also round out the situation with a serial communication library that uses the same API and can be loaded in place of one of the network drivers. I may also do a Windows version of LANLIB, and also the NetBIOS library. If you have an interest in any of these potential projects, please let me know. User interest will play a big part in whether or not I get around to them. If you would like to do something with LANLIB that I haven't taken into account, such as use it with a different compiler, or with overlays, or whatever, let me know. If it's feasible, I can probably be talked into it. Allen Brunson 6500 East 21st #2 Wichita, Kansas 67206 U.S.A. CompuServe: 74464,3472 Internet: 74464.3472@compuserve.com ****************************************************************************** * * *** Special Thanks *** * * ****************************************************************************** Like any good piece of software, LANLIB was not created in a vacuum. I had a lot of help and feedback from many people. Two in particular stand out and deserve special mention: Bart Stewart. He performed countless tests on my behalf using his company's huge NetWare internetwork and various buggy versions of LANTEST.EXE. His knowledge of and experience with IPX diagnostics directly shaped the architecture of LANLIB. Doug Goldner. Unless somebody else gets into an EXTREME hurry, it looks like he will produce the first ever LANLIB-using program, a text-based adventure game called Multi-Venture that uses a client-server architecture. He figured out tricks to using LANLIB that didn't even occur to me, and in the process helped validate the whole LANLIB concept. You can contact Doug about his game at his CIS address, 76702,1257. ****************************************************************************** * * *** Release History *** * * ****************************************************************************** Version 1.00, June 30, 1994 First public general release. Changes: * A little legalese, courtesy of my mom the lawyer, is about all that's new. Version 0.40, June 23, 1994 Fourth public beta release. Changes: * Novell's legal department wouldn't let me use their trademark in my product's name, so I can't call it IPXLIB; now it's LANLIB, and all the files and so on were renamed. * LANTEST (formerly IPXTEST) can now write its network info to a file. This is useful (to me, at least) for debugging ipxRouteFind() if it fails to find all network segments on a given internetwork. * I added the procedure ipxAddrImmed(), which calls IPX to get the preferred immediate address for a given network address, and one new error value for it, ipxeNOPATHFOUND. ipxRouteFind() and LANTEST were both upgraded to use it. * I added a new error value, ipxeMEMABOVE64K, which ipxStart() will now return if the amount of memory required is above 64k (an error). Version 0.30, June 10, 1994 Third public beta release. Changes: * IPX.H was renamed IPXLIB.H, IPX.ASM was renamed IPXLIB.ASM, and the .LIB files were also appropriately renamed. * The define IPXMEMSIZE was added to IPXLIB.H to calculate the memory size needed to pass to ipxStart(). * IPXLIB.INC and IPXCFG.INC, the assembler versions of IPXLIB.H and IPXCFG.H, were added for programmers wishing to use IPXLIB with assembler programs. * I finally finished ipxRouteFind(), the procedure that finds network segments, and added one more IPXLIB error value for it, ipxeROUTEFINDABORT. I got rid of the never-used define IPXHOPS and replaced it with the new IPXNETCNT, given as a parameter to ipxRouteFind(). IPXTEST was upgraded to use the new procedure. "Dealing with Network Segments" was added to the documentation. * ipxeBADCOMMPARMS now also applies to ipxRouteFind(), which will return this value if the communication parameters aren't to its liking. * I added two new procedures in IPXUTIL.C for dealing with IPXADDRFULLs, ipxAddrSocket() and ipxByteSwap(). Version 0.20, June 1, 1994 Second public beta release. Changes: * The code in IPX.ASM was streamlined considerably, eliminating many small bugs. * ipxStart() was changed from taking no parameters to taking all communication parameters, including a far pointer to memory to use for ECBs, buffers, and so on. IPXTEST was modified so that if DEBUG is defined it passes a pointer to an IPXDATA structure to use for communication memory; it will allocate memory from the heap instead if DEBUG is not defined. * IPXDATA.C was eliminated; all communication data is now passed as variables to ipxStart(), including a pointer to memory that is used for the data that formerly was in this file. * Code was added to keep track of the maximum number of ECBs that have been used. IPXTEST was upgraded to display or reset this information and to send it to other IPXTEST users. * Two new IPXLIB error codes were added, ipxeBADCOMMPARMS and ipxeMEMTOOSMALL, which ipxStart() can return if the communication parameters given are wrong or if the size of the memory block given isn't big enough to hold everything, respectively. This shifted the values of all the other error codes. * The ECB pointer field in the IPXEVENT structure was changed from a far (4-byte) to a near (2-byte) pointer. * IPXLIB was tested with Microsoft C++ version 8.0 and proven to work in all memory models except Tiny. IPXTEST was modified to work with Microsoft C as well, although a few minor things didn't get ported, like the variable-length wait before sending a ping response and screen scrolling, because there weren't functions in the Microsoft run-time libraries equivalent to the ones I used in Borland C. * "Flurry mode," that is to say, sending as many packets as time will allow, was added to IPXTEST, so as to stress-test IPXLIB. * IPXTEST can now be "remote controlled:" It attempts to interpret the text of broadcast messages and directed messages as commands. * Several extra IPX programming considerations were added to the IPXTEST documentation. Version 0.10, May 27, 1994 First public beta release.