richm%stanfordalumni.org dd758b072f initial import of docbook contribution from Sun
git-svn-id: svn://10.0.0.236/trunk@228382 18797224-902f-48f8-a5cc-f745e15eee43
2007-06-20 14:26:52 +00:00

1466 lines
61 KiB
Plaintext

<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-api"><title>Using the LDAP C API</title>
<highlights>
<para>This chapter covers features of the LDAP C API to use when writing
an LDAP client application with &DirectorySDKForC;.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdacv">Synchronous and Asynchronous Functions</olink></para>
</listitem>
<listitem><para><olink targetptr="bdadg">Retrieving SDK Information</olink></para>
</listitem>
<listitem><para><olink targetptr="bdadh">Managing Memory</olink></para>
</listitem>
<listitem><para><olink targetptr="bdadi">Reporting Errors</olink></para>
</listitem>
<listitem><para><olink targetptr="bdadq">Handling Referrals With Directory
SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdady">Creating an In-Memory Cache</olink></para>
</listitem>
<listitem><para><olink targetptr="bdadz">Handling Failover</olink></para>
</listitem>
</itemizedlist>
</highlights>
<indexterm><primary>APIs</primary><secondary>C</secondary></indexterm><indexterm><primary>C API</primary></indexterm>
<sect1 id="bdacv"><title>Synchronous and Asynchronous Functions</title>
<para>You can perform most operations with <firstterm>synchronous</firstterm> or
with <firstterm>asynchronous</firstterm> functions. For example, to search
the directory, you can call either the synchronous <function>ldap_search_ext_s</function> function
or the asynchronous <function>ldap_search_ext</function> function. In general,
all synchronous functions have names that end with <literal>_s</literal>.</para>
<para>The difference between the synchronous and asynchronous functions is
the calling convention. The LDAP exchanges are identical.</para>
<sect2 id="bdacw"><title>Calling Synchronous Functions</title>
<indexterm>
<primary>C SDK</primary>
<secondary>synchronous functions</secondary>
</indexterm>
<para>When you call a <emphasis>synchronous</emphasis> function, your client
waits for the operation to complete before executing any subsequent lines
of code. Synchronous functions return <errorcode>LDAP_SUCCESS</errorcode> when
they are successful. Synchronous functions return an LDAP error code when
they are not successful. The following example deletes the entry in the directory.
</para>
<example id="csdk-call-sync-example"><title>Calling Synchronous <function>ldap_delete_ext_s
</function> to Delete an Entry</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
LDAP *ld;
char *matched_msg = NULL, *error_msg = NULL;
int rc;
...
/* Perform an LDAP delete operation. */
rc = ldap_delete_ext_s( ld, DELETE_DN, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_delete_ext_s: %s\n", ldap_err2string( rc ) );
ldap_get_lderrno( ld, &amp;matched_msg, &amp;error_msg );
if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
/* If the server cannot find an entry with the specified DN,
it may send back the portion of the DN that matches an
existing entry.*/
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
} else {
printf( "%s deleted successfully.\n", DELETE_DN );
}
...</programlisting>
</example>
<para>To see other sample programs that call synchronous functions, view the
source files in the <filename>examples/</filename> directory.</para></sect2>
<sect2 id="bdacx"><title>Calling Asynchronous Functions</title>
<indexterm>
<primary>C SDK</primary>
<secondary>asynchronous functions</secondary>
</indexterm>
<para>When you call an <emphasis>asynchronous</emphasis> function, your client
does not need to wait for the operation to complete. The client can continue
performing other tasks, such as initiating other LDAP operations, while the
asynchronous operation is executing. An asynchronous function passes back
a unique message ID to identify the operation being performed. You can pass
this message ID to the <function>ldap_result</function> function to check
the status of the operation. The following sections explain how to call an
asynchronous function and how to check the results of the operation. To see
other sample programs that call asynchronous functions, view the source files
in the <filename>examples/</filename> directory.</para>
<sect3 id="bdacy"><title>Verifying that an LDAP Request Was Sent</title>
<para>Asynchronous functions return an LDAP result code indicating whether
or not the LDAP request was successfully sent to the server. If the function
returns <errorcode>LDAP_SUCCESS</errorcode>, the function has successfully
sent the request to the server. The following example sends an LDAP delete
request to the server and checks if the result was sent successfully. The
example uses the asynchronous <function>ldap_delete_ext</function> function.</para>
<example id="csdk-call-async-example"><title>Calling Asynchronous <function>ldap_delete_ext
</function> and Sending a Verification</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
/* Change these as needed. */
#define DELETE_DN "uid=wjensen,ou=People,dc=example,dc=com"
...
LDAP *ld;
int rc, msgid;
...
/* Send an LDAP delete request to the server. */
rc = ldap_delete_ext( ld, DELETE_DN, NULL, NULL, &amp;msgid );
if ( rc != LDAP_SUCCESS ) {
/* If the request was not sent successfully,
print an error message and return. */
fprintf( stderr, "ldap_delete_ext: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
...</programlisting>
</example>
</sect3>
<sect3 id="bdacz"><title>Retrieving the Server Response</title>
<para>If the request was sent successfully, the function passes the message
ID of the LDAP operation back to the client. Use the message ID to determine
if the server has sent back results for this operation. Call <function>ldap_result
</function>, passing the message ID as a parameter.</para>
<itemizedlist>
<para>The function then returns one of the following values:</para>
<listitem><para><literal>-1</literal> indicates that an error occurred.</para>
</listitem>
<listitem><para><literal>0</literal> indicates that the time&mdash;out period
has been exceeded and that the server has not yet sent a response back to
your client.</para></listitem>
<listitem><para>Any other value indicates that the server has sent a response
for the requested operation back to your client. The <function>ldap_result</function> parameter
passes back a pointer to an <structname>LDAPMessage</structname> structure.</para>
<itemizedlist>
<para>This structure contains the server&rsquo;s response, which can include
the following information:</para>
<listitem><para>An LDAP result code that specifies the result of the operation
you requested</para><para>See <olink targetptr="bdadi">Reporting Errors</olink> for
details.</para></listitem>
<listitem><para>An additional error message sent back from the server</para>
<para>This information is optional.</para></listitem>
<listitem><para>If the server cannot find the entry specified by a DN, the
portion that identifies an existing entry.</para><para>See <olink targetptr="bdado">Receiving the Matching Portion of a DN</olink> for details.</para>
</listitem>
<listitem><para>A set of referrals, if the server&rsquo;s directory does not
contain the requested entries</para><para>The server must be configured to
return referrals</para><para>See <olink targetptr="bdadq">Handling Referrals
With Directory SDK for C</olink> for details.</para></listitem>
<listitem><para>A set of server response controls that apply to the operation
you requested</para><para>See <olink targetptr="csdk-controls">Chapter&nbsp;16,
LDAP Controls With Directory SDK for C</olink> for information about controls.</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>You can specify a timeout period to wait for results from the server.</para>
<sect4 id="bdada"><title>Polling Loop</title>
<para>You can set up a loop to poll for results while doing other work. The
following example defines a function that does other work while waiting for
the server to send a response back to your client</para>
<example id="csdk-poll-example"><title>Polling for Results</title>
<programlisting>int global_counter = 0;
void do_other_work()
{
global_counter++;
}</programlisting>
</example>
</sect4>
<sect4 id="bdadb"><title><literal>while</literal> Loop</title>
<para>This example sets up a <literal>while</literal> loop to call your function
when you are not checking for the server&rsquo;s response.</para>
<example id="csdk-while-example"><title>Using a <literal>while</literal> Loop
to Handle Results</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
LDAP *ld;
LDAPMessage *res;
LDAPControl **serverctrls;
char *matched_msg = NULL, *error_msg = NULL;
char **referrals;
int rc, parse_rc, msgid, finished = 0;
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
...
/* Send an LDAP delete request to the server. */
rc = ldap_delete_ext( ld, DELETE_DN, NULL, NULL, &amp;msgid );
...
/* Poll the server for the results of the LDAP operation. */
while ( !finished ) {
rc = ldap_result( ld, msgid, 0, &amp;zerotime, &amp;res );
/* Check to see if a result was received. */
switch ( rc ) {
case -1:
.../* An error occurred. */...
case 0:
/* The timeout period specified by zerotime was exceeded, meaning
the server has still not yet sent the results of the delete
operation back to the client. Break out of this switch statement,
and continue calling ldap_result() to poll for results. */
default:
finished = 1;
.../* Your client received a response from the server. */...
}
/* Do other work while waiting. This is called if ldap_result()
returns 0 (before you continue to top of the loop and call
ldap_result() again). */
if ( !finished ) {
do_other_work();
}
...
}
...</programlisting>
</example>
</sect4>
</sect3>
<sect3 id="bdadc"><title>Getting Information From a Server Response</title>
<para>To get information from the server response, call <function>ldap_parse_result
</function> as shown here.</para>
<example id="csdk-parse-result-example"><title>The <function>ldap_parse_result</function> Function
</title>
<programlisting>LDAP_API(int) LDAP_CALL
ldap_parse_result( LDAP *ld, LDAPMessage *res, int *errcodep,
char **matcheddnp, char **errmsgp, char ***referralsp,
LDAPControl ***serverctrlsp, int freeit );</programlisting>
</example>
<itemizedlist>
<para>You can get the following information from parameters of the <function>ldap_parse_result
</function>:</para>
<listitem><para><literal>errcodep</literal> holds the LDAP result code of
the operation that the server finished processing.</para><para>See <olink targetptr="bdadi">Reporting Errors</olink> for details.</para></listitem>
<listitem><para><literal>errmsgp</literal> is an additional error message
that the server can send to your client.</para></listitem>
<listitem><para><literal>matcheddnp</literal> is the portion of the DN that
matches an existing entry. The portion of the DN is used when the server is
not able to find an entry for the DN that you specified.</para><para>See <olink targetptr="bdado">Receiving the Matching Portion of a DN</olink> for details.</para>
</listitem>
<listitem><para><literal>referralsp</literal> is a set of referrals sent back
to your client. The set of referrals is sent if you requested an entry that
is not part of the DIT managed by the server. The server must be configured
to refer clients to other LDAP servers.</para><para>See <olink targetptr="bdadq">
Handling Referrals With Directory SDK for C</olink> for details.</para>
</listitem>
<listitem><para><literal>serverctrlsp</literal> is a set of server response
controls that apply to the operation.</para><para>See <olink targetptr="csdk-controls">Chapter&nbsp;16, LDAP Controls With Directory SDK
for C</olink> for details.</para></listitem>
</itemizedlist>
<para>When processing LDAP search operations, the server can send back individual
entries, individual search references, chains of entries, and chains of search
references.</para>
<para>The following example retrieves error information from an <structname>LDAPMessage
</structname> structure returned by <function>ldap_result</function>.</para>
<example id="csdk-get-error-info-example"><title>Retrieving Error Information
From an <structname>LDAPMessage</structname> Structure</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
LDAP *ld;
LDAPMessage *res;
LDAPControl **serverctrls;
char *matched_msg = NULL, *error_msg = NULL;
char **referrals;
int rc, parse_rc, msgid, finished = 0;
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
...
rc = ldap_result( ld, msgid, 0, &amp;zerotime, &amp;res );
/* Check to see if a result was received. */
switch ( rc ) {
case -1:
...
case 0:
...
default:
...
/* Call ldap_parse_result() to get information from the results
received from the server. */
parse_rc = ldap_parse_result( ld, res, &amp;rc, &amp;matched_msg,
&amp;error_msg, &amp;referrals, &amp;serverctrls, 1 );
/* Make sure the results were parsed successfully. */
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n",
ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Check the results of the LDAP operation. */
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "Error: %s\n", ldap_err2string(rc));
if ( error_msg != NULL &amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
/* If the server returned the portion of the DN
that identifies an existing entry, print it out. */
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
} else {
printf( "Operation completed successfully" );
}
}
...</programlisting>
</example>
</sect3>
<sect3 id="bdadd"><title>Freeing an <structname>LDAPMessage</structname> Structure
</title>
<para>When you are done, call <function>ldap_msgfree</function> to free the <structname>
LDAPMessage</structname> structure unless the structure is part of a chain
of results. The result code returned by this function is not the same as the
result code of the operation, <parameter>errcodep</parameter>. This operation
returns a result code that indicates the type of operation to which the freed <structname>
LDAPMessage</structname> structure is a response.</para>
<para>If you pass a non-zero value for the <parameter>freeit</parameter> parameter
of <function>ldap_result</function>, the structure is automatically freed
after the information is retrieved.</para></sect3>
<sect3 id="bdade"><title>Canceling an Operation in Progress</title>
<para>If you need to cancel an LDAP operation, call <function>ldap_abandon_ext</function>.
The function returns <literal>LDAP_SUCCESS</literal> if successful, or an
LDAP result code if an error occurs. After you cancel an operation, you cannot
retrieve the results of that operation. Thus, calling <function>ldap_result</function> does
not return any results.</para></sect3>
<sect3 id="bdadf"><title>Sample Code to Call an Asynchronous Function</title>
<indexterm>
<primary>example programs</primary>
<secondary>asynchronous deletion of an entry</secondary>
</indexterm>
<para>The following example calls <function>ldap_delete_ext</function> to
delete an entry in the directory, and <function>ldap_result</function> within
a loop to poll the results of the delete.</para>
<example id="csdk-async-delete-example"><title>Performing Asynchronous Deletion
of an Entry</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
void do_other_work();
int global_counter = 0;
...
/* Change these as needed. */
#define DELETE_DN "uid=wjensen,ou=People,dc=example,dc=com"
...
LDAP *ld;
LDAPMessage *res;
LDAPControl **serverctrls;
char *matched_msg = NULL, *error_msg = NULL;
char **referrals;
int rc, parse_rc, msgid, finished = 0;
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
...
/* Send an LDAP delete request to the server. */
rc = ldap_delete_ext( ld, DELETE_DN, NULL, NULL, &amp;msgid );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_delete_ext: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Poll the server for the results of the delete operation. */
while ( !finished ) {
/* Call ldap_result() to get the results of the delete operation.
ldap_result() blocks for the time specified by the timeout argument
(set to zerotime here) while waiting for the result from the server. */
rc = ldap_result( ld, msgid, 0, &amp;zerotime, &amp;res );
/* Check to see if a result was received. */
switch ( rc ) {
case -1:
/* If ldap_result() returned -1, an error occurred. */
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
case 0:
/* The timeout period specified by zerotime was exceeded, meaning
the server has still not yet sent the results of the delete
operation back to the client. Break out of this switch statement,
and continue calling ldap_result() to poll for results. */
break;
default:
/* ldap_result() got the results of the delete operation
from the server. No need to keep polling. */
finished = 1;
/* Call ldap_parse_result() to get information from the results
received from the server. Note the last argument is a non-zero
value. This means after the function retrieves information from
the LDAPMessage structure, the structure is freed.
(You do not need to call ldap_msgfree() to free the structure.)*/
parse_rc = ldap_parse_result( ld, res, &amp;rc, &amp;matched_msg,
&amp;error_msg, &amp;referrals, &amp;serverctrls, 1 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n",
ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Check the results of the LDAP delete operation. */
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_delete_ext: %s\n", ldap_err2string(rc));
if ( error_msg != NULL &amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
/* Print the portion of a specified DN that matches an
existing entry, if returned by the server. */
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
} else {
printf( "%s deleted successfully.\n"
"Counted to %d while waiting for the delete operation.\n",
DELETE_DN, global_counter );
}
}
/* Do other work while waiting for the results of the
delete operation. */
if ( !finished ) {
do_other_work();
}
}
ldap_unbind( ld );
return 0;
...
/* Perform other work while polling for results. */
void
do_other_work()
{
global_counter++;
}
...</programlisting>
</example>
</sect3>
</sect2>
</sect1>
<sect1 id="bdadg"><title>Retrieving SDK Information</title>
<indexterm>
<primary>C SDK</primary>
<secondary>retrieving SDK information</secondary>
</indexterm>
<para>You can get information about the particular version of &DirectorySDKForC;
that you are using by calling the <function>ldap_get_option</function> function:</para>
<programlisting>ldap_get_option(..., LDAP_OPT_API_INFO, ...);</programlisting>
<para>The retrieved information can include the version of the SDK or the
highest version of the LDAP that the SDK supports. This example shows how
to use this function to retrieve version information.</para>
<example id="csdk-info-example"><title>Retrieving the SDK Version Using <function>
ldap_get_option</function></title>
<indexterm>
<primary>example programs</primary>
<secondary>retrieving SDK version</secondary>
</indexterm>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
main()
{
LDAPAPIInfo ldapi;
LDAPAPIFeatureInfo fi;
int i;
int rc;
LDAP *ld;
memset( &amp;ldapi, 0, sizeof(ldapi));
ldapi.ldapai_info_version = LDAP_API_INFO_VERSION;
if ((rc = ldap_get_option( ld, LDAP_OPT_API_INFO, &amp;ldapi)) != 0) {
printf("Error: ldap_get_option (rc: %d)\n", rc);
exit(0);
}
printf("LDAP Library Information -\n"
" Highest supported protocol version: %d\n"
" LDAP API revision: %d\n"
" API vendor name: %s\n"
" Vendor-specific version: %.2f\n",
ldapi.ldapai_protocol_version, ldapi.ldapai_api_version,
ldapi.ldapai_vendor_name,
(float)ldapi.ldapai_vendor_version / 100.0 );
if ( ldapi.ldapai_extensions != NULL ) {
printf(" LDAP API Extensions:\n");
for ( i = 0; ldapi.ldapai_extensions[i] != NULL; i++ ) {
printf(" %s", ldapi.ldapai_extensions[i] );
fi.ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
fi.ldapaif_name = ldapi.ldapai_extensions[i];
fi.ldapaif_version = 0;
if ( ldap_get_option( NULL, LDAP_OPT_API_FEATURE_INFO, &amp;fi )
!= 0 ) {
printf("Error: ldap_get_option( NULL,"
" LDAP_OPT_API_FEATURE_INFO, ... ) for %s failed"
" (Feature Info version: %d)\n",
fi.ldapaif_name, fi.ldapaif_info_version );
} else {
printf(" (revision %d)\n", fi.ldapaif_version);
}
}
}
printf("\n");
}</programlisting>
</example>
</sect1>
<sect1 id="bdadh"><title>Managing Memory</title>
<indexterm>
<primary>C SDK</primary>
<secondary>managing memory</secondary>
</indexterm><indexterm>
<primary>memory management</primary>
</indexterm>
<para>Several of the SDK functions allocate memory when called. When you have
finished working with data allocated by these functions, you should free the
memory. The following shows some of the functions that allocate memory and
the corresponding functions you use to free the memory when done.</para>
<table frame="topbot" id="csdk-memory-mgmt-fns"><title>SDK Functions to Allocate
and Free Memory</title>
<tgroup cols="2"><colspec colnum="1" colwidth="30*"><colspec colnum="2"
colwidth="70*">
<thead>
<row>
<entry>
<para>Function to Free Memory</para></entry>
<entry>
<para>Type of Memory Freed</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><function>ldap_unbind</function>, <function>ldap_unbind_s</function></para>
</entry>
<entry>
<para>Frees <structname>LDAP</structname> structures allocated by <function>ldap_init
</function> or <function>prldap_init</function>.</para></entry>
</row>
<row>
<entry>
<para><function>ldap_msgfree</function></para></entry>
<entry>
<para>Frees <structname>LDAPMessage</structname> structures allocated by <function>
ldap_result</function> or <function>ldap_search_ext_s</function>.</para></entry>
</row>
<row>
<entry>
<para><function>ldap_ber_free</function></para></entry>
<entry>
<para>Frees <structname>BerElement</structname> structures allocated by <function>
ldap_first_attribute</function>.</para></entry>
</row>
<row>
<entry>
<para><function>ldap_value_free</function></para></entry>
<entry>
<para>Frees <literal>char **</literal> arrays and structures allocated by <function>
ldap_get_values</function>.</para></entry>
</row>
<row>
<entry>
<para><function>ldap_value_free_len</function></para></entry>
<entry>
<para>Frees arrays of <structname>berval</structname> structures allocated
by <function>ldap_get_values_len</function>.</para></entry>
</row>
<row>
<entry>
<para><function>ber_bvfree</function></para></entry>
<entry>
<para>Frees <structname>berval</structname> structures allocated by <function>ldap_extended_operation_s
</function>, <function>ldap_parse_extended_result</function>, <function>ldap_parse_sasl_bind_result
</function>, and <function>ldap_sasl_bind_s</function>.</para></entry>
</row>
<row>
<entry>
<para><function>ldap_free_friendlymap</function></para></entry>
<entry>
<para>Frees <structname>FriendlyMap</structname> structures allocated by <function>
ldap_friendly_name</function>.</para></entry>
</row>
<row>
<entry>
<para><function>ldap_free_urldesc</function></para></entry>
<entry>
<para>Frees <structname>LDAPURLDesc</structname> structures allocated by <function>
ldap_url_parse</function>.</para></entry>
</row>
<row>
<entry>
<para><function>ldap_getfilter_free</function></para></entry>
<entry>
<para>Frees <structname>LDAPFiltDesc</structname> structures allocated by <function>
ldap_init_getfilter</function> or <function>ldap_init_getfilter_buf</function>.</para>
</entry>
</row>
<row>
<entry>
<para><function>ldap_mods_free</function></para></entry>
<entry>
<para>Frees <structname>LDAPMod</structname><literal>**</literal> arrays and
structures allocated by functions that you call when you add or modify entries.</para>
</entry>
</row>
<row>
<entry>
<para><function>ldap_free_sort_keylist</function></para></entry>
<entry>
<para>Frees <structname>LDAPsortkey</structname><literal>**</literal> arrays
that you allocate by calling <function>ldap_create_sort_keylist</function>.</para>
</entry>
</row>
<row>
<entry>
<para><function>ldap_control_free</function></para></entry>
<entry>
<para>Frees <structname>LDAPControl</structname> structures that you allocate
by calling <function>ldap_create_sort_control</function> or <function>ldap_create_persistentsearch_control
</function>.</para></entry>
</row>
<row>
<entry>
<para><function>ldap_controls_free</function></para></entry>
<entry>
<para>Frees <structname>LDAPControl</structname><literal>**</literal> arrays
and structures that you allocate by calling <function>ldap_get_entry_controls</function>, <function>
ldap_parse_result</function>, or <function>ldap_parse_reference</function>.</para>
</entry>
</row>
<row>
<entry>
<para><function>ldap_memfree</function></para></entry>
<entry>
<para>Frees any other types of memory that you allocate. This function is
a general function for freeing memory.</para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="bdadi"><title>Reporting Errors</title>
<indexterm>
<primary>C SDK</primary>
<secondary>reporting errors</secondary>
</indexterm><indexterm>
<primary>errors</primary>
<secondary>reporting</secondary>
</indexterm>
<para>In LDAP, the success or failure of an operation is specified by a <firstterm>
result code</firstterm> sent back to the client. A result code of zero (<literal>
0</literal>) normally indicates that the operation was successful, whereas
a nonzero result code usually indicates that an error occurred. For a detailed
list of result codes, see <olink targetptr="bdaxx">Chapter&nbsp;22, Directory
SDK for C Result Codes</olink>.</para>
<sect2 id="bdadj"><title>Setting Error Codes</title>
<indexterm>
<primary>C SDK</primary>
<secondary>setting error codes</secondary>
</indexterm><indexterm>
<primary>error codes</primary>
<secondary>setting</secondary>
</indexterm>
<para>When an LDAP operation is performed, the error information from the
operation is specified in the <structname>LDAP</structname> structure. If
you want to set error codes and error information in the <structname>LDAP</structname> structure,
call the <function>ldap_set_lderrno</function> function. This example sets
the <errorcode>LDAP_PARAM_ERROR</errorcode> error code in an <structname>LDAP</structname> structure.
</para>
<example id="csdk-set-error-example"><title>Setting an Error Code</title>
<programlisting>#include "ldap.h"
...
LDAP *ld;
char *errmsg = "Invalid parameter";
...
if ( ldap_my_function() != LDAP_SUCCESS ) {
ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, errmsg );
return( 1 );
}
...</programlisting>
</example>
</sect2>
<sect2 id="bdadk"><title>Getting Information About an Error</title>
<indexterm>
<primary>C SDK</primary>
<secondary>retrieving error information</secondary>
</indexterm>
<para>When an error occurs in an LDAP operation, the server sends an LDAP
result code for the error back to the client. The server also sends a message
with any additional information about the error.</para>
<itemizedlist>
<para>You can get this information back from the server in two ways:</para>
<listitem><para>If you are calling asynchronous functions, you can get the
information from the <structname>LDAPMessage</structname> structure that represents
the result the server returns.</para><para>For details, see <olink targetptr="bdadl">Getting Information From an LDAPMessage Structure</olink>.</para>
</listitem>
<listitem><para>Sometimes, you do not have an <structname>LDAPMessage</structname> structure.
For example, you might be calling functions that do not interact with the
server. When you do not have a message ID, get error information from the <structname>
LDAP</structname> connection handle.</para><para>For details, see <olink targetptr="bdadm">Getting Information From an LDAP Structure</olink>.</para>
</listitem>
</itemizedlist>
<sect3 id="bdadl"><title>Getting Information From an <structname>LDAPMessage</structname> Structure
</title>
<para>If you have requested the operation through an asynchronous function,
get the result by calling the <function>ldap_result</function> function. This
function passes the result as an <structname>LDAPMessage</structname> structure.
You can get information from this structure by calling the <function>ldap_parse_result
</function> function whose prototype is shown here</para>
<example id="csdk-ldap-parse-result-example"><title>The <function>ldap_parse_result
</function> Function</title>
<programlisting>LDAP_API(int) LDAP_CALL ldap_parse_result( LDAP *ld,
LDAPMessage *res, int *errcodep, char **matcheddnp,
char **errmsgp, char ***referralsp,
LDAPControl ***serverctrlsp, int freeit );</programlisting>
</example>
<itemizedlist>
<para>Different types of information are returned in the parameters of this
function.</para>
<listitem><para>The LDAP result code is the <parameter>errcodep</parameter> argument.
</para></listitem>
<listitem><para>Additional information from the server is passed back as the <parameter>
errmsgp</parameter> argument.</para></listitem>
<listitem><para>When the server cannot find an entry from a DN, the portion
of the DN that identifies an entry is passed as the <parameter>matcheddnp</parameter> argument.
</para><para>See <olink targetptr="bdado">Receiving the Matching Portion of
a DN</olink> for details.</para></listitem>
</itemizedlist>
<para>You can also get the error message that describes the LDAP result code
by using the <function>ldap_err2string</function> function. See <olink targetptr="bdadn">Getting the Error Message From an Error Code</olink> for
details.</para>
<para>The following example gets and prints information about an error returned
from the server.</para>
<example id="csdk-print-ldapmessage-example"><title>Getting and Printing Error
Information From an <structname>LDAPMessage</structname> Structure</title>
<indexterm>
<primary>example programs</primary>
<secondary>printing error information</secondary>
</indexterm>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
LDAP *ld;
LDAPMessage *res;
int msgid = 0, rc = 0, parse_rc = 0, finished = 0;
char *matched_msg = NULL, *error_msg = NULL;
char **referrals;
LDAPControl **serverctrls;
struct timeval zerotime;
...
while ( !finished ) {
/* Check to see if the server returned a result. */
rc = ldap_result( ld, msgid, 0, &amp;zerotime, &amp;res );
switch ( rc ) {
...
default:
/* The client has received the result of the LDAP operation. */
finished = 1;
/* Parse this result to determine if the operation was successful. */
parse_rc = ldap_parse_result( ld, res, &amp;rc, &amp;matched_msg,
&amp;error_msg, &amp;referrals, &amp;serverctrls, 1 );
/* Verify that the result was parsed correctly. */
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result error: %s\n",
ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Check the results of the operation. */
if ( rc != LDAP_SUCCESS ) {
/* Print the error message corresponding to the result code. */
fprintf( stderr, "Error: %s\n",
ldap_err2string( rc ) );
/* If the server sent an additional message, print it out. */
if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
/* If the server cannot find an entry with the specified DN,
it may send back the portion of the DN that matches
an existing entry. */
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
/* Disconnect and return. */
ldap_unbind( ld );
return( 1 );
}
...</programlisting>
</example>
</sect3>
<sect3 id="bdadm"><title>Getting Information From an <structname>LDAP</structname> Structure
</title>
<para>Sometimes, you do not get an <structname>LDAPMessage</structname> structure.
For example, when you call functions that do not interact with the server,
get error information from the connection handle. You can get information
about the last error that has occurred by calling the <function>ldap_get_lerrno</function> function
whose prototype is shown here.</para>
<example id="csdk-ldap-get-errno-example"><title>The <function>ldap_get_lderrno</function> Function
</title>
<programlisting>LDAP_API(int) LDAP_CALL ldap_get_lderrno(LDAP *ld,
char **m, char **s);</programlisting>
</example>
<itemizedlist>
<para>The different types of information to retrieve are returned in the following
ways:</para>
<listitem><para>The LDAP result code is returned by this function.</para>
</listitem>
<listitem><para>Additional information from the server is passed back as the <parameter>
s</parameter> argument.</para></listitem>
<listitem><para>When the server cannot find an entry from a DN, the portion
of the DN that identifies an entry is passed as the <literal>m</literal> argument.
</para><para>See <olink targetptr="bdado">Receiving the Matching Portion of
a DN</olink> for details.</para></listitem>
</itemizedlist>
<para>If you do not need to use the parameters returned by the <function>ldap_get_lerrno
</function> function, set the parameters to <literal>NULL</literal>:</para>
<programlisting>ldap_get_lderrno( ld, NULL, NULL );</programlisting>
<para>The following example gets and prints information about an error from
an <structname>LDAP</structname> structure.</para>
<example id="csdk-print-ldap-example"><title>Getting and Printing an Error
Message From an <structname>LDAP</structname> Structure</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
LDAP *ld;
char* *error_msg = NULL, *matched_msg = NULL;
int rc;
...
rc = ldap_get_lderrno( ld, &amp;matched_msg, &amp;error_msg );
fprintf( stderr, "ldap_result error: %s\n", ldap_err2string( rc ) );
if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
/* If the server cannot find an entry with the specified DN,
it may send back the portion of the DN that matches
an existing entry. */
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
...</programlisting>
</example>
</sect3>
<sect3 id="bdadn"><title>Getting the Error Message From an Error Code</title>
<para>If you have an error code, you can retrieve its corresponding error
message using the <function>ldap_err2string</function> function. The function
returns a pointer to the error message. The pointer returned by this function
is a pointer to static data. Do not free this string.</para>
<example id="csdk-msg-from-error-code-example"><title>Retrieving an Error
Message From an Error Code</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
int rc;
...
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "Error: %s\n", ldap_err2string( rc ) );
}
...</programlisting>
</example>
</sect3>
</sect2>
<sect2 id="bdado"><title>Receiving the Matching Portion of a DN</title>
<indexterm>
<primary>distinguished names (DNs)</primary>
<secondary>return portion of</secondary>
</indexterm>
<para>If the server cannot find an entry specified by a DN, the server can
return the portion of the DN that identifies an existing entry. According
to LDAP v3, if a server returns an <errorcode>LDAP_NO_SUCH_OBJECT</errorcode>, <errorcode>
LDAP_ALIAS_PROBLEM</errorcode>, <errorcode>LDAP_INVALID_DN_SYNTAX</errorcode>,
or <errorcode>LDAP_ALIAS_DEREF_PROBLEM</errorcode> result code, the LDAP server
should also send back the portion of the DN that matches an entry that is
closest to the requested entry. </para>
<para>For example, suppose that the LDAP server processes a request to modify
the entry with the DN <literal>uid=bjensen,ou=Contractors,dc=example,dc=com</literal> but
that entry does not exist in the directory. If <literal>ou=Contractors,dc=example,dc=com
</literal> does exist, the server sends this portion of the DN with the result
code <errorcode>LDAP_NO_SUCH_OBJECT</errorcode>. If <literal>ou=Contractors,dc=example,dc=com
</literal> does not exist, but <literal>dc=example,dc=com</literal> does,
the server sends <literal>dc=example,dc=com</literal> back to the client.
The server also returns the result code <errorcode>LDAP_NO_SUCH_OBJECT</errorcode>.
Basically, the server removes one DN component at a time, until the server
can find a DN that identifies an existing entry.</para></sect2>
<sect2 id="bdadp"><title>Printing Error Messages</title>
<indexterm>
<primary>error messages</primary>
<secondary>printing</secondary>
</indexterm>
<para>To print the error message that describes the last error that occurred,
call the <function>ldap_get_lerrno</function> function. The following prints
a message if a function fails to delete an entry in the server.</para>
<example id="csdk-print-error-code-example"><title>Printing Error Messages
From Error Codes</title>
<programlisting>#include "ldap.h"
...
int lderr;
char * errmsg;
LDAP *ld;
char *dn = "uid=bjensen,ou=People,dc=example,dc=com";
...
if ( ldap_delete_s( ld, dn ) != LDAP_SUCCESS ) {
lderr = ldap_get_lderrno (ld, NULL, &amp;errmsg);
if ( errmsg, != NULL ) {
fprintf(stderr, "ldap_delete_s: %s\n", errmsg );
ldap_memfree( errmsg );
}
return( 1 );
}
...</programlisting>
</example>
<para>The client also prints the following message if the client does not
have access permissions to delete the entry:</para>
<programlisting>ldap_delete_s: Insufficient access</programlisting>
</sect2>
</sect1>
<sect1 id="bdadq"><title>Handling Referrals With Directory SDK for C</title>
<indexterm>
<primary>C SDK</primary>
<secondary>handling referrals</secondary>
</indexterm><indexterm>
<primary>referrals</primary>
<secondary>handling with C SDK</secondary>
</indexterm>
<para>When a server receives a request for a DN, that DN might not be in its
directory tree. The server can refer clients to another server that might
contain the DN. The reference that the client receives is called a <firstterm>referral
</firstterm>. </para>
<para>Consider an LDAP server that has a directory that starts under <literal>dc=example,dc=com
</literal>.</para>
<itemizedlist>
<para>Your client sends the server a request to modify the entry with the
DN <literal>uid=bjensen,ou=People,dc=exampleWest,dc=com</literal>, that is,
the entry is not under <literal>dc=example,dc=com</literal>. One of the following
can occur:</para>
<listitem><para>If the server is not configured to send a referral, the server
sends back an <errorcode>LDAP_NO_SUCH_OBJECT</errorcode> result code.</para>
</listitem>
<listitem><para>If the server is configured to refer you to another LDAP server,
the server sends a referral back to your client. The referral consists of
the result code, <errorcode>LDAP_PARTIAL_RESULTS</errorcode> for LDAP v2 clients,
or <errorcode>LDAP_REFERRAL</errorcode> for LDAP v3 clients, and one or more
LDAP URLs. For LDAP v2 clients, the URLs are included in the error message
that the server sends to the client. For LDAP v3 clients, the URLs are included
in a separate section of the result.</para></listitem>
</itemizedlist>
<itemizedlist>
<para>Depending on how your LDAP client is configured, one of the following
can occur:</para>
<listitem><para>If your client handles referrals automatically, the client
connects to the LDAP server specified in the referral. The client then requests
the operation from that server. The client binds anonymously to that server.</para>
</listitem>
<listitem><para>If your client does not handle referrals automatically, your
client returns the result code sent from the server, <errorcode>LDAP_PARTIAL_RESULTS
</errorcode> or <errorcode>LDAP_REFERRAL</errorcode>. You can get the LDAP
URLs from the result by calling the <function>ldap_parse_result</function> function.
</para></listitem>
</itemizedlist>
<para>By default, clients built with &DirectorySDKForC; follow referrals
automatically.</para>
<sect2 id="bdadr"><title>Searching References and Referrals</title>
<indexterm>
<primary>C SDK</primary>
<secondary>search references</secondary>
</indexterm>
<para>A concept that is similar to a referral is a search reference. A <firstterm>
search reference</firstterm> is an entry with the object class <literal>referral</literal>.
The <literal>ref</literal> attribute of this object class contains an LDAP
URL that identifies another LDAP server. When your client searches a subtree
of a directory that contains search references, the server returns a mix of
matching entries and search references.</para>
<itemizedlist>
<para>As your client retrieves search references from the server, one of the
following occurs:</para>
<listitem><para>If your client handles referrals automatically, &DirectorySDKForC;
retrieves each search reference, binds to the server identified in the reference,
and then retrieves the entry.</para></listitem>
<listitem><para>If your client does not handle referrals automatically, &DirectorySDKForC;
adds the search reference to the chain of search results. The search reference
is a message of the type <literal>LDAP_RES_SEARCH_REFERENCE</literal>. You
can get the search references from a chain of results by calling the <function>ldap_first_reference
</function> and <function>ldap_next_reference</function> functions. You can
also call the <function>ldap_first_message</function> and <function>ldap_next_message
</function> functions to get each message in the search results, and then
call the <function>ldap_msgtype</function> function to determine if the message
is of the type <literal>LDAP_RES_SEARCH_REFERENCE</literal>.</para></listitem>
</itemizedlist>
<para>See <olink targetptr="bdaba">ldap_ssl.h Header File</olink> for information
about specifying a DN and password for binding to a server for a referral.</para>
</sect2>
<sect2 id="bdads"><title>Enabling or Disabling Referral Handling With &DirectorySDKForC;
</title>
<indexterm>
<primary>referrals</primary>
<secondary>handling with C SDK<?Pub Caret></secondary>
</indexterm>
<para>By default, clients built with &DirectorySDKForC; automatically follow
referrals to other servers. To change the way referrals are handled, call
the <function>ldap_set_option</function> function and pass <literal>LDAP_OPT_REFERRALS
</literal> as the value of the <parameter>option</parameter> parameter.</para>
<itemizedlist>
<listitem><para>To prevent the client from automatically following referrals,
set the <parameter>optdata</parameter> parameter to <literal>LDAP_OPT_OFF</literal>.
</para></listitem>
<listitem><para>If you want the client to automatically follow referrals again,
set the <parameter>optdata</parameter> parameter to <literal>LDAP_OPT_ON</literal>.
</para><para>Both <literal>LDAP_OPT_OFF</literal> and <literal>LDAP_OPT_ON</literal> are
cast to <literal>(void *)</literal>. You can pass these parameters directly
to the function as shown in the following example. The parameter prevents
the client from automatically following referrals to other LDAP servers.</para>
</listitem>
</itemizedlist>
<example id="csdk-disable-referrals-example"><title>Disabling Referrals</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
LDAP *ld;
int rc;
char *host = "localhost";
...
/* Initialize a session with the LDAP server ldap.example.com:389. */
/* Use prldap_init() for IPv6 support. */
if ( ( ld = ldap_init( host, LDAP_PORT ) ) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Never follow referrals. */
if ( ldap_set_option( ld,
LDAP_OPT_REFERRALS,
LDAP_OPT_OFF) !=
LDAP_SUCCESS ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_set_option: %s\n",
ldap_err2string( rc );
return( 1 );
}
...</programlisting>
</example>
</sect2>
<sect2 id="bdadt"><title>Limiting Referral Hops With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>referral hop limit</secondary>
</indexterm>
<para>You can specify the maximum number of referral hops that should be followed
in a sequence of referrals. The maximum setting is called the <firstterm>referral
hop limit</firstterm>. You can specify the limit as a preference for the connection.
You can also specify the limit as a search constraint for a specific search
operation. For example, LDAP server 1 refers your client to server 2, server
2 to server 3, and then server 3 to server 4. Your client is being referred
three times. With a limit of two referral hops, your client would not follow
the referral to server 4, as the third referral exceeds the limit. If the
referral hop limit is exceeded, the client returns the result code <errorcode>LDAP_REFERRAL_LIMIT_EXCEEDED
</errorcode>.</para>
<para>To set the referral hop limit, pass <literal>LDAP_OPT_REFERRAL_HOP_LIMIT</literal> as
the value of the <literal>option</literal> parameter. Also, pass the maximum
number of hops as the value of the <literal>optdata</literal> parameter. By
default, the maximum number of hops is 5.</para></sect2>
<sect2 id="bdadu"><title>Binding for Referrals</title>
<indexterm>
<primary>C SDK</primary>
<secondary>binding for referrals</secondary>
</indexterm><indexterm>
<primary>referrals</primary>
<secondary>binding for</secondary>
</indexterm>
<para>If the session setup specifies that the client always follows referrals,
the LDAP server that the client connects to can refer the client to another
server. By default, the client binds anonymously when following referrals.
No user name or password is specified. The following sections explain how
to set up your client to authenticate with a DN and with corresponding credentials.
</para>
<sect3 id="bdadv"><title>How Referral Binding Works</title>
<para>To authenticate to the referred LDAP server, define a rebind function
of the type <structname>LDAP_REBINDPROC_CALLBACK</structname>. The rebind
function gets the DN and password to be used for authentication. Then, you
specify that your function should be used if binding to other servers when
following referrals.</para>
<orderedlist>
<para>Referral handling proceeds as follows:</para>
<listitem><para>The LDAP server sends a referral back to the client.</para>
<para>The referral contains an LDAP URL that identifies another LDAP server.</para>
</listitem>
<listitem><para>The client calls the rebind function, specified by the <literal>LDAP_OPT_REBIND_FN
</literal> option, passing <literal>0</literal> as the <parameter>freeit</parameter> argument.
</para></listitem>
<listitem><para>The rebind function sets the <parameter>dnp</parameter>, <parameter>
passwdp</parameter>, and <parameter>authmethodp</parameter> arguments.</para>
<itemizedlist>
<listitem><para>The <parameter>dnp</parameter> argument points to the DN used
to authenticate to the new LDAP server.</para></listitem>
<listitem><para>The <parameter>passwdp</parameter> argument points to the
credentials for this DN.</para></listitem>
<listitem><para>The <parameter>authmethodp</parameter> argument points to
the method of authentication that is used, such as <literal>LDAP_AUTH_SIMPLE</literal>.
</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>If successful, the rebind function returns <errorcode>LDAP_SUCCESS
</errorcode>, and referral processing continues.</para><para>If any other
value is returned, referral processing stops, and that value is returned as
the result code for the original LDAP request.</para></listitem>
<listitem><para>The client gets the DN, the credentials, and the authentication
method from the arguments of the rebind function. The client uses this information
to authenticate to the new LDAP server.</para></listitem>
<listitem><para>The client calls the rebind function again, passing <literal>1</literal> as
the <parameter>freeit</parameter> argument.</para></listitem>
<listitem><para>The rebind function frees any memory that was allocated earlier
to specify the DN and credentials.</para></listitem>
</orderedlist>
</sect3>
<sect3 id="bdadw"><title>Defining the Rebind Function</title>
<itemizedlist>
<para>You need to define a rebind function that does the following:</para>
<listitem><para> If <parameter>freeit</parameter> is <literal>0</literal>,
do the following:</para>
<itemizedlist>
<listitem><para>Set <parameter>dnp</parameter> to point to the DN to be used
for authentication.</para></listitem>
<listitem><para>Set <parameter>passwdp</parameter> to point to the credentials
to be used for authentication.</para></listitem>
<listitem><para>Set <parameter>authmethodp</parameter> to point to the method
of authentication to be used, such as <literal>LDAP_AUTH_SIMPLE</literal>.</para>
</listitem>
<listitem><para>Alternatively, you can also make use of the <parameter>arg</parameter> argument,
a pointer to the argument specified in the <function>ldap_set_rebind_proc</function> function.
If successful, the function returns <errorcode>LDAP_SUCCESS</errorcode>. Otherwise,
the function returns the appropriate LDAP error code.</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>If <parameter>freeit</parameter> is <literal>1</literal>,
free any memory that you allocated to create the DN and credentials.</para>
<para>The following code defines the rebind function. The table defines the
parameters of the rebind function. <structname>LDAP_CALL</structname> and <structname>
LDAP_CALLBACK</structname> set up calling conventions. The structures are
defined in the <literal>lber.h</literal> header file.</para></listitem>
</itemizedlist>
<example id="csdk-rebind-example"><title>Rebind Function Definition</title>
<programlisting>int LDAP_CALL LDAP_CALLBACK rebindproc( LDAP *ld, char **dnp,
char **passwdp, int *authmethodp, int freeit, void *arg );</programlisting>
</example>
<table frame="topbot" pgwide="1" id="csdk-rebind-callback-params"><title><structname>
LDAP_CALL</structname> and <structname>LDAP_CALLBACK</structname> Parameters</title>
<tgroup cols="2"><colspec colnum="1" colwidth="13.87*"><colspec colnum="2"
colwidth="86.13*">
<thead>
<row>
<entry>
<para>Parameter</para></entry>
<entry>
<para>Description</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><parameter>ld</parameter></para></entry>
<entry>
<para>Pointer to the connection handle to the LDAP server.</para></entry>
</row>
<row>
<entry>
<para><parameter>dnp</parameter></para></entry>
<entry>
<para>Pointer to the DN of the user or entity who wants to perform the LDAP
operations. Your function needs to set this value.</para></entry>
</row>
<row>
<entry>
<para><parameter>passwdp</parameter></para></entry>
<entry>
<para>Pointer to the user password. Your function needs to set this value.</para>
</entry>
</row>
<row>
<entry>
<para><parameter>authmethodp</parameter></para></entry>
<entry>
<para>Pointer to the method of authentication. Your function needs to set
this value.</para></entry>
</row>
<row>
<entry>
<para><parameter>freeit</parameter></para></entry>
<entry>
<para>Specifies whether or not to free the memory allocated by the previous <function>
rebindproc</function> function call in the event that this function is called
more than once. If <parameter>freeit</parameter> is set to a nonzero value,
your function should free the memory allocated by the previous call.</para>
</entry>
</row>
<row>
<entry>
<para><parameter>arg</parameter></para></entry>
<entry>
<para>Pointer to data that can be passed to your function.</para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect3>
<sect3 id="bdadx"><title>Registering the Rebind Function</title>
<itemizedlist>
<para>After you define a rebind function, you must register the function.
You can register the function in one of the following ways:</para>
<listitem><para>Call <function>ldap_set_rebind_proc</function>, specifying
your function and any data that you want passed as an argument.</para>
</listitem>
<listitem><para>Call <function>ldap_set_option</function> to set the <literal>LDAP_OPT_REBIND_FN
</literal> option to your function. Use the <literal>LDAP_OPT_REBIND_ARG</literal> option
to specify any arguments to pass to your rebind function.</para></listitem>
</itemizedlist>
</sect3>
</sect2>
</sect1>
<sect1 id="bdady"><title>Creating an In-Memory Cache</title>
<indexterm>
<primary>C SDK</primary>
<secondary>setting up in-memory cache</secondary>
</indexterm><indexterm>
<primary>cache</primary>
<secondary>setting up</secondary>
</indexterm>
<para>&DirectorySDKForC; includes functions that allow you to create an
in-memory cache of search results for your client. Then, when sending a search
request and receiving results, the results would be cached. The next time
your client issues the same search request, the results are read from the
cache. To set up a cache for your connection, complete the following procedure.</para>
<task><title>To Set Up an In-Memory Cache</title>
<procedure>
<step><para>Call the <function>ldap_memcache_init</function> function to create
a new <structname>LDAPMemCache</structname> structure.</para><para>The structure
is the cache. Pass the pointer to this structure for subsequent operations.</para>
</step>
<step><para>Call the <function>ldap_memcache_set</function> function to associate
the cache with an <structname>LDAP</structname> structure, which is a connection
handle.</para><para>When a search request is cached, the search criteria are
used as the key to the item in the cache. If you run the same search again,
the results are read from the cache. If you alter the criteria, your client
gets the results from the server rather than the cache. For example, you can
specify to return all attributes instead of just the <literal>uid</literal> attribute,
</para><para>The cache periodically checks for expired items. The cache mechanism
removes expired items from the cache.</para></step>
<step><para>When you write a multithreaded application, set up a separate
thread to keep the cache up to date. </para><para>To keep the cache updated,
call the <function>ldap_memcache_update</function> function.</para></step>
<step><para>If you want to remove items from the cache or flush the cache,
call the <function>ldap_memcache_flush</function> function.</para></step>
<step><para>When you are done working with the cache, call the <function>ldap_memcache_destroy
</function> function.</para></step>
</procedure>
<example id="csdk-cache-example">
<title>Setting Up an In-Memory Cache</title>
<programlisting>#include "ldap.h"
...
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
...
LDAP *ld;
LDAPMemCache *dircache;
char *matched_msg = NULL, *error_msg = NULL;
int rc;
...
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
...
/* Create an in-memory cache. */
rc = ldap_memcache_init( 0, 0, NULL, NULL, &amp;dircache );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_memcache_init: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Associate the cache with the connection. */
rc = ldap_memcache_set( ld, dircache );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_memcache_set: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
...</programlisting>
</example>
</task>
</sect1>
<sect1 id="bdadz"><title>Handling Failover</title>
<indexterm>
<primary>C SDK</primary>
<secondary>handling failover</secondary>
</indexterm><indexterm>
<primary>failover handling</primary>
<secondary>C SDK</secondary>
</indexterm>
<para>While performing an LDAP operation, if the LDAP client loses the connection
with the server, the SDK returns an <errorcode>LDAP_SERVER_DOWN</errorcode> or <errorcode>
LDAP_CONNECT_ERROR</errorcode> result code.</para>
<itemizedlist>
<para>To reconnect to the server, you can do one of the following:</para>
<listitem><para>Free the current connection handle. Then create a new connection
handle.</para><para>See <olink targetptr="bdaea">Creating a New Connection
Handle</olink> for details.</para></listitem>
<listitem><para>Use the <literal>reconnect</literal> option, <literal>LDAP_OPT_RECONNECT
</literal>, to connect to the server again with the same connection handle.</para>
<para>See <olink targetptr="bdaeb">Using the Reconnect Option</olink> for
details.</para><para>You can use this option if you do not want to free the
connection handle, for example, if multiple threads are sharing the same connection
handle.</para></listitem>
</itemizedlist>
<sect2 id="bdaea"><title>Creating a New Connection Handle</title>
<para>Call the <function>ldap_unbind</function> or <function>ldap_unbind_s</function> function
to free the existing connection handle, which is an <structname>LDAP</structname> structure.
Then call <function>ldap_init</function> or <function>prldap_init</function> to
initialize a new connection as shown in the following example.</para>
<para>The disadvantage of this approach is the need to free the connection
handle, which can make sharing connection handles between threads difficult.</para>
<example id="csdk-new-ldap-example"><title>Initializing a New Connection Handle</title>
<programlisting>#include "ldap.h"
...
LDAP *ld;
int tries = 0, rc = 0;
...
do {
/* Call a function that performs an LDAP operation
(my_ldap_request_function() can be any of these functions,
such as ldap_search_ext_s()) */
rc = my_ldap_request_function( ld );
/* Check to see if the connection was lost. */
if ( rc != LDAP_SERVER_DOWN &amp;&amp; rc != LDAP_CONNECT_ERROR ) {
return( rc ); /* Return result code. */
}
/* If the connection was lost, free the handle. */
ldap_unbind( ld );
/* Create a new connection handle and attempt to bind again. */
/* Use prldap_init() for IPv6 support. */
if (( ld = ldap_init( hostlist, port )) != NULL ) {
ldap_simple_bind_s();
/* Perform any other initialization
work on the connection handle. */
}
} while ( ld != NULL &amp;&amp; ++tries &lt; 2 );
...</programlisting>
</example>
</sect2>
<sect2 id="bdaeb"><title>Using the Reconnect Option</title>
<para>To reconnect to the server without freeing the connection handle, for
example, if multiple threads need to share the same connection handle, call
the <function>ldap_set_option</function> function to set the <literal>LDAP_OPT_RECONNECT
</literal> option to <literal>LDAP_OPT_ON</literal>. Call this function immediately
after calling <function>ldap_init</function> or <function>prldap_init</function> as
shown in the following example:</para>
<example id="csdk-reconnect-ldap-example"><title>Reconnecting to an Existing
Connection Handle</title>
<programlisting>#include "ldap.h"
...
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
...
LDAP *ld;
...
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Set the reconnect option. */
if ( ldap_set_option( ld, LDAP_OPT_RECONNECT, LDAP_OPT_ON ) == 0 ) {
/* success */
} else {
/* failure */
}
...</programlisting>
</example>
<para>If after setting this option, the connection to the server has been
lost, the SDK returns an <errorcode>LDAP_CONNECT_ERROR</errorcode> or <errorcode>
LDAP_SERVER_DOWN</errorcode> result code to your client. When you receive
this result code, call the <function>ldap_simple_bind_s</function> function.
This function reestablishes a connection to one of the hosts specified in
the <function>ldap_init</function> or <function>prldap_init</function> function
call. If your client is able to reconnect with the server, <function>ldap_simple_bind_s
</function> issues a bind request to the server and returns the result. The
following example attempts to reconnect to the server if the client is disconnected.
</para>
<example id="csdk-reconnect2-ldap-example"><title>Reconnecting to a Server
After Disconnect</title>
<programlisting>#include "ldap.h"
...
LDAP *ld;
int tries = 0, rc = 0;
...
do {
/* Call a function that performs an LDAP operation
(my_ldap_request_function() can be any of these functions,
such as ldap_search_ext_s()) */
rc = my_ldap_request_function( ld );
/* Check to see if the connection was lost. */
if ( rc != LDAP_SERVER_DOWN &amp;&amp; rc != LDAP_CONNECT_ERROR ) {
return( rc ); /* Return the result code. */
}
/* If the connection was lost, call
ldap_simple_bind_s() to reconnect. */
if ( ldap_simple_bind_s( ld, dn, passwd ) != LDAP_SUCCESS ) {
/* failure -- could not reconnect */
/* remember that ld as bad */
return( rc );
}
} while ( ++tries &lt; 2 );</programlisting>
</example>
</sect2>
</sect1>
</chapter>