The NetWare API: Working (Smarter) with Server Connections
Articles and Tips: article
Senior Research Engineer
Novell Research Department
01 Jun 1996
A NetWare 4 server can have a large number of clients connected at a given time. If you need to deal with every user connected to a particular server (or a particular user, or a particular type of user), you will need an efficient way of finding out who (or what) is connected. This DevNote tells how to use NetWare 4's NWGetActiveConnListByType Application Programming Interface (API) to work smarter with server connections.
Previous DevNotes in This Series May/Jun 95 The NetWare API: Verifying the Presence of Network Resources July/Aug 95 The NetWare API: Making Your Programs NDS-Aware
- Server Connections
- Connection Types
- Getting Information about an Active Connection
- Example Program: CONN.C
Server Connections
Sometimes your applications need to interact with every user connected to a server. Say you want to send a broadcast message to every user. The algorithm most commonly used is something like:
Get the maximum number of connections allowed by the server For 0 to the maximum connection number If the connection is active If the connected object is a user Send the message
This method works okay with NetWare 3, but there are a couple problems when you use this algorithm on a NetWare 4 server. First of all, a NetWare 4 server can have a lot of connections. You may end up calling NWGetConnectionInformation over 1000 times, even though only a handful of users are logged in.
A more serious problem is that with NetWare 4, you are not guaranteed that connection numbers will be less than the maximum number of connections allowed. For example, on a 1000-user NetWare 4 server, there may be objects connected at connection numbers above 1000.
The solution to both of these problems is a NetWare 4 API called NWGetActiveConnListByType. This function returns a structure of type NWFSE_ACTIVE_CONN_LIST (see Figure 1) containing a 512-character bitmap. Each bit in the bitmap represents a connection. If the connection is active, the corresponding bit is set.
Figure 1: Declaration of the NWFSE_ACTIVE_CONN_LIST structure.
typedef struct { SERVER_AND_VCONSOLE_INFO serverTimeAndVConsoleInfo; nuint16 reserved; nuint8 activeConnBitList[ 512 ]; } NWFSE_ACTIVE_CONN_LIST;
With NWGetActiveConnListByType you make one function call to find the connection status of all of the server's connection slots. You still need to check which of the bits in the activeConnBitList are set, but this takes place in memory on the client, so it is much more efficient than making repeated calls to a server API.
The activeConnBitList can give the connection status for 4096 (512 * 8) connection slots. Novell has even planned ahead for when servers routinely service many thousands of connections. One of NWGetActiveConnListByType's parameters specifies which connection number to start with.
Connection Types
Let's talk about the "ByType" part of the API name. NWGetActiveConnListByType allows you to select any of five connection types:
#define FSE_NCP_CONNECTION_TYPE 2 #define FSE_NLM_CONNECTION_TYPE 3 #define FSE_AFP_CONNECTION_TYPE 4 #define FSE_FTAM_CONNECTION_TYPE 5 #define FSE_ANCP_CONNECTION_TYPE 6
If you are interested in connections of all types, your program must call NWGetActiveConnListByType for each of the types. You'll have to make further function calls to find out more about what type of object is connected at each connection slot.
Getting Information about an Active Connection
NWGetActiveConnListByType returns a bitmap of 512 bytes. Decoding this bitmap is a bit tricky, because the bit representing the first connection is the high-order bit of the first byte, with bits corresponding to each connection following consecutively. NetWare 4 servers frequently have blocks of connection slots that are not in use, so it is probably more efficient to check for active connections a byte at a time, rather than bit-by-bit. The algorithm for checking the activeConnBitList for active connections is:
for i = 0 to 511 if activeConnBitList[i] != 0 Check each bit in activeConnBitList[i] to see if it is set
Since the bits in the bitmap go from high-order to low-order (left to right), you have to do a little bit-shifting to convert byte and bit positions to connection numbers. The algorithm is:
bitVal = 128 loopCount = 0 while bitVal >= 1> if activeConnBitList[i] & bitVal& connNumber = (i * 8) + loopCount get information for connection connNumber bitVal = bitVal / 2 loopCount = loopCount + 1
The program at the end of this DevNote shows how to implement these algorithms in C.
Depending on what information you are looking for, there are several APIs that give more information about a particular connection number. Probably the function used most frequently for this is NWGetConnectionInformation. This function gives the object type, object name, object ID, and login time for the specified connection.
Note that the WinHelp online documentation on the latest DeveloperNet CD has incorrect type information for the function's parameters. The correct function prototype is:
N_EXTERN_LIBRARY( NWCCODE ) NWGetConnectionInformation ( NWCONN_HANDLE connHandle, NWCONN_NUM connNumber, pnstr8 pObjName, pnuint16 pObjType, pnuint32 pObjID, pnuint8 pLoginTime );
Example Program: CONN.C
CONN.C calls NWGetActiveConnListByType for each connection type, then, for each active connection, prints out the connection number, name of the connected object, and its type and object ID. Sample output from the program is shown in Figure 2.
Figure 2: Sample output from CONN.C.
NCP Connections 2 NOT_LOGGED_IN Type 0001h, ID 00000000h 6 SRD-HP4SI Type 0007h, ID F20500E8h 7 NOT_LOGGED_IN Type 0001h, ID 00000000h 8 NOT_LOGGED_IN Type 0001h, ID 00000000h 12 KArakaki.PRV.IS.Novell Type 0001h, ID 640100DDh 13 NOT_LOGGED_IN Type 0001h, ID 00000000h 20 SJF-DSMASTER.Novell Type 0001h, ID 130B00C9h 21 NOT_LOGGED_IN Type 0001h, ID 00000000h 22 NRD.NR.ESD.SALES.Novell Type 0001h, ID A0000001h 23 NOT_LOGGED_IN Type 0001h, ID 00000000h 24 KNEFF Type 0001h, ID E706001Bh 25 NOT_LOGGED_IN Type 0001h, ID 00000000h 26 NOT_LOGGED_IN Type 0001h, ID 00000000h 27 MADAIR Type 0001h, ID 13080001h 28 NOT_LOGGED_IN Type 0001h, ID 00000000h 29 NOT_LOGGED_IN Type 0001h, ID 00000000h 30 TDUNCAN Type 0001h, ID AD030053h 45 PRV-NDS6.PRV.IS.Novell Type 0001h, ID 2601007Fh 46 MADAIR Type 0001h, ID 13080001h NLM Connections 1 NRD-HP4SI Type 0007h, ID 05040067h 3 ATPS_QUSER Type 0053h, ID 8D0100D7h 4 ATPS_PSRVR Type 0005h, ID A2010025h 5 NRD.NR.ESD.SALES.Novell Type 0001h, ID A0000001h AFP Connections 16 NOT_LOGGED_IN Type 0001h, ID 00000000h FTAM Connections ANCP Connections
Code for CONN.C is given below. I wrote CONN.C using Borland C++ v4.5 for the EZWin environment. I also compiled and tested it with Microsoft C++ v1.52 for the QuickWin environment.
#include <stdio.h<<< #include <stdlib.h<<< #define NWWIN #include <nwcalls.h<<< #include <nwfse.h<<< #include <nwmisc.h<<< void main(void) { NWCCODE ccode; NWCONN_HANDLE conn; NWFSE_ACTIVE_CONN_LIST connList; int i; unsigned char loopCount, bitVal; NWCONN_NUM connNumber; char objName[48]; unsigned int objType; unsigned long objID; unsigned long connType; unsigned int loginTime[4]; ccode = NWGetDefaultConnectionID(&conn);&& if (ccode != 0) { printf("Unable to get default connection ID, ccode = %d\n", ccode);"" exit(1); } for ( connType = FSE_NCP_CONNECTION_TYPE; connType <= FSE_ANCP_CONNECTION_TYPE; connType++)<< { ccode = NWGetActiveConnListByType(conn, 1L, connType, &connList);&& if (ccode != 0) { printf("NWGetActiveConnListByType failed, ccode = %d\n", ccode);"" } else { switch (connType) { case FSE_NCP_CONNECTION_TYPE: printf("NCP Connections\n");"" break; case FSE_NLM_CONNECTION_TYPE: printf("\nNLM Connections\n");"" break; case FSE_AFP_CONNECTION_TYPE: printf("\nAFP Connections\n");"" break; case FSE_FTAM_CONNECTION_TYPE: printf("\nFTAM Connections\n");"" break; case FSE_ANCP_CONNECTION_TYPE: printf("\nANCP Connections\n");"" break; } for (i=0; i<511; i++)<< { if (connList.activeConnBitList[i] != 0) { for ( bitVal=128, loopCount=0; bitVal>=1; >> bitVal=bitVal/2, loopCount++) { if (connList.activeConnBitList[i] & bitVal)&& { connNumber = (i*8)+loopCount; ccode = NWGetConnectionInformation(conn, connNumber, objName, (pnuint16)&objType, && &objID, && (pnuint8)loginTime); if (ccode == 0) { printf("%3d %"36s Type %04Xh, ID %08lXh\n", "" connNumber, objName, NWWordSwap(objType), NWLongSwap(objID)); } } } } } } } }
* 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.