Novell is now a part of Micro Focus

Novell Directory Services Q & A

Articles and Tips: article

JOHN BUCKLE
Developer Support Engineer
Developer Support

01 Jun 1997


Q & A

Q. Where did NWGetPreferredDSServer()disappear to?

A.NWGetPreferredDSServer()went to the great API library in the sky for obsolete functions. Unlike the other functions that became obsolete on 1/1/97, this function did not get replaced since it has no place in the multiple tree clients available now.

The functionality of NWGetPreferredDSServer() has been incorporated into several other functions depending on what is trying to be achieved.

To find out which connections are NDS connections use the functions NWCCScanConnRefs() and NWCCGetConnRefInfo()or NWCCGetAllConnRefInfo(). These functions can be used to get connection status (attached, authenticated, licensed) and the tree name.

To find a DS server that has a copy of an NDS object use NWDSResolveName(). This function will return a connection handle to a server that has a copy of the object. The functions NWDSGetServerDN()and NWDSGetServerAddress() can be used to get the name and address of the server from the connection handle.

To find out which server was last used to service an NDS request it is possible to use the key DCK_LAST_CONNECTIONwith NWDSGetContext().This will return the connection handle to the server that was used in the last request. The server name and address can be obtained using the same techniques as above. For this to work the context has to be used in an NDS request; it is insufficient to just set the tree name or context using NWDSSetContext().

The above functions are demonstrated in Listing 1.

Q. Why has the tab for "Foreign Email" disappeared from the new versions of NWAdmin?

A. The "Foreign Email" tab has gone to the great Tab Collection in the sky. The original version of NWAdmin had no provision for snapin tabs. Hence, to allow administrators to set the E-mail Address attribute the "Foreign Email" tab was included. Now that snapins are available, software vendors should provide their own tab pages to record Email information.

Q. Is it possible to call NWDSList() recursively and perform a depth first search of an NDS tree?

A. Yes. You have to reallocate the output buffer on each recursive call and use a different iteration handle, but apart from that there are no problems in calling NWDSList() while in a NWDSList() loop. Listing 2 uses recursion to perform a depth first search of the tree.

An alternative approach is to use NWDSSearch() to scan the whole tree. In this case the filter buffer is set to detect objects that have the "Object Class" property defined. Given that "Object Class" is mandatory for all objects this filter will catch all objects. This technique is used in Listing 3. Using NWDSSearch() also produces a depth first search.

Q. A client application is getting ERR_INSUFFICIENT_BUFFER (FD77) error while creating thousands of user objects. According to the documentation this indicates that the server is out of memory. However, the server has 128MB of RAM and is not out of memory, so what's wrong?

A. Two possible problems. The server could be running out of synchronization buffer space trying to synchronize the DIB with other servers in the replica ring. If the error occurs part way through the user installation, then add delays to allow the servers to synchronize. If the error occurs on certain objects, then check that a null pointer has not been passed for an attribute value.

Listing 1

/*

** NEAREST NDS SERVER.

**

** Finds the nearest NDS server for a given tree

**

** usage: NEAREST treename [objectname [context]]

*/



#include <stdio.h<<
#include <stdlib.h<<
#include <string.h<<


#include <nwdsdc.h<<
#include <nwdsdsa.h<<
#include <nwdsconn.h<<
#include <nwdsmisc.h<<
#include <nwdsname.h<<
#include <nwmisc.h<<
#include <nwdserr.h<<
#include <nwclxcon.h<<


NWDSContextHandle   Handle = (NWDSContextHandle) ERR_CONTEXT_CREATION ;



NWDSCCODE InitialiseNDS();

NWDSCCODE TerminateNDS();

char * PrintServer(NWCONN_HANDLE conn) ;



int Usage()

{

   printf("usage: NEAREST treename [objectname [context]]\n") ;

   return TerminateNDS() ;

}



int Error(char * message, NWCCODE ccode = 0)

{

   printf(message,ccode) ;

   return TerminateNDS() ;

}



int main(int argc, char * argv[])

{

NWCONN_HANDLE conn = 0 ;

NWCCODE       ccode = 0 ;

nuint32       objectID = 0 ;

char          context[256] ;

char          userName[256] ;



   if (NWCallsInit(0,0) || NWNetInit(0,0))

      return Error("Cannot initialise interface to the network\n") ;



   if (InitialiseNDS())

      return Error("Cannot initialise interface to NDS\n") ;



   if (argc < 2 || argc > 4)

      return Usage() ;



   strcpy(userName,(argc > 2) ? argv[2] : DS_ROOT_NAME) ;



   if ((ccode = NWDSSetContext(Handle,DCK_TREE_NAME,argv[1])) != 0)

          return Error("Cannot  set tree name: error %x\n",ccode) ;



   NWDSSetContext(Handle,DCK_NAME_CONTEXT,(argc > 3) ?

      argv[3] : DS_ROOT_NAME) ;



   if ((ccode = NWDSResolveName(Handle,userName,&conn,&objectID)) == 0)&
      printf("Object %s is located on %s\n",

         userName,PrintServer(conn)) ;

   else

      printf("Cannot resolve object %s: error %x\n",userName,ccode) ;



   if ((ccode = NWDSGetPartitionRoot(Handle,userName,context)) == 0 &&

       (ccode = NWDSGetContext(Handle,DCK_LAST_CONNECTION,&conn)) == 0)&
      printf("Partition root for %s is %s, located on %s\n",

         userName,context,PrintServer(conn)) ;

   else

      printf("Cannot find partition root for %s: error %x\n",

         userName,ccode) ;



   return TerminateNDS() ;

}



