The NetWare API: Verifying the Presence of Network Resources
Articles and Tips: article
Senior Research Engineer
Novell Research Department
01 May 1995
This DevNote is the first in a series on programming the NetWare API. It tells how your programs can verify whether IPX, the NetWare shell or requester, and the NetBIOS emulator are loaded. Subsequent articles will cover a variety of NetWare programming concepts.
- A DOS Application's Operating Environment
- Detecting IPX/SPX
- Detecting the NetWare Shell or Requester
- Detecting NetBIOS
- File Server Connections
- More Information on Connections
- Example Program: CLIENT.C
A DOS Application's Operating Environment
Taken together, DOS, the NetWare client software, and the hardware they run on comprise an operating environment that contains a number of variables. Applications frequently need to be aware of features of the underlying hardware: the amount of memory, the display adapter, the number and type of disk drives. The various versions of DOS add another set of variables to the operating environment. And when a network is added to the equation, the possible combinations of hardware, operating system, and network resources a program may have to operate under can become innumerable.
Naturally, programmers want to take advantage of all the facilities of the operating environment that will add functionality to their products, especially when a program is being developed for commercial release. At the same time, programmers want their software to be compatible with as many combinations of hardware, operating system versions, and network operating system versions as possible.
You probably have encountered programs that make assumptions about the operating environment. For example, many programs assume that the computers they run on have one floppy drive (A:) and one hard drive (C:). Other programs assume that if they send ANSI escape sequences to the console device, they will be handled correctly by the console device driver. Before a program attempts to access network resources, it should be sure that those resources exist. A program that simply assumes that IPX and the NetWare shell or requester are present can hang the workstation it is running on.
The program given in the listing at the end of this DevNote (CLIENT.C) illustrates how a program can verify the existence of basic network facilities. Source code for this program can be downloaded from CompuServe's NOVLIB Forum, Library 11. CLIENT.C was compiled and tested using Borland C++ v4.0, and the Novell Client SDK CD, Volume 3.
Detecting IPX/SPX
The NetWare C Interface provides two routines, IPXInitialize and SPXInitialize, that can be used to verify that IPX and SPX are loaded. IPXInitialize just returns an integer indicating whether IPX is present. SPXInitialize takes four parameters that receive information about the version of SPX that is installed - the major and minor version numbers, the maximum number of connections supported, and the number of available SPX connections. EXIST.C passes NULLs in these parameters, because it is only interested in the value returned by SPXInitialize - if it returns zero, SPX is not installed; if it returns 255, SPX is installed.
If your application needs to know which version of IPX and SPX is installed, it can use functions provided by the NetWare C Interface's Diagnostic Services. Have your application use the Diagnostic Services to send a diagnostic packet to the calling workstation that returns the IPX and SPX version numbers. The algorithm is as follows:
Get the internet work address of the workstation's network interface card by calling IPXGetInternetworkAddress.
Pass the internetwork address to BeginDiagnostics to establish a connection. BeginDiagnostics returns a connection number and a list of network components (IPX/SPX, shell driver, nondedicated file server, and so on) on the target workstation, which in this case is also the calling workstation.
Pass the component list to FindComponentOffset to get the offset of the IPX/SPX data in the component list.
Pass the offset to GetIPXSPXVersion to get the major and minor version numbers for IPX and SPX from the componentlist.
Call EndDiagnostics to close the connection established by BeginDiagnostics.
Detecting the NetWare Shell or Requester
To detect the presence of the NetWare shell (NETX) or requester (VLM), simply call NWGetDefaultConnectionID. If the value returned is zero, the shell has not been loaded. If the shell has been loaded, the function will return the connection ID for the default file server, a value that ranges from 1 to 8. More information on file server connection IDs is given in the section "File Server Connections" below.
NWGetDefaultConnectionID simply calls DOS function F0h, subfunction 2h. Since this function is not used by DOS, it normally returns zero in the AL register. If the NetWare shell has intercepted the DOS interrupt vector, or if DOS has redirected the interrupt to the NetWare requester, the interrupt returns the connection ID for the default server.
Detecting NetBIOS
To detect the presence of NetBIOS or Novell's NetBIOS emulator, an application simply needs to check the value of the interrupt service vector used by NetBIOS. DOS function 35h returns a pointer to the interrupt service routine (ISR) for a specified interrupt. To see if NetBIOS is installed, call DOS function 35h by doing the following:
Move 35h to register AH to specify which DOS function to call.
Move 5Ch to register AL to specify which interruptvector to get.
Generate a DOS interrupt 21h.
Check the value returned in ES.
If the segment value returned in ES is zero or F000h, NetBIOS is not loaded. If any other value is returned, it is a pointer to the segment where NetBIOS's ISR is loaded in memory.
File Server Connections
When loaded into memory, the NetWare shell or requester attempts to establish a connection with a file server. If successful, it maintains a data structure containing connection status information for each file server connection. CLIENT.C examines each connection ID to see if it contains an active connection. If so, it displays the file server name from the corresponding entry in the file server name table and the name of the user logged in on the connection.
The NetWare shell has eight slots in its connection ID table. The requester by default allows eight file server connections, but can be configured to allow more or fewer. For this reason, CLIENT.C calls NWGetMaximumConnections to determine how many connections the client might have.
More Information on Connections
Watch for the next article in The NetWare API series; it will have more information about network (NDS) and file server (bindery) connection management.
Example Program: CLIENT.C
/***************************************************************************** * File: CLIENT.C * Author: Morgan B. Adair, Novell, Inc. * Date: 5/29/95 *****************************************************************************/ #include <stdio.h<< #include <stdlib.h<< #include <nwcalls.h<< #include <nwerror.h<< #include <nxtd.h<< #include <diag.h<< #include <dos.h<< void main(void) { BYTE componentList[54]; BeginDiagnosticStruct networkAddress; int connection; int component; AllResponseData response; IPXSPXVersion responseData; NWCCODE ccode; WORD connectionNum; NWCONN_HANDLE connectionID; union REGS regs; struct SREGS sregs; char serverName[48]; BYTE majorVer, minorVer, revLevel; char name[48]; NWNUMBER maxConnections; CONNECT_INFO connInfo; ccode = NWCallsInit(NULL, NULL); if (ccode) { printf("Error initializing NetWare program call interface\n"); exit(1); } /* IPX/SPX present */ if (IPXInitialize() == 240) printf("IPX is NOT loaded.\n"); else { printf("IPX IS loaded.\n"); if (SPXInitialize(NULL, NULL, NULL, NULL) == SPX_NOT_INSTALLED) printf("SPX is NOT loaded.\n"); else printf("SPX IS loaded.\n"); /* IPX/SPX Version */ IPXGetInternetworkAddress((BYTE *)&networkAddress);& if (BeginDiagnostics(&networkAddress, &connectionID, componentList) & != SUCCESSFUL) printf("Unable to get IPX/SPX versions\n"); else { component = FindComponentOffset(componentList, IPX_SPX_COMPONENT); if (component == -1) printf("Unable to get IPX/SPX versions\n"); if (GetIPXSPXVersion(connectionID, component, &response, &responseData)& != SUCCESSFUL) printf("Unable to get IPX/SPX versions\n"); else { printf("IPX Version: %d.%02d\n", responseData.IPXMajorVersion, responseData.IPXMinorVersion); printf("SPX Version: %d.%02d\n", responseData.SPXMajorVersion, responseData.SPXMinorVersion); } } EndDiagnostics(connectionID); } /* NetWare DOS Shell (NETX) or Requester (VLM) */ ccode = NWGetDefaultConnectionID(&connectionID);& if (connectionID == NULL) { printf("NetWare shell or requester is NOT loaded.\n"); /* if shell is not loaded, there is nothing left to live for */ return; } else { printf("NetWare shell or requester IS loaded.\n"); ccode = NWGetRequesterVersion(&majorVer, &minorVer, &revLevel);& printf("Shell Version: %d.%d, Rev %c\n", majorVer, minorVer, revLevel+'A'); } /* NetBIOS */ regs.h.ah = 0x35; /* AH = Interrupt 21h Funtion 35h-- Get Interrupt Vector */ regs.h.al = 0x5C; /* AL = Interrupt vector to get */ intdosx(®s, ®s, &sregs);& switch (sregs.es) { /* ES returns segment of pointer to ISR */ case 0x0000 : case 0xF000 : printf("NetBIOS is NOT loaded.\n"); break; default : printf("NetBIOS IS loaded.\n"); } /* Connection Information */ NWGetMaximumConnections(&maxConnections);& for (connection=1; connection<=maxConnections; connection++) {< ccode = NWGetConnectionStatus(connection, &connInfo, sizeof(CONNECT_INFO));& if (ccode == 0) { if (connInfo.connectFlags & CONNECTION_NDS) {& printf("Connection %d has an NDS connection to %s as %s\n", connection, connInfo.serverName, connInfo.clientName); } else if (connInfo.connectFlags & CONNECTION_LOGGED_IN) {& printf("Connection %d is logged in to %s as %s.\n", connection, connInfo.serverName, connInfo.clientName); } } } }
* Originally published in Novell AppNotes
Disclaimer
The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.