Novell is now a part of Micro Focus

The NetWare API: Working (Smarter) with Server Connections

Articles and Tips: article

MORGAN B. ADAIR
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

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.

© Copyright Micro Focus or one of its affiliates