home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / c / lanlib / lanlib.txt < prev    next >
Encoding:
Text File  |  1994-06-30  |  78.8 KB  |  1,679 lines

  1. ; LANLIB.TXT -- Documentation for LANLIB
  2. ; Copyright (c) 1994 by Allen Brunson  version 1.00  06/30/94
  3.  
  4.  
  5. ******************************************************************************
  6. *                                                                            *
  7. ***  Trademarks                                                            ***
  8. *                                                                            *
  9. ******************************************************************************
  10.  
  11. Borland is a registered trademark of Borland International, Inc.
  12.  
  13. Microsoft and MS-DOS are registered trademarks and Windows is a trademark
  14. of Microsoft Corporation.
  15.  
  16. Netware and Novell are registered trademarks and IPX is a trademark
  17. of Novell, Inc.
  18.  
  19.  
  20.  
  21. ******************************************************************************
  22. *                                                                            *
  23. ***  Introduction                                                          ***
  24. *                                                                            *
  25. ******************************************************************************
  26.  
  27. LANLIB is a library of routines written in assembler for communication
  28. amongst multiple PCs using the IPX protocol, the low-level language spoken
  29. by Novell's NetWare.  It is designed to be called from C, but if you know
  30. what you're doing, you can get it to work with assembler, C++, Pascal, or
  31. any other language that can be made to support the C calling convention and
  32. works with standard object file formats.  Since LANLIB is written in
  33. assembler, its impact on the size of your program is minimal; it has only
  34. 2.8k of code and requires about 12k of memory for communication buffers.
  35.  
  36. IPX is a fast and very low-level protocol, designed for maximum speed.  It
  37. does not guarantee delivery, but Novell claims IPX packets properly arrive
  38. at their destinations about 95 percent of the time.
  39.  
  40. IPX can be quite cumbersome to use.  Given its orientation, a great many
  41. details of NetWare networks must be known by the programmer to use it
  42. properly.  This library takes care of almost all of those details, allowing
  43. you to concentrate on your program's main function rather than worrying
  44. about IPX specifics.
  45.  
  46. This library is geared towards the needs of smaller projects, where perhaps
  47. up to 20 or so PCs will be exchanging data.  Larger projects would probably
  48. be best served if the programmer were to learn how to make IPX calls
  49. directly or by some other product.
  50.  
  51. This library does not offer any NetWare-related services, such as logging in,
  52. logging out, copying files, getting lists of logged-on users, and so on.
  53. Its only purpose is to allow programs running on multiple PCs to share data.
  54.  
  55. This document covers issues specific to using LANLIB.  It assumes that you
  56. are familiar with NetWare and IPX concepts.  It would be a good idea to
  57. read NETWORK.TXT before tackling this file.
  58.  
  59. The file LANTEST.TXT explains the LANLIB demo program, LANTEST.  LANTEST
  60. uses every LANLIB routine, so it is a good reference for implementation
  61. details.
  62.  
  63.  
  64. Shareware Version Restrictions
  65. ------------------------------
  66.  
  67. The shareware version of LANLIB does everything that the registered version
  68. does, with one exception: the procedure ipxRouteFind() has been removed,
  69. so the shareware version is limited to only one network segment.
  70.  
  71. The shareware version is provided for evaluation purposes only.  You are
  72. NOT free to distribute programs you create with it.
  73.  
  74.  
  75.  
  76. ******************************************************************************
  77. *                                                                            *
  78. ***  Adding LANLIB To Your Program                                         ***
  79. *                                                                            *
  80. ******************************************************************************
  81.  
  82. LANLIB has been tested with both Microsoft and Borland C++ compilers.  One
  83. small snag is that the Microsoft C++ compiler won't be able to use the Tiny
  84. model version of LANLIB; its linker reports that far segment accesses are not
  85. allowed in that model.  Other compilers will probably work if they can deal
  86. with standard object files.
  87.  
  88. LANLIB's use is limited to real-mode DOS executables.  I am working on a
  89. version for the Watcom 32-bit compiler, but at this writing I don't have a
  90. release date.
  91.  
  92. Novell's documented method for determining the presence of IPX requires the
  93. use of the DOS multiplex interrupt, which was introduced with DOS version
  94. 3.0.  Therefore, LANLIB will not work with any DOS version earlier than 3.0.
  95.  
  96. Special note for users of Microsoft compilers: Microsoft C defaults to
  97. two-byte (one word) structure member alignment.  This will NOT WORK with
  98. LANLIB, which uses one-byte aligned structures.  (It HAS to; IPX itself
  99. uses one-byte aligned structures.)  You must set the compiler to one-byte
  100. structure alignment for it to work with LANLIB.
  101.  
  102. LANLIB is contained in one of four .LIB files, depending on your chosen
  103. memory model:
  104.  
  105.   LANLIBT.LIB   Tiny model
  106.  LANLIBSC.LIB   Small and Compact models
  107.  LANLIBML.LIB   Medium and Large models
  108.   LANLIBH.LIB   Huge model
  109.  
  110. Include one of these .LIB files in your project.
  111.  
  112. LANLIB always uses far pointers for passed data parameters, so there's no
  113. distinction between Small and Compact (near code calls) or between Medium and
  114. Large (far code calls).  The Tiny model code never makes direct references to
  115. the data segment, so a program built with LANLIBT.LIB can be turned into a
  116. .COM file.  The Huge memory model has special considerations for the data
  117. segment register, so it requires its own .LIB file.
  118.  
  119. Include the file LANLIB.H in any module that will be calling the LANLIB
  120. routines.  It is important that you follow this rule: LANLIB routines all
  121. take far pointers to data structures, and pointers in the small data
  122. memory models are by default near, so messy crashes will result if you don't
  123. perform this step.
  124.  
  125. Defines in LANCFG.H are used to set the number of send and receive packet
  126. buffers, the number of bytes per packet, the socket number, and the number
  127. of networks to allow.  Make a copy of this file for each program that will
  128. use LANLIB and then include LANCFG.H in each source file that will call
  129. LANLIB routines.  See a later section called "Configuring LANLIB With Defines
  130. in LANCFG.H" for more details.
  131.  
  132. The routines in LANUTIL.C can be used to work with IPXADDRFULL structures.
  133. While I was writing the demo program I had to manage the addresses of many
  134. PCs; each requires an IPXADDRFULL structure.  Since this is a large
  135. hunk of data with several unwieldy fields, I wrote routines to copy one
  136. address to another, convert an address to a string, compare two addresses for
  137. equality, and so on.  LANUTIL.C is the result.  See a later section in this
  138. file for reference.
  139.  
  140.  
  141.  
  142. ******************************************************************************
  143. *                                                                            *
  144. ***  Calling LANLIB from Assembler                                         ***
  145. *                                                                            *
  146. ******************************************************************************
  147.  
  148. While LANLIB was being beta-tested, I was contacted by a programmer who was
  149. interested in using it with a pure assembler program.  This is entirely
  150. possible; LANLIB is written in assembler itself.  I've included the file
  151. LANLIB.INC, which contains the same defines as LANLIB.H but in assembler
  152. format, and LANCFG.INC, which duplicates LANCFG.H.
  153.  
  154. All the LANLIB procedures use the C calling convention so you must do the
  155. same when calling them from assembler.  Each procedure's arguments are
  156. pushed on the stack in right-to-left order; after the call, you must get rid
  157. of them by POPing them off (or by adding a value to SP, the stack pointer).
  158. If a procedure returns a value, it will be in AX on return (this is standard
  159. C procedure).  Since C compilers don't require procedures to save many
  160. registers, the LANLIB procedures trash most of them.  All registers except
  161. BP, SP, SI, DI, SS, and DS might be trashed.
  162.  
  163. You won't be able to use the utility routines in LANUTIL.C in an assembler
  164. program, of course.  But their use is optional; you may discover you don't
  165. need them; and if you do, they are all quite simple and easy to port to
  166. assembler.
  167.  
  168.  
  169.  
  170. ******************************************************************************
  171. *                                                                            *
  172. ***  An Overview Of LANLIB Structures                                      ***
  173. *                                                                            *
  174. ******************************************************************************
  175.  
  176. You don't need to know a whole lot about IPX structures to use LANLIB; it
  177. pretty much takes care of the details for you.  However, a general overview
  178. of the seven structures defined in LANLIB.H (and LANLIB.INC) seems
  179. appropriate.
  180.  
  181. struct IPXADDR: This is the network, node, and socket number for a PC.  It
  182. is enough to uniquely identify a process on a PC, but not enough info to
  183. be able to send a packet to any process on any PC anywhere on an
  184. internetwork.  Note that the socket field is high-low (Motorola) format.
  185. This structure is defined only for inclusion in the IPXPKTHDR structure.
  186.  
  187. struct IPXADDRFULL: This is a superset of the IPXADDR structure, adding an
  188. immediate address field.  Therefore it contains enough address info to send
  189. a packet anywhere.  I kind of "made up" this structure; nowhere in "official"
  190. IPX do you find all four of these fields grouped together; however it seems
  191. quite convenient for storing the addresses of other PCs you wish to
  192. communicate with.  LANTEST uses a group of these structures to keep track
  193. of all other LANTEST users; it is assumed that LANLIB users will employ a
  194. similar scheme.  Keep in mind that the socket field MUST be maintained in
  195. high-low byte order or sends and receives will not complete properly.
  196. Routines for manipulating IPXADDRFULLs are given in LANUTIL.C.
  197.  
  198. struct IPXDIAG: This is the structure of the data portion of the IPX
  199. diagnostic packet.  It is used by ipxRouteFind() to locate other network
  200. segments.
  201.  
  202. struct IPXDIAGREPLY: This is the format of the data portion of IPX diagnostic
  203. reply packets received in response to diagnostic requests; again, it is used
  204. by ipxRouteFind().
  205.  
  206. struct IPXEVENT: This is another structure I "made up."  LANLIB contains
  207. two ESRs (Event Service Routines), one which IPX calls when a send is
  208. completed, the other when a receive is completed.  Each of these ESRs
  209. maintains a queue of events that it has been notified of (except that the
  210. send ESR simply throws away events if the send completed without errors).
  211. Each event is stored in a queue of IPXEVENT structures.  These queues are
  212. maintained and processed entirely by internal LANLIB functions.
  213.  
  214. struct IPXPKTHDR: This is the 30-byte packet header that all IPX packets
  215. must have.  You don't need to directly concern yourself with it; LANLIB
  216. will fill out the fields in IPX packet headers where necessary.
  217.  
  218. struct ECB: This is the standard IPX Event Control Block.  It contains
  219. pointers to two "fragments," the packet header and the packet data.  An
  220. ECB can actually have fields for any number of "fragments," but LANLIB
  221. always uses two, one for the header and one for the data.  Again, LANLIB
  222. will take care of filling out ECB fields, so you don't have to worry about
  223. them.
  224.  
  225.  
  226.  
  227. ******************************************************************************
  228. *                                                                            *
  229. ***  Configuring LANLIB with Defines In LANCFG.H                           ***
  230. *                                                                            *
  231. ******************************************************************************
  232.  
  233. LANLIB is tailored to the needs of your program by setting the defines in
  234. LANCFG.H (or LANCFG.INC for assembly programmers).  In this way, you
  235. determine how many ECB/packet pairs are available for sending and receiving,
  236. the size of the packets, the socket number, and the maximum number of network
  237. segments allowed.  (These defines are then used as parameters to ipxStart()
  238. and ipxRouteFind(), described below.)  You will also indirectly be setting
  239. how much memory the communication data will take.
  240.  
  241. Set IPXSOCKET to the socket number you want your program to use.  This
  242. value will be passed as a parameter to ipxStart().  Novell states that
  243. "dynamic" socket numbers, that is, ones not officially reserved, start at
  244. 4000h and end at 7FFFh.  The default socket number is 51E7h, but you should
  245. open up the file and change it right now, because everybody else who uses
  246. LANLIB will also be getting that as the default, and two programs running on
  247. the same network with the same socket number will bump heads.  See the file
  248. NETWORK.TXT for more information on socket numbers.
  249.  
  250. Set IPXNETCNT to the maximum number of network segments you will want LANLIB
  251. to be aware of.  The default is 10.  Most NetWare networks have six or fewer
  252. segments.  Setting it to higher numbers means that networks further away
  253. will be found, but communicating with PCs farther away will take longer and
  254. will require a bigger structure for managing network segment addresses.
  255. The shareware version of LANLIB is effectively limited to 1 regardless of
  256. what you set this value to.  LANLIB imposes no upper limit on this value,
  257. but generally speaking, setting it higher than 300 seems pointless.
  258.  
  259. Set IPXRECVCNT to the total number of ECB/packet pairs you wish to make
  260. available for receiving incoming packets.  The default is 30.  The minimum
  261. value is 0; the maximum is 250.  If you are planning to use ipxRouteFind()
  262. to locate other network segments, then the minimum is 30.  It is passed as
  263. a parameter to ipxStart() and is used to set the number of receive ECBs,
  264. packet headers, packet data buffers, and the receive event queue size.  You
  265. can make your program completely "deaf" to incoming packets by setting this
  266. value to 0.  If your program will only receive packets infrequently and
  267. you're prepared to retrieve them quickly, you might get by with setting this
  268. value to 1.  If you anticipate receiving lots of data and your program's
  269. main loop might not get around to processing incoming packets for several
  270. seconds, set this value to a high number, perhaps as high as 200.  It's far
  271. better to set this number too high than too low, because if a data packet
  272. arrives and all the ECBs are already full, IPX will simply throw it away
  273. without so much as an error.  Each ECB/packet pair requires one ECB
  274. (48 bytes), one packet header (30 bytes), one entry in the receive event
  275. queue (4 bytes), and one packet buffer, the size of which is set by
  276. IPXDATASIZE (see below).
  277.  
  278. Set IPXSENDCNT to the total number of ECB/packet pairs you wish to use for
  279. sending packets.  The default is 8.  The minimum value is 0; the maximum is
  280. 250.  If you're going to use ipxRouteFind(), the minimum is 2.  It is passed
  281. as a parameter to ipxStart().  It is used to set the number of send ECBs,
  282. send packet headers, send packet buffers, and the size of the send event
  283. queue.  You can make your program listen-only by setting this value to 0.
  284. Generally this number can be lower than IPXRECVCNT because most network
  285. programs send less data than they receive and send requests are usually
  286. carried out very quickly.  Even if all send ECBs are in use when you want to
  287. do another send, you'll simply get an error; you're free to retry the send a
  288. few milliseconds later.  Setting this value to 1 is plenty enough for
  289. programs with light send needs.  Even if your program does nothing but sit in
  290. a loop sending packets, you probably shouldn't need more than 20.  Each send
  291. ECB/packet pair takes the same number of bytes as a receive ECB/packet pair
  292. (see above).
  293.  
  294. Set IPXDATASIZE to the number of bytes of data you want to be able to send
  295. (and receive) in each packet.  Don't take the 30-byte IPX packet header
  296. into account here; this number is only for data bytes.  The default is 256.
  297. The minimum size is 0; the maximum is 546.  If you're going to use
  298. ipxRouteFind(), the minimum is 256.  It's entirely possible to send packets
  299. with zero data bytes; the receiver will know nothing more than the sender's
  300. address, but in some contexts this might be enough.  If you'll be sending
  301. lots of little packets, set IPXDATASIZE to a small number; big streams of
  302. data would be better-served by large packet sizes (but this will require
  303. more memory).  It's possible to send packets that are smaller than
  304. IPXDATASIZE, but it's never possible to send one that's bigger than this
  305. value.  The amount of memory taken up by this setting depends on the values
  306. of IPXRECVCNT and IPXSENDCNT; each ECB/packet pair used for both sending and
  307. receiving will have one buffer of this size.
  308.  
  309.  
  310.  
  311. ******************************************************************************
  312. *                                                                            *
  313. ***  Dealing with Network Segments                                         ***
  314. *                                                                            *
  315. ******************************************************************************
  316.  
  317. Network segments involve some of the most difficult concepts of IPX
  318. programming, and therefore also some of the most difficult concepts in LANLIB
  319. programming.
  320.  
  321. There are two general approaches you can take: Operate only on one segment,
  322. or operate with many or all accessible segments.  Naturally there are
  323. advantages and disadvantages to each approach.
  324.  
  325. If ROUTE is not defined (in LANTEST.H), then LANTEST will be a single-segment
  326. program.  If ROUTE is defined, then it will function as a multiple-segment
  327. program (after ipxRouteFind() has been called, which is accomplished with
  328. the R command).  Look for the conditional compile directive "#ifdef ROUTE"
  329. which appears in several places in NETWORK.C to see what's different for each
  330. approach.
  331.  
  332.  
  333. The Single Segment Approach
  334. ---------------------------
  335.  
  336. Operating on only one segment is easiest, fastest, and simplest to manage,
  337. and the only mode available for LANLIB programs if you're using the
  338. shareware version.  There are no worries about finding other network
  339. segments.  Since no routers will be involved, you can rest assured that
  340. packets will arrive as quickly as possible.  Every IPX-aware game I've ever
  341. seen operates in this manner (excepting games in development using LANLIB, of
  342. course).  When you need to broadcast packets to find potential users in
  343. single segment mode, you merely call ipxAddrLocal() with a pointer to an
  344. IPXADDRFULL structure, then pass that structure to ipxAddrBrd() to set it
  345. up as a broadcast address, then pass that address to ipxSendPkt() for the
  346. broadcast.  You don't need to concern yourself further with the concept
  347. of network segments.
  348.  
  349.  
  350. The Multiple Segment Approach
  351. -----------------------------
  352.  
  353. Operating with multiple segments is more complicated to manage and
  354. potentially slower if more than a few routers are involved, but far more
  355. flexible, and also better in tune with the size and scope of today's
  356. networks.  I've installed and managed NetWare networks for many years now,
  357. and I can say for certain that networks with multiple segments are far more
  358. common than single-segment networks.  It doesn't seem particularly sporting
  359. to restrict users from interacting with each other via your program simply
  360. because their PCs are attached to different network segments.
  361.  
  362. The method for discovering network segments other than your own in NetWare
  363. environments is accomplished through "NetWare diagnostics."  It's an
  364. interesting bit of trivia that NetWare file servers, routers, and PCs
  365. running NetWare's shell TSRs keep quite a few statistics on their
  366. performance, and are willing to give up this information (via SPX
  367. diagnostics) to anyone on the network who requests it, with absolutely no
  368. security checks whatever.  You don't even have to be logged in to gather
  369. NetWare statistics.
  370.  
  371. Another use for the statistics functions is to gather network segment
  372. information.  When an IPX diagnostic request is broadcast on a network
  373. segment, PCs will respond with a simple list of "components" installed:
  374. IPX/SPX, shell, shell driver, and so on.  Routers will return this
  375. information as well, but will also give information about all network
  376. segments they are attached to.  Then the diagnostic request can be
  377. rebroadcast on these newly discovered segments, which will probably turn
  378. up more routers with information on more segments, and so on.  This method
  379. is used by ipxRouteFind() to locate network segments.
  380.  
  381. ipxRouteFind() is called with a structure of two or more IPXADDRFULLs.  (If
  382. you were only interested in knowing about one network segment, you wouldn't
  383. need ipxRouteFind().)  It sets up the first of these structures to be
  384. a broadcast address suitable for use on the local segment; it will have its
  385. node and immediate address fields set to FFFFFFFFFFFFh.  In other words, it
  386. will be set up exactly as you would set it up yourself in a single segment
  387. program with a call to ipxAddrLocal() and then ipxAddrBrd().
  388.  
  389. This first broadcast address is used to send a diagnostic request on the
  390. local segment.  PCs will respond with their diagnostic information, but they
  391. are ignored, and in fact subsequent diagnostic packets are filled with a list
  392. of "exclusion addresses," or nodes that should not respond to the request;
  393. all known PC addresses are added to this list.  ipxRouteFind() only cares
  394. about routers.
  395.  
  396. If there are routers on the segment, they will respond with more network
  397. segment numbers.  These segments are all added to the table of network
  398. addresses; the node address fields will all be set to FFFFFFFFFFFh,
  399. suitable for broadcasting, and the immediate address fields will be filled
  400. in with a call to ipxAddrImmed(), which is the officially sanctioned
  401. method of determining the "correct" immediate address to use.  Remember
  402. that packets sent to other network segments must first be sent to a router,
  403. which in turn sends the packet on its way towards its destination.  The
  404. immediate address indicates the node number on the local segment of the
  405. router that will do the first part of the routing.
  406.  
  407. Each new broadcast address set up in this fashion is used to send a
  408. diagnostic request on that segment.  Newly discovered segments will continue
  409. to be added.  ipxRouteFind() works its way through the list with the aid of
  410. two pointers: one that indicates the network segment currently being
  411. investigated and another that indicates the first free slot in the table for
  412. storing a newly discovered address.  When the two pointers point to the same
  413. location, router-finding is finished; all known network segments have been
  414. investigated.
  415.  
  416. So, when it's time to broadcast queries looking for other users of your
  417. program, you do not send out a request only on your network segment, as
  418. you would in a single-segment program.  You send out a request on all
  419. segments in all the IPXADDRFULL structures you passed to ipxRouteFind(),
  420. using those addresses as the address parameter to ipxSendPkt().  You can use
  421. the sending addresses of received replies just as you would in a single-
  422. segment program, even though some will probably contain network numbers other
  423. than your own.
  424.  
  425. If you want to allow your program to work with a few segments for
  426. flexibility, but not a huge number so as to keep the speed up, you can limit
  427. the number of IPXADDRFULL structures you pass to ipxRouteFind().  You could
  428. even save this number as a run-time variable and let the user change it
  429. according to his or her needs (obviously the user would have to be rather
  430. technically astute to understand this option, however).  You could perhaps
  431. set a reasonable default, or maybe have two radio buttons in your "network
  432. options" dialogue, one labeled "favor speed" which would allow up to six
  433. network segments, the other labeled "find all possible users" which would
  434. allow up to 60.
  435.  
  436.  
  437. "Virtual" Network Segments
  438. --------------------------
  439.  
  440. It is likely that at least one of the segments that ipxRouteFind() locates
  441. for you will be a "virtual" segment.  Starting with NetWare v3.0, servers
  442. must be assigned something called an "IPX Internal Network Number;" this
  443. is normally set in the server's AUTOEXEC.NCF command file with the command
  444. "IPX Internal Net xxxxxxxx".  Internal network numbers are eight hexadecimal
  445. digits long, just like "real" network numbers.  The server always makes
  446. itself node address 000000000001 on this network.  This is its "official"
  447. network address and there will be no other nodes on the virtual network.
  448. Prior to version 3.x, a NetWare server's address was the network and node
  449. address of the first NIC installed in it (the one referred to as "LAN A").
  450.  
  451. Network information returned from routers has one byte that indicates the
  452. type of each known network, and so virtual networks can be distinguished
  453. from "real" networks.  It would at first seem logical for ipxRouteFind() to
  454. throw away information on these virtual networks, but there are two catches
  455. that make this a bad idea.
  456.  
  457. First is the fact that there is another type of "virtual" network.  Servers
  458. running version 2.x of non-dedicated NetWare all have a virtual network
  459. segment that is used for the DOS side of the server itself.  (Non-dedicated
  460. servers function as both a file server and as a normal DOS PC through the
  461. magic of multitasking.)  Therefore this type of virtual network will have a
  462. PC on it that you might want to communicate with.  From the standpoint of
  463. NetWare diagnostics, this type of virtual network is indistinguishable from a
  464. NetWare v3.x server's virtual network.
  465.  
  466. Second is the fact that one possible use of LANLIB is to poke around inside
  467. NetWare itself.  Filtering out the server's network segment would make it
  468. impossible to send requests directly to a NetWare file server.
  469.  
  470.  
  471. NetWare Diagnostics Cautions
  472. ----------------------------
  473.  
  474. In testing LANLIB, I have noticed that if lots of PCs are running diagnostic
  475. searches at the same time, one or more may end up with incomplete network
  476. information.  I ran LANTEST on 16 PCs attached to a two-segment Ethernet
  477. network with one NetWare v3.12 server acting as the router.  I sent a command
  478. to all PCs to start diagnostics at the exact same moment.  Seven ended up
  479. with incomplete network information; they knew about their own network
  480. segment (of course), but did not find the second one or the server's
  481. "virtual" segment.  Since each PC sends three diagnostic requests on each
  482. segment, and the server exists on all three segments, it had to (try to) send
  483. nine diagnostic replies to each PC.  My guess is that the IPX drivers at each
  484. workstation were so busy sending and receiving diagnostic requests and
  485. replies that some were lost, or the server/router could not keep up with the
  486. demand.  (Almost all the PCs were 486s; there were only two 386s.)  Obviously
  487. this is a worst case scenario, but it's not unlikely that several people
  488. could start up your program at the same time.  A possible option would be to
  489. allow the user to re-scan if all expected users do not appear, or perhaps to
  490. have a secondary diagnostic phase where all copies of your program ask all
  491. other known copies for their network info; if even one PC on a segment got
  492. all the information, then it could pass it on to all others whose knowledge
  493. might be incomplete.
  494.  
  495. "Diagnostic inundation" is not the only reason that using NetWare diagnostics
  496. to locate network segments is not totally foolproof.  It will work reliably
  497. almost all of the time in small- to medium-sized networks, where the only
  498. type of routers in use are probably NetWare file servers.  Larger
  499. environments can be trickier.  Some standalone routers may route NetWare
  500. packets from segment to segment and yet not respond to standard NetWare
  501. diagnostic requests.  Given my resources, there's no way I can support
  502. non-standard routers in LANLIB.
  503.  
  504. There is another method that can be used for locating network segments: the
  505. list of logged-in users (the "connection list") on a NetWare file server can
  506. be examined.  This method has a big disadvantage, however: it requires that
  507. everybody who will use the program must be logged in to a file server.  Ad
  508. hoc networks can spring up solely for the purpose of running a favorite
  509. network-aware game; many of these networks may be too small to even have a
  510. file server, so this would not be a good approach in those situations.
  511. Still, if a LANLIB user tells me that ipxRouteFind() isn't working in a
  512. particular environment she wants to support, I would probably write a
  513. secondary ipxRouteFind()-like procedure that operated via a server's
  514. connection list that could be used in troublesome environments.
  515.  
  516.  
  517.  
  518. ******************************************************************************
  519. *                                                                            *
  520. ***  ECB Usage Statistics                                                  ***
  521. *                                                                            *
  522. ******************************************************************************
  523.  
  524. While I was writing LANTEST, I found myself wondering how many ECBs the
  525. program was actually using.  It had the default total of 8 send ECBs, but
  526. was there ever a time when that many were in use?  The LANLIB procedure for
  527. sending packets will report an error if there are no send ECBs free, but
  528. that doesn't tell you much.  Receive ECBs are even harder to gauge; if you
  529. run out, IPX simply starts throwing away packets.
  530.  
  531. That's when I built ECB usage statistics into LANLIB.  It keeps track of
  532. how many receive and send ECBs are in use at any given moment in variables,
  533. and makes two other word-sized variables available to your program,
  534. "ipxRecvMax" and "ipxSendMax," that contain the maximum number of receive
  535. and send ECBs that have been in use so far.  For the purposes of the
  536. statistics, a send ECB is considered "in use" between the time when you post
  537. it to IPX and the time that IPX notifies LANLIB that it has been sent; a
  538. receive ECB is considered "in use" beginning at the moment when IPX uses it
  539. to receive a packet and is no longer in use once you collect that packet and
  540. the ECB is put back into service.  All the LANLIB procedures update these
  541. variables dynamically as packets are sent and received, when the Event
  542. Service Routines are notified that sends and receives have completed, and so
  543. on, so they will always be correct.
  544.  
  545. You can reset the values of "ipxRecvMax" and "ipxSendMax" to zeroes at any
  546. time you like to start over again.
  547.  
  548. I ran LANTEST with "flurry mode" turned on (which means it continually
  549. sends out packets as fast as it can) and checked the statistics.  What I
  550. discovered is that it is very rare for LANTEST to need more than one send
  551. ECB.  If the main loop is jiggered to favor sends over receives, then it
  552. might need as many as four, but not usually.
  553.  
  554. Receive ECBs are a different matter.  I discovered that normally the program
  555. gets along just fine with four or fewer receive ECBs in "flurry mode," but
  556. that every now and then some event will steal time normally used for
  557. processing incoming packets, like dealing with a lot of keyboard input, and
  558. the max receive ECB value will spike up to a value as high as 50 or 60.  In
  559. fact, no matter how high I set the receive value, I could eventually get the
  560. program into a jam bad enough that it would use every last one of its receive
  561. ECBs.  That's bad news, because it almost certainly means that there were at
  562. least one or two more packets that were lost.  This is a good argument for
  563. writing your program to send acknowledges for all packet transactions.
  564.  
  565.  
  566.  
  567. ******************************************************************************
  568. *                                                                            *
  569. ***  LANLIB Error Values                                                   ***
  570. *                                                                            *
  571. ******************************************************************************
  572.  
  573. LANLIB routines generally return zero to indicate no error or some positive
  574. error value otherwise (some routines take a pointer to a word-sized variable
  575. and return errors there).  Possible error values are defined in LANLIB.H and
  576. LANLIB.INC along with a brief description for each.  All defines begin with
  577. the letters "ipxe", or "IPX Error."  ipxeNOERR is defined as 0; other values
  578. begin at 2 and head upward from there.  Further treatment of the error values
  579. is given in the descriptions of the LANLIB routines.
  580.  
  581. It is strongly recommended that you use the error defines in your program
  582. rather than the numerical values of the defines, because I reserve the right
  583. to change the numerical values in future versions of LANLIB.
  584.  
  585. It was my original intention to use IPX's own error return values, but this
  586. proved to be unworkable.  Almost every IPX call can return the error code
  587. FFh, for instance, but it means something different in every case.  I wanted
  588. one set of error codes that always meant the same thing, so procedures in
  589. LANLIB all "translate" IPX's errors into one of the LANLIB error values.
  590.  
  591. Note that, in some very rare cases, you may get an error return value other
  592. than the ones listed in LANLIB.H.  Novell has released many, many different
  593. versions of the IPX TSRs over the years, and I wouldn't be surprised if some
  594. of them return error values not given in Novell's documentation.
  595.  
  596. Naturally LANLIB can only translate error values that it knows about.  It is
  597. programmed so that if IPX returns an unrecognized error value, it will pass
  598. the unknown value straight through to your program untranslated.  Chances
  599. are good that such an error would be in the E0h to FDh range; IPX calls
  600. tend to return high-numbered errors.  If you get such an error value, I'd
  601. be interested in hearing about it so I can incorporate it into future
  602. versions of LANLIB.
  603.  
  604.  
  605.  
  606. ******************************************************************************
  607. *                                                                            *
  608. ***  Using The Routines in LANLIB                                          ***
  609. *                                                                            *
  610. ******************************************************************************
  611.  
  612. The following is a reference guide for all the routines in LANLIB that your
  613. program can use.  This is NOT the place to start if you don't understand the
  614. concepts involved.  Begin by reading NETWORK.TXT, then the earlier parts of
  615. this file.  Use this section as a day-to-day reference for the routines.
  616.  
  617.  
  618.  
  619. ipxAddrImmed()
  620. --------------
  621.  
  622. Prototype: word ipxAddrImmed(struct IPXADDRFULL far *ipxAddr,
  623.                              word far *ticks);
  624.  
  625. This procedure calls the IPX routine known as IPX Get Local Target to get the
  626. preferred immediate address for a network address.  At minimum, the network
  627. and node address fields in "ipxAddr" should be filled in before calling this
  628. procedure.  If successful, it will fill in the immediate address field.  If
  629. the address is on the same network segment, then the immediate address will
  630. be the same as the node address; if it's on a different segment, then the
  631. immediate address will be that of the router that is best suited for the
  632. task.
  633.  
  634. Parameters:
  635.  
  636.   * struct IPXADDRFULL far *ipxAddr: A pointer to an address containing
  637.     a network number and node number which are known to be valid.  It's
  638.     okay if the node number is FFFFFFFFFFFFh (a broadcast address).
  639.  
  640.   * word far *ticks: A pointer to a word to receive the estimated time
  641.     of arrival to this destination address, in IBM PC clock ticks
  642.     (approximately 1/18th of a second).  This time is only an estimate;
  643.     actual transport time will vary depending on network traffic.
  644.  
  645. Return values:
  646.  
  647.   * ipxeNOERR (FALSE): The immediate address was filled in without errors.
  648.  
  649.   * ipxeIPXNOTSTARTED: ipxStart() hasn't yet been called.
  650.  
  651.   * ipxeNOPATHFOUND: No path to the destination address could be found;
  652.     the immediate address field hasn't been set.
  653.  
  654. You should use this procedure only once for each address, rather than
  655. before each send, because it requires IPX to do some spelunking out on the
  656. network, which can create network traffic as well as take time.
  657.  
  658. Generally speaking, use of this procedure is optional, because there is a
  659. more direct method for determining the immediate address for a network
  660. address: When a packet is received, simply save the full address of the
  661. sender, including the immediate address, and use that.  However, there are
  662. some occasions where this procedure comes in useful.
  663.  
  664. Since there can be more than one route to a given destination, there can
  665. be more than one immediate address that will work for a given address.  When
  666. this procedure is used, IPX tries to determine the "best" route, taking
  667. network traffic and hop distance into account.
  668.  
  669. This procedure is also useful if you know the network and node address of a
  670. PC you want to talk to but don't also know the immediate address.
  671.  
  672. Finally, its estimate of time necessary to reach an address can be helpful
  673. if transport speed is important to your program.
  674.  
  675. ipxRouteFind() uses this procedure to determine the best immediate address
  676. to use for each network address that it finds.
  677.  
  678.  
  679.  
  680. ipxAddrLocal()
  681. --------------
  682.  
  683. Prototype: word ipxAddrLocal(struct IPXADDRFULL far *ipxAddr);
  684.  
  685. This procedure gets the IPX address of the PC that your program is running
  686. on.  It fills in every field of the IPXADDRFULL structure.  The immediate
  687. address will be the same as the node address.
  688.  
  689. Parameters:
  690.  
  691.   * struct IPXADDRFULL far *ipxAddr: A pointer to a structure to receive
  692.     the address.  It doesn't have to be initialized in any way, as every
  693.     field will be filled in.
  694.  
  695. Return values:
  696.  
  697.   * ipxeNOERR (FALSE): The address was collected without errors.
  698.  
  699.   * ipxeIPXNOTSTARTED: ipxStart() has not yet been called; the local
  700.     address can't be retrieved until it is.
  701.  
  702.  
  703.  
  704. ipxLibVer()
  705. -----------
  706.  
  707. Prototype: word ipxLibVer(void);
  708.  
  709. This procedure gets the version number of LANLIB.  It is the only LANLIB
  710. function that can be called before ipxStart() or after ipxStop().  The major
  711. version number is returned in the high byte and the minor version in the low
  712. byte.  For example, a return value of 0100h would mean major version 1, minor
  713. version 0, or 1.0.
  714.  
  715.  
  716.  
  717. ipxRecvChk()
  718. ------------
  719.  
  720. Prototype: word ipxRecvChk(void);
  721.  
  722. This procedure checks to see if any packets have been received and are
  723. waiting to be picked up.  If there are, you can retrieve them with
  724. ipxRecvPkt().
  725.  
  726. Return values:
  727.  
  728.   * FALSE: No packets are waiting.
  729.  
  730.   * TRUE: At least one packet is waiting.
  731.  
  732.   * ipxeIPXNOTSTARTED: ipxStart() hasn't been called; it isn't possible
  733.     to check for packets yet.
  734.  
  735. If IPXRECVCNT is 0, then this procedure will always indicate that no packets
  736. are waiting.
  737.  
  738.  
  739.  
  740. ipxRecvPkt()
  741. ------------
  742.  
  743. Prototype: word ipxRecvPkt(void far *data,
  744.                            word dataSize,
  745.                            struct IPXADDRFULL far *ipxAddr,
  746.                            word far *pktSize,
  747.                            word far *error);
  748.  
  749. This procedure checks to see if a packet has arrived, and if it has, it
  750. passes the data in the packet and the IPX address of the PC it was
  751. received from to your program.
  752.  
  753. Parameters:
  754.  
  755.   * void far *data: A pointer to your buffer for receiving the data.
  756.  
  757.   * word dataSize: The size, in bytes, of your buffer.
  758.  
  759.   * struct IPXADDRFULL far *ipxAddr: A structure for receiving the
  760.     address of the sending PC.
  761.  
  762.   * word far *pktSize: The address of a word that will receive the total
  763.     size of the data in the packet.
  764.  
  765.   * word far *error: The address of a word that will receive the error
  766.     code associated with this packet.
  767.  
  768. Return values:
  769.  
  770.   * FALSE: No packets are waiting and nothing was copied to your data
  771.     buffer or ipxAddr structure.  "pktSize" is zero.  "error" is also
  772.     zero, unless ipxStart() hasn't yet been called.
  773.  
  774.   * TRUE: A packet has been received.  The sending address has been
  775.     copied to ipxAddr and "error" has been set accordingly.  If "error"
  776.     is set to ipxeNOERR (zero) or ipxeSOCKETNOTOPEN, a packet has been
  777.     copied to your buffer and "pktSize" has been set to the number of
  778.     data bytes received.  If "error" has some other nonzero value, no
  779.     packet data has been copied and "pktSize" is set to zero.
  780.  
  781. Return values for "error:"
  782.  
  783.   * ipxeNOERR (FALSE): A packet was received and copied to your buffer
  784.     without any errors.
  785.  
  786.   * ipxeIPXNOTSTARTED: ipxStart() has not been called so no packets can
  787.     be received.
  788.  
  789.   * ipxeRECVPKTTOOBIG: A packet was received but it was too big to fit
  790.     in the buffer associated with the ECB (in other words, it was larger
  791.     than IPXDATASIZE), so IPX threw it away.  No data was copied to your
  792.     buffer, but your IPXADDRFULL structure has been filled in with the
  793.     sender's address.
  794.  
  795.   * ipxeRECVCANCEL: IPX reports that the receive event was canceled.
  796.     No packet data was copied.  The sender's address has been copied, but
  797.     is probably meaningless in this case.  This should never happen under
  798.     normal circumstances.
  799.  
  800.   * ipxeSOCKETNOTOPEN: The packet was received okay and has been copied
  801.     to your buffer, as well as the sender's address.  While LANLIB was
  802.     attempting to put the ECB back into service to receive more packets,
  803.     IPX reported that the socket referenced by the ECB is not open.  This
  804.     should never happen under normal circumstances.
  805.  
  806. If the size of your buffer isn't large enough to hold all the received data
  807. (this can only happen if your buffer is smaller than IPXDATASIZE), then as
  808. much data as would fit was copied (and no error will be returned).  You can
  809. tell this has happened if the value of "pktSize" is greater than the value
  810. you passed as "dataSize."
  811.  
  812. If IPXRECVCNT is 0, then this procedure will always indicate that no packets
  813. have been received.
  814.  
  815.  
  816.  
  817. ipxRouteFind()
  818. --------------
  819.  
  820. Prototype: word ipxRouteFind(struct IPXADDRFULL far *network,
  821.                              word netCnt,
  822.                              word (*ipxWaitProc)(word netsFound),
  823.                              word far *netsFound);
  824.  
  825. This is a complicated procedure which finds other network segments in the
  826. internetwork.  It fills in a structure of IPXADDRFULLs with broadcast
  827. addresses for all the segments it finds, including the network segment the
  828. program is running on.  See the earlier section "Dealing with Network
  829. Segments" for details on using this information.  This procedure is not
  830. available in the shareware version of LANLIB.
  831.  
  832. Parameters:
  833.  
  834.   * struct IPXADDRFULL far *network: A pointer to at least two
  835.     IPXADDRFULL structures.  It is suggested that you use the define
  836.     IPXNETCNT from LANCFG.H when determining how big to make this
  837.     structure (or how much memory to allocate for it), rather than
  838.     using a fixed number.
  839.  
  840.   * word netCnt: The total number of IPXADDRFULLs pointed to by
  841.     "network."  It is suggested that you use the define IPXNETCNT
  842.     rather than a fixed number.
  843.  
  844.   * word (*ipxWaitProc)(word netsFound): A pointer to a procedure
  845.     that will be called repeatedly while the router-finding is taking
  846.     place.  This will be a near pointer in small code models and a far
  847.     pointer in large code models.  Since ipxRouteFind() might conceivably
  848.     take quite a long time to do its work, this gives you a chance to
  849.     display something on the screen to let the user know the program
  850.     hasn't crashed and to allow an opportunity to abort the procedure, if
  851.     need be.  See the description for ipxWaitProc() for details.  If this
  852.     pointer is NULL, then no external procedure will be called.
  853.  
  854.   * word far *netsFound: A pointer to a word that will receive the
  855.     number of network segments that were located.
  856.  
  857. Return values:
  858.  
  859.   * ipxeNOERR (FALSE): The procedure completed without errors.
  860.     "network" has been filled in with all known networks, and the
  861.     total count has been placed in "netsFound."
  862.  
  863.   * TRUE (1): A send error occurred either at some point before
  864.     ipxRouteFind() was called or while sending out diagnostic requests.
  865.     The send error(s) are still waiting to be picked up via calls to
  866.     ipxSendErr().
  867.  
  868.   * ipxeNETOVERFLOW: The procedure aborted because it found at least one
  869.     more network segment than would fit in the "network" structure that
  870.     was passed to it.  This is not really an "error" per se; you might
  871.     purposefully wish to keep the number of networks your program will
  872.     work with to a minimum to ensure fast response.
  873.  
  874.   * ipxeBADCOMMPARMS: "netCnt" is less than two, or one or more of the
  875.     values IPXRECVCNT, IPXSENDCNT, or IPXDATASIZE passed to ipxStart()
  876.     are too small to allow the procedure to run.  See below for details.
  877.  
  878.   * ipxeNOFREESENDECB: While trying to send out a diagnostic request,
  879.     ipxSendPkt() reported that there were no free send ECBs.  If you get
  880.     this error during testing, you should increase the value of
  881.     IPXSENDCNT.
  882.  
  883.   * ipxeROUTEFINDABORT: The procedure was aborted because "ipxWaitProc()"
  884.     returned TRUE.  See below for details.
  885.  
  886.   * ipxeIPXNOTSTARTED: ipxStart() has not yet been called.
  887.  
  888.   * ipxeNOPATHFOUND: When ipxRouteFind() called ipxAddrImmed() to get
  889.     the immediate address for a discovered network, ipxAddrImmed()
  890.     returned this value.  This shouldn't happen under normal
  891.     circumstances.
  892.  
  893.   * ipxeRECVPKTTOOBIG: While receiving diagnostic replies, ipxRecvPkt()
  894.     reported this error.  See ipxRecvPkt() for more details.
  895.  
  896.   * ipxeRECVCANCEL: See explanation for ipxeRECVPKTTOOBIG above.
  897.  
  898.   * ipxeSOCKETNOTOPEN: See explanation for ipxeRECVPKTTOOBIG above.
  899.  
  900. If the procedure returns with some value other than FALSE, the network
  901. information in the "network" structure and the "netCnt" variable will be
  902. accurate but not necessarily complete; the procedure might not have found
  903. all networks before it had to abort.  If the value returned is
  904. ipxeBADCOMMPARMS or ipxeIPXNOTSTARTED, then "network" will contain no
  905. network information at all.
  906.  
  907. ipxRouteFind() performs the following steps:
  908.  
  909.   * It calls ipxAddrLocal() to fill in the first IPXADDRFULL structure
  910.     pointed to by "network" with the network address of the network that
  911.     it is running on.  Then it sets the node and immediate address fields
  912.     of this first structure to all F's, making the address suitable for
  913.     broadcasting.
  914.  
  915.   * It calls ipxSendChk() to make sure there are no send errors in the
  916.     send queue.  If there are, it aborts and returns to your program,
  917.     leaving the send errors in the queue.
  918.  
  919.   * It calls ipxSendPkt() to send out a diagnostic request on the local
  920.     network segment.
  921.  
  922.   * It calls ipxRecvPkt() repeatedly to get diagnostic replies.  Packets
  923.     from anything that routes packets to other segments (standalone
  924.     routers or file servers) are examined for other network segments.
  925.     Replies from other PCs are ignored.  Non-diagnostic packets are also
  926.     ignored (this is determined by examining the socket that the packet
  927.     came from).  The addresses of other networks discovered are saved,
  928.     and ipxAddrImmed() is called for each to fill in the best immediate
  929.     address.  To avoid clogging the network with diagnostic replies,
  930.     each node will wait for a period of time up to half a second before
  931.     sending a diagnostic response, so this procedure will wait at least
  932.     that long to give all nodes a chance to respond.  It only checks the
  933.     elapsed time when no replies are coming in, so the actual time used
  934.     might be greater than half a second.
  935.  
  936.   * If a pointer to a procedure of type ipxWaitProc() was given, it is
  937.     called at this point.
  938.  
  939.   * The cycle is repeated twice more, starting with the call to
  940.     ipxSendChk(), to ensure that all routers are heard from and to allow
  941.     enough time to receive responses from routers that might take longer
  942.     than half a second to arrive.  Therefore, about 1.5 seconds are spent
  943.     analyzing the network segment from start to finish, and ipxWaitProc()
  944.     will be called three times.
  945.  
  946.   * The entire 1.5 second three-cycle ordeal is repeated for each new
  947.     segment that is discovered.  It is possible that late replies from
  948.     earlier diagnostic requests on other segments might arrive during
  949.     this time; if so, they will be properly processed as well.  This
  950.     process continues until all segments have been discovered and
  951.     analyzed or until a new segment is discovered and the structure
  952.     for saving the segment information is full, whichever comes first.
  953.  
  954.   * After all discovered segments have been analyzed, the procedure waits
  955.     one more full second to see if any more late diagnostic responses
  956.     will arrive.  If one or more such responses arrive, and they contain
  957.     the addresses of one or more new network segments, then the 1.5
  958.     second analysis procedure is again run for those segments and the
  959.     full second final wait will be repeated.
  960.  
  961. Since ipxRouteFind() is basically a small LANLIB-using application unto
  962. itself, it has certain requirements that must be met for it to be used:
  963. IPXRECVCNT must be at least 30, IPXSENDCNT must be at least 2, and
  964. IPXDATASIZE must be at least 256.  If these conditions aren't met, then
  965. ipxRouteFind() will return ipxeBADCOMMPARMS, no network segment data
  966. will be copied to "network," and "netsFound" will be zero.
  967.  
  968. If a procedure was given as "ipxWaitProc()", then ipxRouteFind() will call it
  969. at the end of each send/receive cycle, approximately every half second.  The
  970. procedure is called with one word-sized parameter, netsFound, which indicates
  971. the number of networks found so far.  This number will not be incremented on
  972. every call to "ipxWaitProc()".  If the ipxWaitProc() procedure returns FALSE,
  973. then router-finding continues; if it returns TRUE, then ipxRouteFind() will
  974. abort and return ipxeROUTEFINDABORT.  See ipxWaitProc() for more details.
  975.  
  976. You shouldn't have any "conversations" with other PCs going on when you call
  977. this procedure, because it will "eat" any and all packets that are received
  978. while it is running and throw away any that aren't diagnostic responses.
  979.  
  980. It's okay to call this procedure more than once during the run of a program;
  981. for instance, it might need to be called a second time with a higher number
  982. for netCnt if a particular expected address was not found or ipxeNETOVERFLOW
  983. was returned.
  984.  
  985. It is possible but unlikely that your program will receive a late diagnostic
  986. response at some point after ipxRouteFind() completes.  You can check for
  987. this condition by examining the socket number in the sending address;
  988. diagnostic replies come from socket 0456h.  If this happens consistently,
  989. let me know; it probably means that I need to tweak the code inside
  990. ipxRouteFind() to wait a little longer for replies to arrive.
  991.  
  992. If a router does not respond to standard NetWare diagnostic requests, then
  993. this procedure won't recognize it and won't be able to access the networks
  994. it knows about.  I am told that routers like this exist in some NetWare
  995. environments.  Routers of this type are not supported by LANLIB.
  996.  
  997. If a router claims to be attached to more than 32 networks, its information
  998. is ignored.  Values higher than 32 probably indicate an error of some sort.
  999.  
  1000. Since it must take real time into account, ipxRouteFind() examines the word
  1001. at 0040:006Ch in the BIOS data segment, which is the least significant word
  1002. of the number of timer ticks that have elapsed since midnight.
  1003.  
  1004. This procedure uses almost 1k of stack space for temporary variables, so you
  1005. should ensure that this much is available.
  1006.  
  1007.  
  1008.  
  1009. ipxSendChk()
  1010. ------------
  1011.  
  1012. Prototype: word ipxSendChk(void);
  1013.  
  1014. This procedure checks to see if any errors were encountered while trying
  1015. to send packets, and therefore whether those packets are waiting around
  1016. for you to pick them up.  If there are unsent packets, you can pick them up
  1017. with ipxSendErr().  This should be done periodically, because ECB/packet
  1018. pairs that were used for unsuccessful sends are unusable until retrieved
  1019. with ipxSendErr().
  1020.  
  1021. Return values:
  1022.  
  1023.   * FALSE: No undelivered packets are waiting.
  1024.  
  1025.   * TRUE: At least one undelivered packet is waiting.
  1026.  
  1027.   * ipxeIPXNOTSTARTED: ipxStart() hasn't been called; it isn't possible
  1028.     to check for send packet errors yet.
  1029.  
  1030. If IPXSENDCNT is 0, then this procedure will always indicate that no send
  1031. errors are waiting.
  1032.  
  1033.  
  1034.  
  1035. ipxSendErr()
  1036. ------------
  1037.  
  1038. Prototype: word ipxSendErr(void far *data,
  1039.                            word dataSize,
  1040.                            struct IPXADDRFULL far *ipxAddr,
  1041.                            word far *pktSize,
  1042.                            word far *error);
  1043.  
  1044. This procedure checks for IPX send errors.  It is unlikely that you'll get
  1045. any, but if you do, this routine in effect gives your packet back to you so
  1046. you can retry the send or take other steps as necessary.  It should be called
  1047. every now and then even if you don't want to process send errors, because a
  1048. send ECB/packet pair that had an error is taken out of service indefinitely
  1049. until you call ipxSendErr() to free it up.  If all send ECBs are taken out
  1050. of service due to errors, then you won't be able to send any more data.
  1051.  
  1052. Parameters:
  1053.  
  1054.   * void far *data: A pointer to your buffer that will receive the
  1055.     packet that couldn't be sent (if an error is reported).
  1056.  
  1057.   * word dataSize: The size of your buffer, in bytes.
  1058.  
  1059.   * struct IPXADDRFULL far *ipxAddr: A structure to receive the address
  1060.     of the PC that the packet should have been sent to.
  1061.  
  1062.   * word far *pktSize: A pointer to a word to receive the size of the
  1063.     data that is being returned.
  1064.  
  1065.   * word far *error: A pointer to a word to receive the error value
  1066.     associated with the packet.
  1067.  
  1068. Return values:
  1069.  
  1070.   * FALSE: No undelivered packets are waiting.  "error" will be set to
  1071.     ipxeNOERR (zero) unless ipxStart() hasn't been called.
  1072.  
  1073.   * TRUE: An undelivered packet has been copied to your buffer, the
  1074.     total size has been set in "pktSize," and the intended recipient's
  1075.     address has been copied to "ipxAddr."  The ECB with the error is
  1076.     returned to service, ready to be used for the next send request.
  1077.  
  1078. Return values for "error:"
  1079.  
  1080.   * ipxeNOERR (FALSE): There are no undelivered packets to be processed.
  1081.  
  1082.   * ipxeIPXNOTSTARTED: ipxStart() has not been called.
  1083.  
  1084.   * ipxeSENDBADROUTE: The packet was undeliverable.  This can happen
  1085.     if you send a packet to yourself (broadcasts count as "sending a
  1086.     packet to yourself") and there are no free receive ECBs.  If the
  1087.     packet was to another PC, then IPX could not find a route to the
  1088.     destination node; this probably indicates a problem with the
  1089.     immediate address.
  1090.  
  1091.   * ipxeSENDCANCEL: IPX reported that the send event was canceled.  This
  1092.     shouldn't happen under normal circumstances.
  1093.  
  1094.   * ipxeSENDPKTBAD: The packet was "malformed," to use Novell's term.
  1095.     It was either too short, too long, or the fragment count was wrong.
  1096.     LANLIB takes care of all this, so this error should never be
  1097.     returned under normal circumstances.
  1098.  
  1099.   * ipxeSENDNETFAIL: IPX reports that the local network hardware or the
  1100.     network itself has failed.
  1101.  
  1102. If IPXSENDCNT is 0, then this procedure will always indicate that no send
  1103. errors are waiting.
  1104.  
  1105.  
  1106.  
  1107. ipxSendPkt()
  1108. ------------
  1109.  
  1110. Prototype: word ipxSendPkt(void far *data,
  1111.                            word dataSize,
  1112.                            struct IPXADDRFULL far *ipxAddr);
  1113.  
  1114. This procedure posts a send request with IPX.  No error associated with
  1115. the send will be returned, because ipxSendPkt() will return before IPX
  1116. has actually sent the packet.
  1117.  
  1118. Parameters:
  1119.  
  1120.   * void far *data: A pointer to your buffer filled with packet data to
  1121.     be sent.
  1122.  
  1123.   * word dataSize: The number of bytes in your buffer to be sent.  This
  1124.     does not have to be the same as the size of the buffer, if you want
  1125.     to send fewer bytes.
  1126.  
  1127.   * struct IPXADDRFULL far *ipxAddr: The full IPX address of the PC to
  1128.     send the packet to.  If you set the node address to FFFFFFFFFFFFh,
  1129.     the packet will be sent to all nodes on the selected network segment.
  1130.  
  1131. Return values:
  1132.  
  1133.   * ipxeNOERR (FALSE): The request was posted without errors.  This DOES
  1134.     NOT mean that the packet has been sent.
  1135.  
  1136.   * ipxeIPXNOTSTARTED: ipxStart() has not been called.
  1137.  
  1138.   * ipxeNOFREESENDECB: All send ECBs are currently in use, waiting to be
  1139.     sent by IPX (or else IPXSENDCNT is set to 0, which shouldn't be true
  1140.     if your program ever sends any packets).  You can retry the send at
  1141.     some point later in time.  If you get this error during testing, you
  1142.     can increase the number of send ECBs by setting the define IPXSENDCNT
  1143.     in LANCFG.H to a higher value.
  1144.  
  1145. If the value of "dataSize" given is bigger than the value of IPXDATASIZE,
  1146. then you've given more data than the procedure can send; the number of
  1147. bytes sent will be truncated to IPXDATASIZE and no error will be returned.
  1148.  
  1149. The procedure ipxSendErr() should be called occasionally to check for send
  1150. errors.  If all packets are sent successfully, then ipxSendErr() will return
  1151. nothing, but keep in mind that this does NOT mean that the packet was
  1152. successfully received; it could have been lost in transit.  IPX does not
  1153. guarantee that all packets sent will be received.
  1154.  
  1155. IPX allows you to "send packets to yourself," so to speak.  You could call
  1156. ipxSendPkt() to send some data, setting "ipxAddr" to your own IPX address,
  1157. and then receive that same packet with ipxRecvPkt().  IPX is smart enough
  1158. to figure out that the packet doesn't have to go out onto the network and
  1159. merely copies it in memory.  This can be useful for debugging.
  1160.  
  1161. If a program "broadcasts" a packet to all addresses on its own network
  1162. segment by sending to node address FFFFFFFFFFFFh, then the program will
  1163. receive a copy of its own sent packet.
  1164.  
  1165.  
  1166.  
  1167. ipxStart()
  1168. ----------
  1169.  
  1170. Prototype: word ipxStart(word recvCnt,
  1171.                          word sendCnt,
  1172.                          word dataSize,
  1173.                          word socket,
  1174.                          void far *memPtr,
  1175.                          word memSize);
  1176.  
  1177. Call this as the very first IPX-related routine in your program.  No other
  1178. IPX functions except ipxLibVer() may be used until ipxStart() has been
  1179. called.  It performs the following functions:
  1180.  
  1181.   * It checks all parameters for validity except "socket."  It also
  1182.     checks to make sure that the amount of memory given is large enough
  1183.     to hold everything.
  1184.  
  1185.   * It checks to make sure that the IPX driver is loaded.  If not, it
  1186.     returns with an error code.  If IPX is available, it saves the entry
  1187.     point used to make far calls to the IPX driver, which is needed by
  1188.     all other LANLIB routines except ipxLibVer().
  1189.  
  1190.   * It opens the IPX socket number given as the parameter "socket"
  1191.     for sending and receiving packets.
  1192.  
  1193.   * It registers all receive ECBs and their associated packet buffers
  1194.     with IPX, making them available to receive incoming data packets.
  1195.  
  1196. Parameters:
  1197.  
  1198.   * word recvCnt: The number of receive ECB/buffer pairs to use.  Legal
  1199.     values are 0 to 250.  The minimum is 30 if ipxRouteFind() will be
  1200.     used.  It is suggested that you use the define IPXRECVCNT from
  1201.     LANCFG.H rather than passing a number directly.  Each receive
  1202.     ECB/buffer pair will require IPXCOMMSIZE bytes (a define in
  1203.     LANLIB.H).
  1204.  
  1205.   * word sendCnt: The number of send ECB/buffer pairs to use.  Legal
  1206.     values are 0 to 250.  The minimum is 2 if ipxRouteFind() will be
  1207.     used.  It is suggested that you use the define IPXSENDCNT from
  1208.     LANCFG.H rather than passing a number directly.  Each send
  1209.     ECB/buffer pair will require IPXCOMMSIZE bytes.
  1210.  
  1211.   * dataSize: The maximum number of data bytes per packet.  Legal values
  1212.     are 0 to 546.  The minimum is 256 if ipxRouteFind() will be used.
  1213.     It is suggested that you use the define IPXDATASIZE in LANCFG.H
  1214.     rather than passing a number directly.
  1215.  
  1216.   * void far *memPtr: This is a far pointer to an allocated block of
  1217.     memory that LANLIB will use for ECBs, buffers, queues, and so on.
  1218.     This can be memory allocated from the near heap with malloc() or from
  1219.     the far heap with farmalloc(), memory obtained with a direct call to
  1220.     DOS, a pointer to a block of memory in an initialized or
  1221.     uninitialized data segment, or just about anything else, just so long
  1222.     as it's big enough to hold everything (see below).  It doesn't have
  1223.     to be set to all zeroes; LANLIB does that itself.  The memory block
  1224.     must be less than 64k.
  1225.  
  1226.   * word memSize: The size of the memory block pointed to by memPtr, in
  1227.     bytes.  This value can be calculated by using the define IPXMEMSIZE
  1228.     located in LANLIB.H.
  1229.  
  1230. Return values:
  1231.  
  1232.   * ipxeNOERR (FALSE): All operations were completed without errors.
  1233.  
  1234.   * ipxeNOIPX: The IPX driver TSR (or TSRs) are not loaded.  IPX
  1235.     communication is not possible.
  1236.  
  1237.   * ipxeIPXSTARTED: ipxStart() has already been called.  It should not
  1238.     be called twice.
  1239.  
  1240.   * ipxeBADCOMMPARMS: One of the communication parameters given was set
  1241.     to an illegal value.  All are checked for validity except "socket."
  1242.     This value will be returned if "memPtr" is NULL.
  1243.  
  1244.   * ipxeMEMTOOSMALL: The value of memSize indicates that the memory
  1245.     block given is not big enough to hold all the communication data
  1246.     (see below).
  1247.  
  1248.   * ipxeMEMABOVE64K: The amount of memory required for all requested
  1249.     ECBs and buffers would exceed 64k.  This is not allowed (see
  1250.     below).
  1251.  
  1252.   * ipxeSOCKETTABLEFULL: The selected socket cannot be opened because
  1253.     the IPX driver's socket table is full.  IPX defaults to allowing up
  1254.     to 20 open sockets.  To increase this amount, add the line
  1255.     "IPX SOCKETS = xx" to the NET.CFG file, where "xx" is the number of
  1256.     sockets required.  Sockets use some of the PC's memory, so don't
  1257.     increase the number any higher than necessary.
  1258.  
  1259.   * ipxeSOCKETOPEN: The requested socket was already open; ipxStart()
  1260.     did not complete.  Some other program is probably using the socket.
  1261.     This can also happen if the user "crashes out" of your program, so
  1262.     ipxStop() was never called and the socket was left open, and then
  1263.     the user tries to start it again.  In this case, a reboot will fix
  1264.     the trouble.
  1265.  
  1266.   * ipxeSOCKETNOTOPEN: While setting up the listen ECBs to receive
  1267.     incoming packets, IPX reported that the selected socket was not open,
  1268.     despite the fact that the socket was opened earlier with no error.
  1269.     It is extremely unlikely that this error will be reported under
  1270.     normal circumstances.
  1271.  
  1272. The formula for determining how much memory to pass to ipxStart() is as
  1273. follows (and is also defined as IPXMEMSIZE in LANLIB.H):
  1274.  
  1275.   (IPXRECVCNT + IPXSENDCNT) * IPXCOMMSIZE
  1276.  
  1277. This is the total number of send and receive ECB/buffer pairs times the
  1278. amount of memory for each, IPXCOMMSIZE.  This is the total overhead bytes
  1279. for each plus IPXDATASIZE.  IPXCOMMSIZE is defined in LANLIB.H.  The user
  1280. must ensure that the total amount of memory needed is less than 64k.  If
  1281. it's greater, reduce the size of one or all of IPXRECVCNT, IPXSENDCNT, or
  1282. IPXDATASIZE, defined in LANCFG.H, until the required size is less than
  1283. 64k.
  1284.  
  1285. There is no point in passing more memory than the amount given by this
  1286. formula.  LANLIB will not use any excess memory.
  1287.  
  1288.  
  1289.  
  1290. ipxStop()
  1291. ---------
  1292.  
  1293. Prototype: word ipxStop(void);
  1294.  
  1295. Call this as the last IPX function in your program.  If you end your program
  1296. without calling it, your computer may well crash later on when IPX tries to
  1297. store an incoming packet in a memory buffer that no longer belongs to you.
  1298.  
  1299. ipxStop() performs the following function:
  1300.  
  1301.   * It closes the IPX socket passed to ipxStart() as the parameter
  1302.     "socket."  This has the effect of canceling any pending send
  1303.     requests and all receive ECBs.  The IPX close socket function never
  1304.     returns an error, so no form of IPX error will be passed to your
  1305.     program.
  1306.  
  1307. Return values:
  1308.  
  1309.   * ipxeNOERR (FALSE): The procedure completed without errors.
  1310.  
  1311.   * ipxeIPXNOTSTARTED: ipxStart() was never called, so there is nothing
  1312.     to stop.
  1313.  
  1314. If memory was allocated for ipxStart() (as opposed to passing a pointer to
  1315. an area of a data segment), then the memory should be freed after the call
  1316. to ipxStop().
  1317.  
  1318.  
  1319.  
  1320. ipxWaitProc()
  1321. -------------
  1322.  
  1323. Prototype: word ipxWaitProc(word netsFound);
  1324.  
  1325. This is not a procedure in LANLIB, but rather one that can exist in your
  1326. program.
  1327.  
  1328. Since ipxRouteFind() takes about 1.5 seconds to process each network segment,
  1329. and an internetwork might well contain 20 or more segments, it would be easy
  1330. for a user of your program to assume that it had crashed and reboot the PC.
  1331. To get around this problem, ipxRouteFind() takes as one of its parameters a
  1332. pointer to a procedure of this type that it will call approximately every
  1333. half second.
  1334.  
  1335. Your procedure will receive one word-sized variable, netsFound, which will
  1336. be the number of network segments discovered so far.  This number will
  1337. never be less than one, since the network segment that your program is
  1338. running on is counted, and it is "discovered" before your procedure is
  1339. called the first time.  This value might be two or higher on the very first
  1340. call to your procedure since one diagnostic cycle will have been completed
  1341. at that point.
  1342.  
  1343. Your procedure must return one word-sized variable that indicates whether
  1344. or not ipxRouteFind() should continue.  If your procedure returns FALSE (0),
  1345. then ipxRouteFind() will continue.  If it returns any other value then
  1346. ipxRouteFind() will abort.
  1347.  
  1348. This procedure is not subject to the restrictions imposed on interrupt
  1349. service routines.  At the time it is called the PC is in a stable state.
  1350. The procedure can call other procedures in the program, collect keyboard
  1351. or mouse input, call DOS and perform file I/O if need be, display information
  1352. on the screen (perhaps the running total of networks it was called with), and
  1353. take as long as it likes to complete; any amount of time up to a second or so
  1354. is reasonable.  It should not call any LANLIB procedures, however (or call
  1355. other procedures that call LANLIB); ipxRouteFind() is using LANLIB at the
  1356. moment; LANLIB calls should wait until after ipxRouteFind() has finished.
  1357.  
  1358. This procedure can be written in any language, but it must follow the C
  1359. calling convention.  Its lone parameter will be on the stack at the time it
  1360. is called, it must put its return value in the AX register, and
  1361. ipxRouteFind() will clean up the stack afterwards.  It doesn't have to save
  1362. any registers except SP, BP, SI, DI, DS, and SS.  This is all according to
  1363. the standard C calling convention.  ipxRouteFind() will access it with a near
  1364. call in small code models and with a far call in large code models, so it
  1365. must use the default return type (near or far) for the current memory model.
  1366.  
  1367. The LANLIB demo program LANTEST contains a procedure of this type, called
  1368. routeWait(), in the file NETWORK.C.
  1369.  
  1370.  
  1371.  
  1372. ******************************************************************************
  1373. *                                                                            *
  1374. ***  LANUTIL Routines                                                      ***
  1375. *                                                                            *
  1376. ******************************************************************************
  1377.  
  1378. Programs using LANLIB will almost certainly have to keep track of at least a
  1379. few other PCs out on the network.  This requires keeping track of those PC's
  1380. IPX addresses, which are best kept in IPXADDRFULL structures.  You might
  1381. have to copy one address to another, compare two addresses to see if they're
  1382. the same or to sort a list, or print an address to the screen.  Since an
  1383. IPXADDRFULL structure is large and complicated, these sorts of tasks are made
  1384. more difficult.  This is exactly the problem I found myself up against when
  1385. I wrote LANTEST.  The LANUTIL routines are the solution I came up with.
  1386.  
  1387. The LANUTIL routines are written in C and the source code is included in the
  1388. file LANUTIL.C.  You can use or modify this code as you see fit.
  1389.  
  1390.  
  1391.  
  1392. ipxAddrBrd()
  1393. ------------
  1394.  
  1395. Prototype: struct IPXADDRFULL *ipxAddrBrd(struct IPXADDRFULL *ipxAddr);
  1396.  
  1397. This procedure sets the node address and immediate address fields in an
  1398. IPXADDR structure to FFFFFFFFFFFFh, which makes the address suitable for
  1399. broadcasting packets to all PCs on the local network segment.  It does
  1400. nothing at all to the network and socket fields, so those values should
  1401. already be set before performing this call.
  1402.  
  1403. A convenient way to set up an IPXADDRFULL structure suitable for
  1404. broadcasting packets on your local segment is to first get your local
  1405. address from the LANLIB procedure ipxAddrLocal(), then pass that address
  1406. to ipxAddrBrd() to set the node and immediate address fields.
  1407.  
  1408. Note that if you broadcast a packet to all PCs on your network segment,
  1409. you yourself will also get a copy of that packet.
  1410.  
  1411. This procedure returns a pointer to the IPXADDRFULL structure.
  1412.  
  1413.  
  1414.  
  1415. ipxAddrCmp()
  1416. ------------
  1417.  
  1418. Prototype: int ipxAddrCmp(struct IPXADDRFULL *ipxAddr1,
  1419.                           struct IPXADDRFULL *ipxAddr2)
  1420.  
  1421. This procedure compares the network, node, and socket numbers of two
  1422. IPXADDRFULL structures.  It can be used to sort addresses into numerical
  1423. order or simply to determine if two addresses are identical.  It returns
  1424. -1 if the first address is less than the second, 0 if the addresses are
  1425. the same, or 1 if the first address is greater than the second.
  1426.  
  1427.  
  1428.  
  1429. ipxAddrCpy()
  1430. ------------
  1431.  
  1432. Prototype: struct IPXADDRFULL *ipxAddrCpy(struct IPXADDRFULL *ipxAddrDst,
  1433.                                           struct IPXADDRFULL *ipxAddrSrc)
  1434.  
  1435. This procedure copies the entire contents of one IPXADDRFULL structure
  1436. to another.  It returns a pointer to the destination address.
  1437.  
  1438.  
  1439.  
  1440. ipxAddrSocket()
  1441. ---------------
  1442.  
  1443. Prototype: struct IPXADDRFULL *ipxAddrSocket(struct IPXADDRFULL *ipxAddr,
  1444.                                              word socket)
  1445.  
  1446. This procedure accepts a pointer to an IPXADDRFULL structure and a socket
  1447. number in normal Intel low-high format.  It flips the socket number to
  1448. high-low format, as required by IPX, and puts it in the structure.  It
  1449. returns a pointer to the structure.
  1450.  
  1451.  
  1452.  
  1453. ipxAddrStr()
  1454. ------------
  1455.  
  1456. Prototype: char *ipxAddrStr(char *str, struct IPXADDRFULL *ipxAddr)
  1457.  
  1458. This procedure creates a string representation of the network and node
  1459. address in an IPXADDRFULL structure in the string pointed to by "str"
  1460. in the format xxxxxxxx:yyyyyyyyyyyy, where the x's are the network number
  1461. and the y's are the node number.  The string given as "str" must contain at
  1462. least 22 bytes.  The network and node are all that's needed to uniquely
  1463. identify one PC from any other, so many of NetWare's own utilites use
  1464. this format for displaying addresses.  It returns a pointer to the string.
  1465.  
  1466.  
  1467.  
  1468. ipxAddrStrLong()
  1469. ----------------
  1470.  
  1471. Prototype: char *ipxAddrStrLong(char *str, struct IPXADDRFULL *ipxAddr)
  1472.  
  1473. This procedure creates a string representation of all four components of
  1474. the IPXADDRFULL structure, all separated by colons.  The string given as
  1475. "str" must contain at least 40 bytes.  This is probably not too useful
  1476. for production programs, but it sometimes comes in handy for debugging.  It
  1477. returns a pointer to the string.
  1478.  
  1479.  
  1480.  
  1481. ipxByteSwap()
  1482. -------------
  1483.  
  1484. Prototype: word ipxByteSwap(word socket)
  1485.  
  1486. This procedure takes a word parameter (typically a socket number), swaps
  1487. its high byte with its low byte, and returns the modified value.  This
  1488. will convert a socket number in low-high Intel format to high-low Motorola
  1489. format, or vice versa.  This can be useful because IPX requires that the
  1490. socket field of IPXADDRFULLs be maintained in high-low (Motorola) format.
  1491.  
  1492.  
  1493.  
  1494. ******************************************************************************
  1495. *                                                                            *
  1496. ***  The Future of LANLIB                                                  ***
  1497. *                                                                            *
  1498. ******************************************************************************
  1499.  
  1500. I am planning to do a 32-bit version of LANLIB compatible with the Watcom
  1501. 32-bit compiler.
  1502.  
  1503. I expect to eventually do a NetBIOS library as well, devise a common API
  1504. layer that both the NetBIOS version and LANLIB will share, and figure out
  1505. a way that a program can load one or the other but not both at runtime.
  1506. Eventually I might also round out the situation with a serial communication
  1507. library that uses the same API and can be loaded in place of one of the
  1508. network drivers.
  1509.  
  1510. I may also do a Windows version of LANLIB, and also the NetBIOS library.
  1511.  
  1512. If you have an interest in any of these potential projects, please let me
  1513. know.  User interest will play a big part in whether or not I get around
  1514. to them.
  1515.  
  1516. If you would like to do something with LANLIB that I haven't taken into
  1517. account, such as use it with a different compiler, or with overlays, or
  1518. whatever, let me know.  If it's feasible, I can probably be talked into it.
  1519.  
  1520.  
  1521. Allen Brunson
  1522. 6500 East 21st #2
  1523. Wichita, Kansas  67206
  1524. U.S.A.
  1525.  
  1526. CompuServe: 74464,3472
  1527. Internet: 74464.3472@compuserve.com
  1528.  
  1529.  
  1530.  
  1531. ******************************************************************************
  1532. *                                                                            *
  1533. ***  Special Thanks                                                        ***
  1534. *                                                                            *
  1535. ******************************************************************************
  1536.  
  1537. Like any good piece of software, LANLIB was not created in a vacuum.  I had
  1538. a lot of help and feedback from many people.  Two in particular stand out and
  1539. deserve special mention:
  1540.  
  1541. Bart Stewart.  He performed countless tests on my behalf using his company's
  1542. huge NetWare internetwork and various buggy versions of LANTEST.EXE.  His
  1543. knowledge of and experience with IPX diagnostics directly shaped the
  1544. architecture of LANLIB.
  1545.  
  1546. Doug Goldner.  Unless somebody else gets into an EXTREME hurry, it looks like
  1547. he will produce the first ever LANLIB-using program, a text-based adventure
  1548. game called Multi-Venture that uses a client-server architecture.  He figured
  1549. out tricks to using LANLIB that didn't even occur to me, and in the process
  1550. helped validate the whole LANLIB concept.  You can contact Doug about his
  1551. game at his CIS address, 76702,1257.
  1552.  
  1553.  
  1554.  
  1555. ******************************************************************************
  1556. *                                                                            *
  1557. ***  Release History                                                       ***
  1558. *                                                                            *
  1559. ******************************************************************************
  1560.  
  1561.  
  1562. Version 1.00, June 30, 1994
  1563.  
  1564. First public general release.
  1565.  
  1566. Changes:
  1567.  
  1568.   * A little legalese, courtesy of my mom the lawyer, is about all that's
  1569.     new.
  1570.  
  1571.  
  1572. Version 0.40, June 23, 1994
  1573.  
  1574. Fourth public beta release.
  1575.  
  1576. Changes:
  1577.  
  1578.   * Novell's legal department wouldn't let me use their trademark in my
  1579.     product's name, so I can't call it IPXLIB; now it's LANLIB, and all
  1580.     the files and so on were renamed.
  1581.  
  1582.   * LANTEST (formerly IPXTEST) can now write its network info to a file.
  1583.     This is useful (to me, at least) for debugging ipxRouteFind() if it
  1584.     fails to find all network segments on a given internetwork.
  1585.  
  1586.   * I added the procedure ipxAddrImmed(), which calls IPX to get the
  1587.     preferred immediate address for a given network address, and one
  1588.     new error value for it, ipxeNOPATHFOUND.  ipxRouteFind() and LANTEST
  1589.     were both upgraded to use it.
  1590.  
  1591.   * I added a new error value, ipxeMEMABOVE64K, which ipxStart() will
  1592.     now return if the amount of memory required is above 64k (an error).
  1593.  
  1594.  
  1595. Version 0.30, June 10, 1994
  1596.  
  1597. Third public beta release.
  1598.  
  1599. Changes:
  1600.  
  1601.   * IPX.H was renamed IPXLIB.H, IPX.ASM was renamed IPXLIB.ASM, and the
  1602.     .LIB files were also appropriately renamed.
  1603.  
  1604.   * The define IPXMEMSIZE was added to IPXLIB.H to calculate the memory
  1605.     size needed to pass to ipxStart().
  1606.  
  1607.   * IPXLIB.INC and IPXCFG.INC, the assembler versions of IPXLIB.H and
  1608.     IPXCFG.H, were added for programmers wishing to use IPXLIB with
  1609.     assembler programs.
  1610.  
  1611.   * I finally finished ipxRouteFind(), the procedure that finds network
  1612.     segments, and added one more IPXLIB error value for it,
  1613.     ipxeROUTEFINDABORT.  I got rid of the never-used define IPXHOPS and
  1614.     replaced it with the new IPXNETCNT, given as a parameter to
  1615.     ipxRouteFind().  IPXTEST was upgraded to use the new procedure.
  1616.     "Dealing with Network Segments" was added to the documentation.
  1617.  
  1618.   * ipxeBADCOMMPARMS now also applies to ipxRouteFind(), which will
  1619.     return this value if the communication parameters aren't to its
  1620.     liking.
  1621.  
  1622.   * I added two new procedures in IPXUTIL.C for dealing with
  1623.     IPXADDRFULLs, ipxAddrSocket() and ipxByteSwap().
  1624.  
  1625.  
  1626. Version 0.20, June 1, 1994
  1627.  
  1628. Second public beta release.
  1629.  
  1630. Changes:
  1631.  
  1632.   * The code in IPX.ASM was streamlined considerably, eliminating many
  1633.     small bugs.
  1634.  
  1635.   * ipxStart() was changed from taking no parameters to taking all
  1636.     communication parameters, including a far pointer to memory to
  1637.     use for ECBs, buffers, and so on.  IPXTEST was modified so that
  1638.     if DEBUG is defined it passes a pointer to an IPXDATA structure
  1639.     to use for communication memory; it will allocate memory from
  1640.     the heap instead if DEBUG is not defined.
  1641.  
  1642.   * IPXDATA.C was eliminated; all communication data is now passed as
  1643.     variables to ipxStart(), including a pointer to memory that is used
  1644.     for the data that formerly was in this file.
  1645.  
  1646.   * Code was added to keep track of the maximum number of ECBs that have
  1647.     been used.  IPXTEST was upgraded to display or reset this information
  1648.     and to send it to other IPXTEST users.
  1649.  
  1650.   * Two new IPXLIB error codes were added, ipxeBADCOMMPARMS and
  1651.     ipxeMEMTOOSMALL, which ipxStart() can return if the communication
  1652.     parameters given are wrong or if the size of the memory block given
  1653.     isn't big enough to hold everything, respectively.  This shifted the
  1654.     values of all the other error codes.
  1655.  
  1656.   * The ECB pointer field in the IPXEVENT structure was changed from a
  1657.     far (4-byte) to a near (2-byte) pointer.
  1658.  
  1659.   * IPXLIB was tested with Microsoft C++ version 8.0 and proven to work
  1660.     in all memory models except Tiny.  IPXTEST was modified to work with
  1661.     Microsoft C as well, although a few minor things didn't get ported,
  1662.     like the variable-length wait before sending a ping response and
  1663.     screen scrolling, because there weren't functions in the Microsoft
  1664.     run-time libraries equivalent to the ones I used in Borland C.
  1665.  
  1666.   * "Flurry mode," that is to say, sending as many packets as time will
  1667.     allow, was added to IPXTEST, so as to stress-test IPXLIB.
  1668.  
  1669.   * IPXTEST can now be "remote controlled:" It attempts to interpret the
  1670.     text of broadcast messages and directed messages as commands.
  1671.  
  1672.   * Several extra IPX programming considerations were added to the IPXTEST
  1673.     documentation.
  1674.  
  1675.  
  1676. Version 0.10, May 27, 1994
  1677.  
  1678. First public beta release.
  1679.