NWDSCCODE InitialiseNDS()

{

   if ((Handle = NWDSCreateContext()) == ERR_CONTEXT_CREATION)

      return ERR_CONTEXT_CREATION ;



   return 0 ;

}



NWDSCCODE TerminateNDS()

{

   if (Handle != ERR_CONTEXT_CREATION) NWDSFreeContext(Handle) ;



   return 0 ;

}



char * PrintServer(NWCONN_HANDLE conn)

{

static char serverName[48] ;



   if (NWCCGetConnInfo(conn,NWCC_INFO_SERVER_NAME,48,serverName))

      strcpy(serverName,"Error") ;



   return serverName ;

}

Listing 2

NWDSCCODE RList(char * context)

{

Buf_T * output ;



   NWDSAllocBuf(DEFAULT_MESSAGE_LEN,& output) ;& output) ;


   nint32  iterationHandle = NO_MORE_ITERATIONS ;

   nuint32 objCount = 0 ;

   nuint32 attrCount = 0 ;

   char    objName[MAX_DN_CHARS+1] ;



   Object_Info_T objInfo ;



   do {

      if (NWDSList(Handle,context,& iterationHandle,output)) break ;& iterationHandle,output)) break ;


      NWDSGetObjectCount(Handle,output,& objCount) ;& objCount) ;


      for (nuint32 i = 0 ; i < objCount ; i++){

         NWDSGetObjectName(Handle,output,objName,

            & attrCount,& objInfo) ;& attrCount,& objInfo) ;
         if (context[0])

            strcat(strcat(objName,"."),context) ;

         printf("%s\n",objName) ;

         if (objInfo.subordinateCount){

            RList(objName) ;

         }

      }

   } while (iterationHandle != NO_MORE_ITERATIONS) ;



   NWDSFreeBuf(output) ;



   return 0 ;

}

Listing 3

NWDSCCODE RSearch(char * context)

{

Buf_T * output, * filter ;



   NWDSAllocBuf(DEFAULT_MESSAGE_LEN,& output) ;& output) ;
   NWDSAllocBuf(DEFAULT_MESSAGE_LEN,& filter) ;& filter) ;


   nint32  iterationHandle = NO_MORE_ITERATIONS ;

   nuint32 objCount = 0 ;

   nuint32 attrCount = 0 ;

   nint32  found = 0 ;

   char    objName[MAX_DN_CHARS+1] ;



   Object_Info_T objInfo ;

   Filter_Cursor_T * cursor ;

   NWDSCCODE ccode ;



   NWDSAllocFilter(&cursor);&




   NWDSAddFilterToken(cursor,FTOK_PRESENT, NULL,NULL);

   NWDSAddFilterToken(cursor,FTOK_ANAME,"Object Class",SYN_CLASS_NAME);

   NWDSAddFilterToken(cursor,FTOK_END,NULL,NULL);



   NWDSInitBuf(Handle,DSV_SEARCH_FILTER,filter);

   NWDSPutFilter(Handle,filter,cursor,NULL);



   do {

      if (ccode = NWDSSearch(

         Handle,              // Context handle

         context,             //Base of search

         DS_SEARCH_SUBTREE,   //Search entire subtree

         TRUE,                //Dereference alias objects

         filter,              //Search filter

         TRUE,                //Return attribute names only

         FALSE,               //Return specified attributes 

         NULL,                //No attributes specified

         & iterationHandle,   //Iteration handle

         0x7fffffffL,         //Max objects to return

         & found,             //Number found  

         output)) break ;     //Result buffer



      NWDSGetObjectCount(Handle,output,& objCount) ;& objCount) ;


      for (nuint32 i = 0 ; i < objCount ; i++){

         NWDSGetObjectName(Handle,output,objName,

            & attrCount,& objInfo) ;& attrCount,& objInfo) ;
         printf("%s\n",objName) ;

      }

   } while (iterationHandle != NO_MORE_ITERATIONS) ;

   NWDSFreeBuf(output) ;

   NWDSFreeBuf(filter) ;



   return 0 ;

}

* 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