Setting the Workstation Name Using the Client Connection Services (NWCC) APIs
Articles and Tips: article
Developer Support Engineer
Developer Support
01 Jun 1996
Certain applications based on Microsoft networks require the workstation executing the application to have a name. The name is used by the application in peer-to-peer networks to label and address messages sent between instances of the application. NetWare is based on the client-server paradigm where named clients are not necessary. For these applications to have full functionality on a NetWare network it is necessary to give the workstation a name before the application is started. A possible solution on NetWare networks is to name the workstation using the user's login name or the workstation's IPX node address.
This article describes how to set the workstation name using the NetWare Client Connection Services APIs. These APIs are designed to simplify the process of attaching to servers by introducing a simple Open/Close connection model. In this model a client uses one of the NWCCOpenConn APIs to open a connection and calls NWCCCloseConn to close the connection.
Introduction
Certain applications based on Microsoft networks require the workstation executing the application to have a name. The name is used by the application in peer-to-peer networks to label and address messages sent between instances of the application. NetWare is based on the client-server paradigm where named clients are not necessary. For these applications to have full functionality on a NetWare network it is necessary to give the workstation a name before the application is started. A possible solution on NetWare networks is to name the workstation using the user's login name or the workstation's IPX node address.
The workstation name can be configured using the DOS Int 21h Function 5Eh calls. Sub-function 00h can be used to read the workstation name, and sub-function 01h can be used to set the name. When setting the name the function should be provided with a 15-byte string, padded with spaces and terminated with a null byte. The format of the function calls is given in Figure 1.
Figure 1: Format for function calls.
Int 21 Function 5Eh Subfunction 00h (Get Machine Name) Call with: AH 5Eh AL 00h DS:DX segment:offset of buffer Returns: Carry flag clear if successful, set if not successful AX error code if not successful CH 00h if name not defined, non zero if name defined DS:DX segment:offset of buffer Int 21 Function 5Eh Subfunction 01h (Set Machine Name) Call with: AH 5Eh AL 01h DS:DX segment:offset of buffer Returns: Carry flag clear if successful, set if not successful AX error code if not successful DS:DX segment:offset of buffer
As suggested earlier, a good name for a workstation on a NetWare network is the user's login name or the workstation's IPX node address. Note that the term login name is used rather than simply username because a workstation can be attached to several servers using different usernames. The login name will refer to the username on the workstation's primary server, defined in the Client Functions manual as: The primary connection identifies the server that the user originally logged in to. For NDS, this is the connection with the writeable replica used during login.
While the login name is more readable it is not necessarily unique on the network since a user can log in from multiple workstations.
A simple way to generate a unique workstation name is to use the workstation's node address. In the case of NetWare networks this is best achieved by using the IPX node address, which is a six-byte field normally associated with the workstation's media access control address. The six-byte field can be written as a twelve-character hexadecimal number, which corresponds well with the maximum 15-byte string used by DOS.
NetWare Client Connection Services APIs
Novell has introduced a new set of connection APIs for clients. These APIs are designed to simplify the process of attaching to servers by introducing a simple Open/Close connection model. In this model a client uses one of the NWCCOpenConn APIs to open a connection and calls NWCCCloseConn to close the connection. There is now no need to test to see if a connection already exists to the server before opening a connection, nor worry about closing a connection that might be in use elsewhere. The NWCC APIs track all connection handles to servers and will only close a connection once it is no longer in use.
Several of the older connection APIs are now obsolete. These include some of the author's favourite APIs, such as NWAttachToFileServer, NWGetDefaultConnectionIDand NWGetConnectionHandle. These APIs have now been replaced by NWCC APIs and should no longer be used.
The procedure of getting the username from the primary connection is given in Figure 2. A handle to the primary server is obtained by getting a connection reference to the server using NWCCGetPrimConnRef and then opening a connection using NWCCOpenConnByRef. Connection references provide an efficient means to cache information about a server to which connections are being frequently made.
The username for a server connection is obtained by getting the connection number of the connection using NWCCGetConnRefInfo and then getting the information about the connection number using NWGetConnectionInformation. Connection handles should be treated as a limited resource; hence once the information has been obtained the connection handle should be closed using NWCCCloseConn.
Figure 2: Obtaining a username from the primary connection.
nuint32 connRef = 0L ; nuint connNumber = 0 ; NWCONN_HANDLE connHandle = 0 ; char userName[48] ; if (NWCallsInit(0,0)) return exitError("Initialisation error") ; if (NWCCGetPrimConnRef(& connRef) || NWCCOpenConnByRef(connRef,NWCC_OPEN_UNLICENSED,0,& connHandle)) return exitError("No primary connection") ; if (NWCCGetConnRefInfo(connRef,NWCC_INFO_CONN_NUMBER, sizeof(connNumber),& connNumber) || NWGetConnectionInformation(connHandle,connNumber, userName,0,0,0)){ NWCCCloseConn(connHandle); return exitError("Cannot determine user name") ; } NWCCCloseConn(connHandle);
The process of getting a workstation's IPX node address is fairly straightforward and is given in Figure 3. The client transport APIs can be used to return the ten-byte IPX address. The first four bytes are the network address; the remaining six are the node address. The code in Figure 3 will only compile on the DOS platform since the function prototypes are different for Windows and OS/2. A platform-independent method to get the IPX address is to ask the server for the workstation address. This method requires the workstation to have a connection to a server, which might not be the case in a peer-to-peer environment.
Figure 3: Obtaining a workstation's IPX node address.
BYTE address[10] ; char addrName[32] ; IPXInitialize() ; IPXGetInternetworkAddress(address); sprintf(addrName,"%02x%02x%02x%02x%02x%02x", address[4],address[5],address[6], address[7],address[8],address[9]);
WORKNAME Utility
The above code has been combined into a simple DOS utility that can be used in a workstation's AUTOEXEC or user's login script to set the machine name. The utility has been combined with two other means of specifying the workstation name, by command line argument or from an environment variable. The usage description is given in Figure 4.
Figure 4: Usage description.
usage: WORKNAME [-login] [-envir variable] [-nic] [name] No parameters - display machine name -login - set machine name to user's login name -envir - set machine name to environment variable -nic - set machine name to node address name - set machine name to name.
In the source code the Borland function intdos is used to execute an interrupt 21 in DOS. A different method will have to be used for other compile vendors. The object code has to be linked with the following NetWare libraries: caldos16.lib, clndos16.lib, clxdos16.lib, locdos16.lib, ncpdos16.lib, lnwipxsp.lib.
Listing 1: Workname.cpp
/* ** WORKNAME - Get andSet a Workstation Machine Name ** ** John Buckle, Novell Inc: ** ** WORKNAME [-login] [-envir variableName] [-nic] [workstationName] ** ** With no arguments, WORKNAME prints the workstation name using the ** DOS Int 21 call 5e00. When given a single argument not begining with ** a minus symbol, WORKNAME sets the workstation name the argument using ** the DOS Int 21 call 5e01. The following arguments set the workstation ** name to the following values: ** -login Login name of users on the primary connection. ** -envir Value of environment variable. ** -nic Value of IPX node address. */ # define NWDOS # include <stdio.h<<< # include <string.h<<< # include <stdlib.h<<< # include <dos.h<<< # include <nwclxcon.h<<< # include <nwipxspx.h<<< # include <nwconnec.h<<< # include <nwmisc.h<<< # define MaxCharacters 14 /* ** The buffer used to pass the machine name should be declared global or static ** so that it is in the data segement and not on the stack. */ char Buffer[MaxCharacters+1]; /* ** char * usageStrings[] */ char * usageStrings[] = { "usage: WORKNAME [-login] [-envir variable] [-nic] [name]\n","" " No parameters - display machine name\n","" " -login - set machine name to user's login name\n","" " -envir - set machine name to environment variable\n","" " -nic - set machine name to node address\n","" " name - set machine name to name.\n","" 0 } ; /* ** int usage(int ccode) ** ** Display usage information. */ int usage(int ccode) { for (int i = 0 ; usageStrings[i] ; i++) fputs(usageStrings[i],stderr); return ccode ; } /* ** int exitError(char * message) ** ** Display error message and exit. */ int exitError(char * message) { fprintf(stderr,"WORKNAME: %s\n",message) ;"" return 1 ; } /* ** int setMachineName(char * name) ** ** Set the machine name using DOS Int 21 call 5e01 to the specified ** string. The name has to be 14 characters padded with spaces. */ int setMachineName(char * name) { REGS regs ; memset(Buffer,' ',MaxCharacters); for (int i = 0 ; i < MaxCharacters<< * name ; i++)<< Buffer[i] = * name++; Buffer[MaxCharacters] = 0 ; regs.x.ax = 0x5E01 ; regs.x.cx = 0x0101 ; regs.x.dx = FP_OFF(Buffer); return intdos(®s,®s);&& } /* ** int getMachineName() ** ** Get the machine name using DOS Int 21 call 5e00. */ int getMachineName() { REGS regs ; regs.x.ax = 0x5E00 ; regs.x.dx = FP_OFF(Buffer); int ccode = intdos(®s,®s);&& // CH register is set if a machine name has been defined. If no // machine name has been defined then CH is zero. if (regs.h.ch) puts(Buffer) ; return ccode ; } /* ** int setEnvirName(char * envirVariable) ** ** Get the value of the environment variable and pass it onto ** setMachineName(). */ int setEnvirName(char * envirVariable) { char * value = getenv(strupr(envirVariable)); if (value == 0) return exitError("Environment variable not set") ;"" return setMachineName(value); } /* ** int setLoginName() ** ** Get the primary connection handle using the primary reference. Once ** the connection handle has been obtained, get the user's login name. */ int setLoginName() { nuint32 connRef = 0L ; nuint connNumber = 0 ; NWCONN_HANDLE connHandle = 0 ; char userName[48] ; NWCallsInit(0,0) ; if (NWCCGetPrimConnRef(& connRef) ||&& NWCCOpenConnByRef(connRef,NWCC_OPEN_UNLICENSED,0,& connHandle))&& return exitError("No primary connection") ;"" if (NWCCGetConnRefInfo(connRef,NWCC_INFO_CONN_NUMBER,sizeof(connNumber),& connNumber) ||&& NWGetConnectionInformation(connHandle,connNumber,userName,0,0,0)){ NWCCCloseConn(connHandle); return exitError("Cannot determine user name") ;"" } NWCCCloseConn(connHandle); return setMachineName(userName); } /* ** int setAddressName() ** ** Get the workstation IPX address. The address consists of a four byte ** network address and six byte node address. The network address is ** not used since it is not unique to the workstation. */ int setAddressName() { BYTE address[10] ; char addrName[32] ; IPXInitialize() ; IPXGetInternetworkAddress(address); sprintf(addrName,"%02x%02x%02x%02x%02x%02x","" address[4],address[5],address[6], address[7],address[8],address[9]); return setMachineName(addrName); } /* ** int main(int argc, char * argv[]) ** ** Parse command line arguments and call appropriate handler. */ int main(int argc, char * argv[]) { if (argc == 1) return getMachineName(); if (argv[1][0] == '/' || argv[1][0] == ' '){ switch (argv[1][1]) { case '?': case 'h': case 'H': return usage(0) ; case 'e': case 'E': return (argc == 3) ? setEnvirName(argv[2]) : usage(1) ; case 'l': case 'L': return setLoginName() ; case 'n': case 'N': return setAddressName() ; } } return setMachineName(argv[1]); }
* 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.