summaryrefslogtreecommitdiffstats
path: root/ldap/c-sdk/libprldap
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/c-sdk/libprldap')
-rw-r--r--ldap/c-sdk/libprldap/ldappr-dns.c166
-rw-r--r--ldap/c-sdk/libprldap/ldappr-error.c335
-rw-r--r--ldap/c-sdk/libprldap/ldappr-int.h139
-rw-r--r--ldap/c-sdk/libprldap/ldappr-io.c744
-rw-r--r--ldap/c-sdk/libprldap/ldappr-public.c454
-rw-r--r--ldap/c-sdk/libprldap/ldappr-threads.c643
-rw-r--r--ldap/c-sdk/libprldap/libprldap.def59
-rw-r--r--ldap/c-sdk/libprldap/moz.build31
8 files changed, 2571 insertions, 0 deletions
diff --git a/ldap/c-sdk/libprldap/ldappr-dns.c b/ldap/c-sdk/libprldap/ldappr-dns.c
new file mode 100644
index 000000000..a88bfe31c
--- /dev/null
+++ b/ldap/c-sdk/libprldap/ldappr-dns.c
@@ -0,0 +1,166 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * DNS callback functions for libldap that use the NSPR (Netscape
+ * Portable Runtime) thread API.
+ *
+ */
+
+#include "ldappr-int.h"
+
+static LDAPHostEnt *prldap_gethostbyname( const char *name,
+ LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
+ void *extradata );
+static LDAPHostEnt *prldap_gethostbyaddr( const char *addr, int length,
+ int type, LDAPHostEnt *result, char *buffer, int buflen,
+ int *statusp, void *extradata );
+static int prldap_getpeername( LDAP *ld, struct sockaddr *addr,
+ char *buffer, int buflen );
+static LDAPHostEnt *prldap_convert_hostent( LDAPHostEnt *ldhp,
+ PRHostEnt *prhp );
+
+
+/*
+ * Install NSPR DNS functions into ld (if ld is NULL, they are installed
+ * as the default functions for new LDAP * handles).
+ *
+ * Returns 0 if all goes well and -1 if not.
+ */
+int
+prldap_install_dns_functions( LDAP *ld )
+{
+ struct ldap_dns_fns dnsfns;
+
+ memset( &dnsfns, '\0', sizeof(struct ldap_dns_fns) );
+ dnsfns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE;
+ dnsfns.lddnsfn_gethostbyname = prldap_gethostbyname;
+ dnsfns.lddnsfn_gethostbyaddr = prldap_gethostbyaddr;
+ dnsfns.lddnsfn_getpeername = prldap_getpeername;
+ if ( ldap_set_option( ld, LDAP_OPT_DNS_FN_PTRS, (void *)&dnsfns ) != 0 ) {
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+static LDAPHostEnt *
+prldap_gethostbyname( const char *name, LDAPHostEnt *result,
+ char *buffer, int buflen, int *statusp, void *extradata )
+{
+ PRHostEnt prhent;
+
+ if( !statusp || ( *statusp = (int)PR_GetIPNodeByName( name,
+ PRLDAP_DEFAULT_ADDRESS_FAMILY, PR_AI_DEFAULT,
+ buffer, buflen, &prhent )) == PR_FAILURE ) {
+ return( NULL );
+ }
+
+ return( prldap_convert_hostent( result, &prhent ));
+}
+
+
+static LDAPHostEnt *
+prldap_gethostbyaddr( const char *addr, int length, int type,
+ LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
+ void *extradata )
+{
+ PRHostEnt prhent;
+ PRNetAddr iaddr;
+
+ if ( NULL == statusp ) {
+ return( NULL );
+ }
+
+ memset( &iaddr, 0, sizeof( iaddr ));
+ if ( PR_StringToNetAddr( addr, &iaddr ) == PR_FAILURE ) {
+ return( NULL );
+ }
+ PRLDAP_SET_PORT( &iaddr, 0 );
+
+ if( PR_FAILURE == (*statusp =
+ PR_GetHostByAddr(&iaddr, buffer, buflen, &prhent ))) {
+ return( NULL );
+ }
+
+ return( prldap_convert_hostent( result, &prhent ));
+}
+
+
+static int
+prldap_getpeername( LDAP *ld, struct sockaddr *addr, char *buffer, int buflen)
+{
+ PRLDAPIOSocketArg *sa;
+ PRNetAddr iaddr;
+ int ret;
+
+ if (NULL != ld) {
+ ret = prldap_socket_arg_from_ld( ld, &sa );
+ if (ret != LDAP_SUCCESS) {
+ return (-1);
+ }
+ ret = PR_GetPeerName(sa->prsock_prfd, &iaddr);
+ if( ret == PR_FAILURE ) {
+ return( -1 );
+ }
+ *addr = *((struct sockaddr *)&iaddr.raw);
+ ret = PR_NetAddrToString(&iaddr, buffer, buflen);
+ if( ret == PR_FAILURE ) {
+ return( -1 );
+ }
+ return (0);
+ }
+ return (-1);
+}
+
+
+/*
+ * Function: prldap_convert_hostent()
+ * Description: copy the fields of a PRHostEnt struct to an LDAPHostEnt
+ * Returns: the LDAPHostEnt pointer passed in.
+ */
+static LDAPHostEnt *
+prldap_convert_hostent( LDAPHostEnt *ldhp, PRHostEnt *prhp )
+{
+ ldhp->ldaphe_name = prhp->h_name;
+ ldhp->ldaphe_aliases = prhp->h_aliases;
+ ldhp->ldaphe_addrtype = prhp->h_addrtype;
+ ldhp->ldaphe_length = prhp->h_length;
+ ldhp->ldaphe_addr_list = prhp->h_addr_list;
+ return( ldhp );
+}
diff --git a/ldap/c-sdk/libprldap/ldappr-error.c b/ldap/c-sdk/libprldap/ldappr-error.c
new file mode 100644
index 000000000..b0cb6ed96
--- /dev/null
+++ b/ldap/c-sdk/libprldap/ldappr-error.c
@@ -0,0 +1,335 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Utilities for manageing the relationship between NSPR errors and
+ * OS (errno-style) errors.
+ *
+ * The overall strategy used is to map NSPR errors into OS errors.
+ */
+
+#include "ldappr-int.h"
+
+void
+prldap_set_system_errno( int oserrno )
+{
+ PR_SetError( PR_GetError(), oserrno );
+}
+
+
+int
+prldap_get_system_errno( void )
+{
+ return( PR_GetOSError());
+}
+
+/*
+ * Retrieve the NSPR error number, convert to a system error code, and return
+ * the result.
+ */
+struct prldap_errormap_entry {
+ PRInt32 erm_nspr; /* NSPR error code */
+ int erm_system; /* corresponding system error code */
+};
+
+/* XXX: not sure if this extra mapping for Windows is good or correct */
+#ifdef _WINDOWS
+#ifndef ENOTSUP
+#define ENOTSUP -1
+#endif
+#ifndef ETIMEDOUT
+#define ETIMEDOUT WSAETIMEDOUT
+#endif
+#ifndef EADDRNOTAVAIL
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#endif
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif
+#ifndef EISCONN
+#define EISCONN WSAEISCONN
+#endif
+#ifndef EADDRINUSE
+#define EADDRINUSE WSAEADDRINUSE
+#endif
+#ifndef ECONNREFUSED
+#define ECONNREFUSED WSAECONNREFUSED
+#endif
+#ifndef EHOSTUNREACH
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#endif
+#ifndef ENOTCONN
+#define ENOTCONN WSAENOTCONN
+#endif
+#ifndef ENOTSOCK
+#define ENOTSOCK WSAENOTSOCK
+#endif
+#ifndef EPROTOTYPE
+#define EPROTOTYPE WSAEPROTOTYPE
+#endif
+#ifndef EOPNOTSUPP
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#endif
+#ifndef EPROTONOSUPPORT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#endif
+#ifndef EOVERFLOW
+#define EOVERFLOW -1
+#endif
+#ifndef ECONNRESET
+#define ECONNRESET WSAECONNRESET
+#endif
+#ifndef ELOOP
+#define ELOOP WSAELOOP
+#endif
+#ifndef ENOTBLK
+#define ENOTBLK -1
+#endif
+#ifndef ETXTBSY
+#define ETXTBSY -1
+#endif
+#ifndef ENETDOWN
+#define ENETDOWN WSAENETDOWN
+#endif
+#ifndef ESHUTDOWN
+#define ESHUTDOWN WSAESHUTDOWN
+#endif
+#ifndef ECONNABORTED
+#define ECONNABORTED WSAECONNABORTED
+#endif
+#endif /* _WINDOWS */
+
+#if defined(macintosh)
+/*
+ * Some Unix error defs. Under CW 7, we can't define OTUNIXERRORS because
+ * it generates many conflicts with errno.h. Define what we need here.
+ * These need to be in sync with OpenTransport.h
+ */
+#define EWOULDBLOCK 35
+#define ENOTSOCK 38
+#define EPROTOTYPE 41
+#define EPROTONOSUPPORT 43
+#define EOPNOTSUPP 45
+#define EADDRINUSE 48
+#define EADDRNOTAVAIL 49
+#define ENETDOWN 50
+#define ECONNABORTED 53
+#define ECONNRESET 54
+#define EISCONN 56
+#define ENOTCONN 57
+#define ESHUTDOWN 58
+#define ETIMEDOUT 60
+#define ECONNREFUSED 61
+#define EHOSTUNREACH 65
+#define EAFNOSUPPORT -1
+#define ELOOP -1
+#define ENOTBLK -1
+#define ENOTSUP -1
+#define EOVERFLOW -1
+#define ETXTBSY -1
+#endif /* macintosh */
+
+#ifdef XP_OS2
+#define SOCBASEERR 0
+#endif
+#ifndef ENOTSUP
+#define ENOTSUP -1
+#endif
+#ifndef EOVERFLOW
+#define EOVERFLOW -1
+#endif
+#ifndef EDEADLOCK
+#define EDEADLOCK -1
+#endif
+#ifndef EFAULT
+#define EFAULT SOCEFAULT
+#endif
+#ifndef EPIPE
+#define EPIPE SOCEPIPE
+#endif
+#ifndef EIO
+#define EIO (SOCBASEERR+5)
+#endif
+#ifndef EDEADLK
+#define EDEADLK (SOCBASEERR+11)
+#endif
+#ifndef ENOTBLK
+#define ENOTBLK (SOCBASEERR+15)
+#endif
+#ifndef EBUSY
+#define EBUSY (SOCBASEERR+16)
+#endif
+#ifndef ENOTDIR
+#define ENOTDIR (SOCBASEERR+20)
+#endif
+#ifndef EISDIR
+#define EISDIR (SOCBASEERR+21)
+#endif
+#ifndef ENFILE
+#define ENFILE (SOCBASEERR+23)
+#endif
+#ifndef ETXTBSY
+#define ETXTBSY (SOCBASEERR+26)
+#endif
+#ifndef EFBIG
+#define EFBIG (SOCBASEERR+27)
+#endif
+#ifndef ESPIPE
+#define ESPIPE (SOCBASEERR+29)
+#endif
+#ifndef EROFS
+#define EROFS (SOCBASEERR+30)
+#endif
+
+#ifdef BEOS
+#define ENOTSUP -1
+#define ENOTBLK -1
+#define ETXTBSY -1
+#endif
+
+#if defined(BSDI) || defined(OPENBSD) || defined (NETBSD)
+#define ENOTSUP -1
+#endif
+
+#if defined(OSF1) || defined(BSDI) || defined(VMS) || defined(OPENBSD)
+#define EOVERFLOW -1
+#endif
+
+#if defined(__hpux) || defined(_AIX) || defined(OSF1) || defined(DARWIN) || \
+ defined(BEOS) || defined(FREEBSD) || defined(BSDI) || defined(VMS) || \
+ defined(OPENBSD) || defined(NETBSD)
+#define EDEADLOCK -1
+#endif
+
+/* XXX: need to verify that the -1 entries are correct (no mapping) */
+static struct prldap_errormap_entry prldap_errormap[] = {
+ { PR_OUT_OF_MEMORY_ERROR, ENOMEM },
+ { PR_BAD_DESCRIPTOR_ERROR, EBADF },
+ { PR_WOULD_BLOCK_ERROR, EAGAIN },
+ { PR_ACCESS_FAULT_ERROR, EFAULT },
+ { PR_INVALID_METHOD_ERROR, EINVAL }, /* XXX: correct mapping ? */
+ { PR_ILLEGAL_ACCESS_ERROR, EACCES }, /* XXX: correct mapping ? */
+ { PR_UNKNOWN_ERROR, -1 },
+ { PR_PENDING_INTERRUPT_ERROR, -1 },
+ { PR_NOT_IMPLEMENTED_ERROR, ENOTSUP },
+ { PR_IO_ERROR, EIO },
+ { PR_IO_TIMEOUT_ERROR, ETIMEDOUT }, /* XXX: correct mapping ? */
+ { PR_IO_PENDING_ERROR, -1 },
+ { PR_DIRECTORY_OPEN_ERROR, ENOTDIR },
+ { PR_INVALID_ARGUMENT_ERROR, EINVAL },
+ { PR_ADDRESS_NOT_AVAILABLE_ERROR, EADDRNOTAVAIL },
+ { PR_ADDRESS_NOT_SUPPORTED_ERROR, EAFNOSUPPORT },
+ { PR_IS_CONNECTED_ERROR, EISCONN },
+ { PR_BAD_ADDRESS_ERROR, EFAULT }, /* XXX: correct mapping ? */
+ { PR_ADDRESS_IN_USE_ERROR, EADDRINUSE },
+ { PR_CONNECT_REFUSED_ERROR, ECONNREFUSED },
+ { PR_NETWORK_UNREACHABLE_ERROR, EHOSTUNREACH },
+ { PR_CONNECT_TIMEOUT_ERROR, ETIMEDOUT },
+ { PR_NOT_CONNECTED_ERROR, ENOTCONN },
+ { PR_LOAD_LIBRARY_ERROR, -1 },
+ { PR_UNLOAD_LIBRARY_ERROR, -1 },
+ { PR_FIND_SYMBOL_ERROR, -1 },
+ { PR_INSUFFICIENT_RESOURCES_ERROR, -1 },
+ { PR_DIRECTORY_LOOKUP_ERROR, EHOSTUNREACH },/* an approximation */
+ { PR_TPD_RANGE_ERROR, -1 },
+ { PR_PROC_DESC_TABLE_FULL_ERROR, -1 },
+ { PR_SYS_DESC_TABLE_FULL_ERROR, -1 },
+ { PR_NOT_SOCKET_ERROR, ENOTSOCK },
+ { PR_NOT_TCP_SOCKET_ERROR, EPROTOTYPE },
+ { PR_SOCKET_ADDRESS_IS_BOUND_ERROR, -1 },
+ { PR_NO_ACCESS_RIGHTS_ERROR, EACCES }, /* XXX: correct mapping ? */
+ { PR_OPERATION_NOT_SUPPORTED_ERROR, EOPNOTSUPP },
+ { PR_PROTOCOL_NOT_SUPPORTED_ERROR, EPROTONOSUPPORT },
+ { PR_REMOTE_FILE_ERROR, -1 },
+ { PR_BUFFER_OVERFLOW_ERROR, EOVERFLOW },
+ { PR_CONNECT_RESET_ERROR, ECONNRESET },
+ { PR_RANGE_ERROR, ERANGE },
+ { PR_DEADLOCK_ERROR, EDEADLK },
+ { PR_FILE_IS_LOCKED_ERROR, EDEADLOCK }, /* XXX: correct mapping ? */
+ { PR_FILE_TOO_BIG_ERROR, EFBIG },
+ { PR_NO_DEVICE_SPACE_ERROR, ENOSPC },
+ { PR_PIPE_ERROR, EPIPE },
+ { PR_NO_SEEK_DEVICE_ERROR, ESPIPE },
+ { PR_IS_DIRECTORY_ERROR, EISDIR },
+ { PR_LOOP_ERROR, ELOOP },
+ { PR_NAME_TOO_LONG_ERROR, ENAMETOOLONG },
+ { PR_FILE_NOT_FOUND_ERROR, ENOENT },
+ { PR_NOT_DIRECTORY_ERROR, ENOTDIR },
+ { PR_READ_ONLY_FILESYSTEM_ERROR, EROFS },
+ { PR_DIRECTORY_NOT_EMPTY_ERROR, ENOTEMPTY },
+ { PR_FILESYSTEM_MOUNTED_ERROR, EBUSY },
+ { PR_NOT_SAME_DEVICE_ERROR, EXDEV },
+ { PR_DIRECTORY_CORRUPTED_ERROR, -1 },
+ { PR_FILE_EXISTS_ERROR, EEXIST },
+ { PR_MAX_DIRECTORY_ENTRIES_ERROR, -1 },
+ { PR_INVALID_DEVICE_STATE_ERROR, ENOTBLK }, /* XXX: correct mapping ? */
+ { PR_DEVICE_IS_LOCKED_ERROR, -2 },
+ { PR_NO_MORE_FILES_ERROR, ENFILE },
+ { PR_END_OF_FILE_ERROR, -1 },
+ { PR_FILE_SEEK_ERROR, ESPIPE }, /* XXX: correct mapping ? */
+ { PR_FILE_IS_BUSY_ERROR, ETXTBSY },
+ { PR_OPERATION_ABORTED_ERROR, -1 },
+ { PR_IN_PROGRESS_ERROR, -1 },
+ { PR_ALREADY_INITIATED_ERROR, -1 },
+ { PR_GROUP_EMPTY_ERROR, -1 },
+ { PR_INVALID_STATE_ERROR, -1 },
+ { PR_NETWORK_DOWN_ERROR, ENETDOWN },
+ { PR_SOCKET_SHUTDOWN_ERROR, ESHUTDOWN },
+ { PR_CONNECT_ABORTED_ERROR, ECONNABORTED },
+ { PR_HOST_UNREACHABLE_ERROR, EHOSTUNREACH },
+ { PR_MAX_ERROR, -1 },
+};
+
+
+int
+prldap_prerr2errno( void )
+{
+ int oserr, i;
+ PRInt32 nsprerr;
+
+ nsprerr = PR_GetError();
+
+ oserr = -1; /* unknown */
+ for ( i = 0; prldap_errormap[i].erm_nspr != PR_MAX_ERROR; ++i ) {
+ if ( prldap_errormap[i].erm_nspr == nsprerr ) {
+ oserr = prldap_errormap[i].erm_system;
+ break;
+ }
+ }
+
+ return( oserr );
+}
diff --git a/ldap/c-sdk/libprldap/ldappr-int.h b/ldap/c-sdk/libprldap/ldappr-int.h
new file mode 100644
index 000000000..ed4bfbce6
--- /dev/null
+++ b/ldap/c-sdk/libprldap/ldappr-int.h
@@ -0,0 +1,139 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Internal header for libprldap -- glue NSPR (Netscape Portable Runtime)
+ * to libldap.
+ *
+ */
+
+#include "ldap.h"
+#include "nspr.h"
+#include "ldappr.h"
+
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+
+/*
+ * Macros:
+ */
+
+/* #define PRLDAP_DEBUG 1 */ /* uncomment to enable debugging printfs */
+
+/*
+ * All of the sockets we use are IPv6 capable.
+ * Change the following #define to PR_AF_INET to support IPv4 only.
+ */
+#define PRLDAP_DEFAULT_ADDRESS_FAMILY PR_AF_INET6
+
+/*
+ * Max length for sending message with one PR_Send.
+ * If a single message is larger than this size, the message is divided
+ * into multiple pieces up to this length and sent out. This is necessary
+ * on Microsoft Windows at least where attempts to send really large
+ * messages in one PR_Send() call result in an error.
+ */
+#define PRLDAP_MAX_SEND_SIZE (8*1024*1024) /* 8MB */
+
+/*
+ * Macro to set port to the 'port' field of a NSPR PRNetAddr union.
+ ** INPUTS:
+ ** PRNetAddr *myaddr A network address.
+ ** PRUint16 myport port to set to the 'port' field of 'addr'.
+ ** RETURN: none
+ */
+#define PRLDAP_SET_PORT(myaddr,myport) \
+ ((myaddr)->raw.family == PR_AF_INET6 ? ((myaddr)->ipv6.port = PR_htons(myport)) : ((myaddr)->inet.port = PR_htons(myport)))
+
+/*
+ * Data structures:
+ */
+
+/* data structure that populates the I/O callback session arg. */
+typedef struct lextiof_session_private {
+ PRPollDesc *prsess_pollds; /* for poll callback */
+ int prsess_pollds_count; /* # of elements in pollds */
+ int prsess_io_max_timeout; /* in milliseconds */
+ void *prsess_appdata; /* application specific data */
+} PRLDAPIOSessionArg;
+
+/* data structure that populates the I/O callback socket-specific arg. */
+typedef struct lextiof_socket_private {
+ PRFileDesc *prsock_prfd; /* associated NSPR file desc. */
+ int prsock_io_max_timeout; /* in milliseconds */
+ void *prsock_appdata; /* application specific data */
+} PRLDAPIOSocketArg;
+
+
+/*
+ * Function prototypes:
+ */
+
+/*
+ * From ldapprio.c:
+ */
+int prldap_install_io_functions( LDAP *ld, int shared );
+int prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp );
+int prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp,
+ int io_max_timeout );
+int prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp,
+ int *io_max_timeoutp );
+int prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp );
+PRLDAPIOSocketArg *prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg );
+
+
+/*
+ * From ldapprthreads.c:
+ */
+int prldap_install_thread_functions( LDAP *ld, int shared );
+int prldap_thread_new_handle( LDAP *ld, void *sessionarg );
+void prldap_thread_dispose_handle( LDAP *ld, void *sessionarg );
+
+
+/*
+ * From ldapprdns.c:
+ */
+int prldap_install_dns_functions( LDAP *ld );
+
+
+/*
+ * From ldapprerror.c:
+ */
+void prldap_set_system_errno( int e );
+int prldap_get_system_errno( void );
+int prldap_prerr2errno( void );
diff --git a/ldap/c-sdk/libprldap/ldappr-io.c b/ldap/c-sdk/libprldap/ldappr-io.c
new file mode 100644
index 000000000..863545146
--- /dev/null
+++ b/ldap/c-sdk/libprldap/ldappr-io.c
@@ -0,0 +1,744 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Extended I/O callback functions for libldap that use
+ * NSPR (Netscape Portable Runtime) I/O.
+ *
+ * High level strategy: we use the socket-specific arg to hold our own data
+ * structure that includes the NSPR file handle (PRFileDesc *), among other
+ * useful information. We use the default argument to hold an LDAP session
+ * handle specific data structure.
+ */
+
+#include "ldappr-int.h"
+
+#define PRLDAP_POLL_ARRAY_GROWTH 5 /* grow arrays 5 elements at a time */
+
+/*
+ * Local function prototypes:
+ */
+static PRIntervalTime prldap_timeout2it( int ms_timeout, int ms_maxtimeout );
+static int LDAP_CALLBACK prldap_read( int s, void *buf, int bufsize,
+ struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_write( int s, const void *buf, int len,
+ struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_poll( LDAP_X_PollFD fds[], int nfds,
+ int timeout, struct lextiof_session_private *sessionarg );
+static int LDAP_CALLBACK prldap_connect( const char *hostlist, int defport,
+ int timeout, unsigned long options,
+ struct lextiof_session_private *sessionarg,
+ struct lextiof_socket_private **socketargp );
+static int LDAP_CALLBACK prldap_close( int s,
+ struct lextiof_socket_private *socketarg );
+static int LDAP_CALLBACK prldap_newhandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static void LDAP_CALLBACK prldap_disposehandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static int LDAP_CALLBACK prldap_shared_newhandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static void LDAP_CALLBACK prldap_shared_disposehandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg );
+static PRLDAPIOSessionArg *prldap_session_arg_alloc( void );
+static void prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp );
+static void prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp );
+static void *prldap_safe_realloc( void *ptr, PRUint32 size );
+
+
+
+/*
+ * Local macros:
+ */
+/* given a socket-specific arg, return the corresponding PRFileDesc * */
+#define PRLDAP_GET_PRFD( socketarg ) \
+ (((PRLDAPIOSocketArg *)(socketarg))->prsock_prfd)
+
+/*
+ * Static variables.
+ */
+static int prldap_default_io_max_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
+
+
+/*
+ * Install NSPR I/O functions into ld (if ld is NULL, they are installed
+ * as the default functions for new LDAP * handles).
+ *
+ * Returns 0 if all goes well and -1 if not.
+ */
+int
+prldap_install_io_functions( LDAP *ld, int shared )
+{
+ struct ldap_x_ext_io_fns iofns;
+
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ iofns.lextiof_read = prldap_read;
+ iofns.lextiof_write = prldap_write;
+ iofns.lextiof_poll = prldap_poll;
+ iofns.lextiof_connect = prldap_connect;
+ iofns.lextiof_close = prldap_close;
+ if ( shared ) {
+ iofns.lextiof_newhandle = prldap_shared_newhandle;
+ iofns.lextiof_disposehandle = prldap_shared_disposehandle;
+ } else {
+ iofns.lextiof_newhandle = prldap_newhandle;
+ iofns.lextiof_disposehandle = prldap_disposehandle;
+ }
+ if ( NULL != ld ) {
+ /*
+ * If we are dealing with a real ld, we allocate the session specific
+ * data structure now. If not allocated here, it will be allocated
+ * inside prldap_newhandle() or prldap_shared_newhandle().
+ */
+ if ( NULL ==
+ ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
+ ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( -1 );
+ }
+ } else {
+ iofns.lextiof_session_arg = NULL;
+ }
+
+ if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &iofns ) != 0 ) {
+ prldap_session_arg_free(
+ (PRLDAPIOSessionArg **) &iofns.lextiof_session_arg );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+static PRIntervalTime
+prldap_timeout2it( int ms_timeout, int ms_maxtimeout )
+{
+ PRIntervalTime prit;
+
+ if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_timeout ) {
+ prit = PR_INTERVAL_NO_WAIT;
+ } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ) {
+ prit = PR_INTERVAL_NO_TIMEOUT;
+ } else {
+ prit = PR_MillisecondsToInterval( ms_timeout );
+ }
+
+ /* cap at maximum I/O timeout */
+ if ( LDAP_X_IO_TIMEOUT_NO_WAIT == ms_maxtimeout ) {
+ prit = LDAP_X_IO_TIMEOUT_NO_WAIT;
+ } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT != ms_maxtimeout ) {
+ if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT == ms_timeout ||
+ ms_timeout > ms_maxtimeout ) {
+ prit = PR_MillisecondsToInterval( ms_maxtimeout );
+ }
+ }
+
+#ifdef PRLDAP_DEBUG
+ if ( PR_INTERVAL_NO_WAIT == prit ) {
+ fprintf( stderr, "prldap_timeout2it: NO_WAIT\n" );
+ } else if ( PR_INTERVAL_NO_TIMEOUT == prit ) {
+ fprintf( stderr, "prldap_timeout2it: NO_TIMEOUT\n" );
+ } else {
+ fprintf( stderr, "prldap_timeout2it: %dms\n",
+ PR_IntervalToMilliseconds(prit));
+ }
+#endif /* PRLDAP_DEBUG */
+
+ return( prit );
+}
+
+
+static int LDAP_CALLBACK
+prldap_read( int s, void *buf, int bufsize,
+ struct lextiof_socket_private *socketarg )
+{
+ PRIntervalTime prit;
+
+ prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
+ socketarg->prsock_io_max_timeout );
+ return( PR_Recv( PRLDAP_GET_PRFD(socketarg), buf, bufsize, 0, prit ));
+}
+
+
+static int LDAP_CALLBACK
+prldap_write( int s, const void *buf, int len,
+ struct lextiof_socket_private *socketarg )
+{
+ PRIntervalTime prit;
+ char *ptr = (char *)buf;
+ int rest = len;
+
+ prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
+ socketarg->prsock_io_max_timeout );
+
+ while ( rest > 0 ) {
+ int rval;
+ if ( rest > PRLDAP_MAX_SEND_SIZE ) {
+ len = PRLDAP_MAX_SEND_SIZE;
+ } else {
+ len = rest;
+ }
+ /*
+ * Note the 4th parameter (flags) to PR_Send() has been obsoleted and
+ * must always be 0
+ */
+ rval = PR_Send( PRLDAP_GET_PRFD(socketarg), ptr, len, 0, prit );
+ if ( 0 > rval ) {
+ return rval;
+ }
+
+ if ( 0 == rval ) {
+ break;
+ }
+
+ ptr += rval;
+ rest -= rval;
+ }
+
+ return (int)( ptr - (char *)buf );
+}
+
+
+struct prldap_eventmap_entry {
+ PRInt16 evm_nspr; /* corresponding NSPR PR_Poll() event */
+ int evm_ldap; /* LDAP poll event */
+};
+
+static struct prldap_eventmap_entry prldap_eventmap[] = {
+ { PR_POLL_READ, LDAP_X_POLLIN },
+ { PR_POLL_EXCEPT, LDAP_X_POLLPRI },
+ { PR_POLL_WRITE, LDAP_X_POLLOUT },
+ { PR_POLL_ERR, LDAP_X_POLLERR },
+ { PR_POLL_HUP, LDAP_X_POLLHUP },
+ { PR_POLL_NVAL, LDAP_X_POLLNVAL },
+};
+
+#define PRLDAP_EVENTMAP_ENTRIES \
+ sizeof(prldap_eventmap)/sizeof(struct prldap_eventmap_entry )
+
+static int LDAP_CALLBACK
+prldap_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
+ struct lextiof_session_private *sessionarg )
+{
+ PRLDAPIOSessionArg *prsessp = sessionarg;
+ PRPollDesc *pds;
+ int i, j, rc;
+
+ if ( NULL == prsessp ) {
+ prldap_set_system_errno( EINVAL );
+ return( -1 );
+ }
+
+ /* allocate or resize NSPR poll descriptor array */
+ if ( prsessp->prsess_pollds_count < nfds ) {
+ pds = prldap_safe_realloc( prsessp->prsess_pollds,
+ ( nfds + PRLDAP_POLL_ARRAY_GROWTH )
+ * sizeof( PRPollDesc ));
+ if ( NULL == pds ) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ return( -1 );
+ }
+ prsessp->prsess_pollds = pds;
+ prsessp->prsess_pollds_count = nfds + PRLDAP_POLL_ARRAY_GROWTH;
+ } else {
+ pds = prsessp->prsess_pollds;
+ }
+
+ /* populate NSPR poll info. based on LDAP info. */
+ for ( i = 0; i < nfds; ++i ) {
+ if ( NULL == fds[i].lpoll_socketarg ) {
+ pds[i].fd = NULL;
+ } else {
+ pds[i].fd = PRLDAP_GET_PRFD( fds[i].lpoll_socketarg );
+ }
+ pds[i].in_flags = pds[i].out_flags = 0;
+ if ( fds[i].lpoll_fd >= 0 ) {
+ for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
+ if (( fds[i].lpoll_events & prldap_eventmap[j].evm_ldap )
+ != 0 ) {
+ pds[i].in_flags |= prldap_eventmap[j].evm_nspr;
+ }
+ }
+ }
+ fds[i].lpoll_revents = 0; /* clear revents */
+ }
+
+ /* call PR_Poll() to do the real work */
+ rc = PR_Poll( pds, nfds,
+ prldap_timeout2it( timeout, prsessp->prsess_io_max_timeout ));
+
+ /* populate LDAP info. based on NSPR results */
+ for ( i = 0; i < nfds; ++i ) {
+ if ( pds[i].fd != NULL ) {
+ for ( j = 0; j < PRLDAP_EVENTMAP_ENTRIES; ++j ) {
+ if (( pds[i].out_flags & prldap_eventmap[j].evm_nspr )
+ != 0 ) {
+ fds[i].lpoll_revents |= prldap_eventmap[j].evm_ldap;
+ }
+ }
+ }
+ }
+
+ return( rc );
+}
+
+
+/*
+ * Utility function to try one TCP connect()
+ * Returns 1 if successful and -1 if not. Sets the NSPR fd inside prsockp.
+ */
+static int
+prldap_try_one_address( struct lextiof_socket_private *prsockp,
+ PRNetAddr *addrp, int timeout, unsigned long options )
+{
+ /*
+ * Open a TCP socket:
+ */
+ if (( prsockp->prsock_prfd = PR_OpenTCPSocket(
+ PR_NetAddrFamily(addrp) )) == NULL ) {
+ return( -1 );
+ }
+
+ /*
+ * Set nonblocking option if requested:
+ */
+ if ( 0 != ( options & LDAP_X_EXTIOF_OPT_NONBLOCKING )) {
+ PRSocketOptionData optdata;
+
+ optdata.option = PR_SockOpt_Nonblocking;
+ optdata.value.non_blocking = PR_TRUE;
+ if ( PR_SetSocketOption( prsockp->prsock_prfd, &optdata )
+ != PR_SUCCESS ) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ PR_Close( prsockp->prsock_prfd );
+ return( -1 );
+ }
+ }
+
+#ifdef PRLDAP_DEBUG
+ {
+ char buf[ 256 ], *p, *fmtstr;
+
+ if ( PR_SUCCESS != PR_NetAddrToString( addrp, buf, sizeof(buf ))) {
+ strcpy( buf, "conversion failed!" );
+ }
+ if ( strncmp( buf, "::ffff:", 7 ) == 0 ) {
+ /* IPv4 address mapped into IPv6 address space */
+ p = buf + 7;
+ fmtstr = "prldap_try_one_address(): Trying %s:%d...\n";
+ } else {
+ p = buf;
+ fmtstr = "prldap_try_one_address(): Trying [%s]:%d...\n";
+ }
+ fprintf( stderr, fmtstr, p, PR_ntohs( addrp->ipv6.port ));
+ }
+#endif /* PRLDAP_DEBUG */
+
+ /*
+ * Try to open the TCP connection itself:
+ */
+ if ( PR_SUCCESS != PR_Connect( prsockp->prsock_prfd, addrp,
+ prldap_timeout2it( timeout, prsockp->prsock_io_max_timeout ))
+ && PR_IN_PROGRESS_ERROR != PR_GetError() ) {
+ PR_Close( prsockp->prsock_prfd );
+ prsockp->prsock_prfd = NULL;
+ return( -1 );
+ }
+
+#ifdef PRLDAP_DEBUG
+ fputs( "prldap_try_one_address(): Connected.\n", stderr );
+#endif /* PRLDAP_DEBUG */
+
+ /*
+ * Success. Return a valid file descriptor (1 is always valid)
+ */
+ return( 1 );
+}
+
+
+/*
+ * XXXmcs: At present, this code ignores the timeout when doing DNS lookups.
+ */
+static int LDAP_CALLBACK
+prldap_connect( const char *hostlist, int defport, int timeout,
+ unsigned long options, struct lextiof_session_private *sessionarg,
+ struct lextiof_socket_private **socketargp )
+{
+ int rc, parse_err, port;
+ char *host;
+ struct ldap_x_hostlist_status *status;
+ struct lextiof_socket_private *prsockp;
+ PRNetAddr addr;
+ PRAddrInfo *infop = NULL;
+
+ if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
+ prldap_set_system_errno( EINVAL );
+ return( -1 );
+ }
+
+ if ( NULL == ( prsockp = prldap_socket_arg_alloc( sessionarg ))) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ return( -1 );
+ }
+
+ rc = -1; /* pessimistic */
+ for ( parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
+ &status );
+ rc < 0 && LDAP_SUCCESS == parse_err && NULL != host;
+ parse_err = ldap_x_hostlist_next( &host, &port, status )) {
+ /*
+ * First, call PR_GetAddrInfoByName; PR_GetAddrInfoByName could
+ * support both IPv4 and IPv6 addresses depending upon the system's
+ * configuration. All available addresses are returned and each of
+ * them is examined in prldap_try_one_address till it succeeds.
+ * Then, try converting the string address, in case the string
+ * address was not successfully handled in PR_GetAddrInfoByName.
+ */
+ if ( NULL != ( infop =
+ PR_GetAddrInfoByName( host, PR_AF_UNSPEC,
+ (PR_AI_ADDRCONFIG|PR_AI_NOCANONNAME) ))) {
+ void *enump = NULL;
+ do {
+ memset( &addr, 0, sizeof( addr ));
+ enump = PR_EnumerateAddrInfo( enump, infop, port, &addr );
+ if ( NULL == enump ) {
+ break;
+ }
+ rc = prldap_try_one_address( prsockp, &addr, timeout, options );
+ } while ( rc < 0 );
+ PR_FreeAddrInfo( infop );
+ } else if ( PR_SUCCESS == PR_StringToNetAddr( host, &addr )) {
+ PRLDAP_SET_PORT( &addr, port );
+ rc = prldap_try_one_address( prsockp, &addr, timeout, options );
+ }
+ ldap_memfree( host );
+ }
+
+ if ( host ) {
+ ldap_memfree( host );
+ }
+ ldap_x_hostlist_statusfree( status );
+
+ if ( rc < 0 ) {
+ prldap_set_system_errno( prldap_prerr2errno());
+ prldap_socket_arg_free( &prsockp );
+ } else {
+ *socketargp = prsockp;
+ }
+
+ return( rc );
+}
+
+
+static int LDAP_CALLBACK
+prldap_close( int s, struct lextiof_socket_private *socketarg )
+{
+ int rc;
+
+ rc = 0;
+ if ( PR_Close( PRLDAP_GET_PRFD(socketarg)) != PR_SUCCESS ) {
+ rc = -1;
+ prldap_set_system_errno( prldap_prerr2errno());
+ }
+ prldap_socket_arg_free( &socketarg );
+
+ return( rc );
+}
+
+
+/*
+ * LDAP session handle creation callback.
+ *
+ * Allocate a session argument if not already done, and then call the
+ * thread's new handle function.
+ */
+static int LDAP_CALLBACK
+prldap_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+
+ if ( NULL == sessionarg ) {
+ struct ldap_x_ext_io_fns iofns;
+
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+ (void *)&iofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+ if ( NULL ==
+ ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
+ return( LDAP_NO_MEMORY );
+ }
+ if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
+ (void *)&iofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+/* only called/installed if shared is non-zero. */
+static int LDAP_CALLBACK
+prldap_shared_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+ int rc;
+
+ if (( rc = prldap_newhandle( ld, sessionarg )) == LDAP_SUCCESS ) {
+ rc = prldap_thread_new_handle( ld, sessionarg );
+ }
+
+ return( rc );
+}
+
+
+static void LDAP_CALLBACK
+prldap_disposehandle( LDAP *ld, struct lextiof_session_private *sessionarg )
+{
+ prldap_session_arg_free( &sessionarg );
+}
+
+
+/* only called/installed if shared is non-zero */
+static void LDAP_CALLBACK
+prldap_shared_disposehandle( LDAP *ld,
+ struct lextiof_session_private *sessionarg )
+{
+ prldap_thread_dispose_handle( ld, sessionarg );
+ prldap_disposehandle( ld, sessionarg );
+}
+
+
+/*
+ * Allocate a session argument.
+ */
+static PRLDAPIOSessionArg *
+prldap_session_arg_alloc( void )
+{
+ PRLDAPIOSessionArg *prsessp;
+
+ prsessp = PR_Calloc( 1, sizeof( PRLDAPIOSessionArg ));
+
+ if ( NULL != prsessp ) {
+ /* copy global defaults to the new session handle */
+ prsessp->prsess_io_max_timeout = prldap_default_io_max_timeout;
+ }
+
+ return( prsessp );
+}
+
+
+static void
+prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp )
+{
+ if ( NULL != prsesspp && NULL != *prsesspp ) {
+ if ( NULL != (*prsesspp)->prsess_pollds ) {
+ PR_Free( (*prsesspp)->prsess_pollds );
+ (*prsesspp)->prsess_pollds = NULL;
+ }
+ PR_Free( *prsesspp );
+ *prsesspp = NULL;
+ }
+}
+
+
+/*
+ * Given an LDAP session handle, retrieve a session argument.
+ * Returns an LDAP error code.
+ */
+int
+prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp )
+{
+ struct ldap_x_ext_io_fns iofns;
+
+ if ( NULL == ld || NULL == sessargpp ) {
+ /* XXXmcs: NULL ld's are not supported */
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ if ( NULL == iofns.lextiof_session_arg ) {
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ *sessargpp = iofns.lextiof_session_arg;
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Given an LDAP session handle, retrieve a socket argument.
+ * Returns an LDAP error code.
+ */
+int
+prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp )
+{
+ Sockbuf *sbp;
+ struct lber_x_ext_io_fns extiofns;
+
+ if ( NULL == ld || NULL == sockargpp ) {
+ /* XXXmcs: NULL ld's are not supported */
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( ldap_get_option( ld, LDAP_X_OPT_SOCKBUF, (void *)&sbp ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ memset( &extiofns, 0, sizeof(extiofns));
+ extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ if ( ber_sockbuf_get_option( sbp, LBER_SOCKBUF_OPT_EXT_IO_FNS,
+ (void *)&extiofns ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ if ( NULL == extiofns.lbextiofn_socket_arg ) {
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ *sockargpp = extiofns.lbextiofn_socket_arg;
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Allocate a socket argument.
+ */
+PRLDAPIOSocketArg *
+prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg )
+{
+ PRLDAPIOSocketArg *prsockp;
+
+ prsockp = PR_Calloc( 1, sizeof( PRLDAPIOSocketArg ));
+
+ if ( NULL != prsockp && NULL != sessionarg ) {
+ /* copy socket defaults from the session */
+ prsockp->prsock_io_max_timeout = sessionarg->prsess_io_max_timeout;
+ }
+
+ return( prsockp );
+}
+
+
+static void
+prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp )
+{
+ if ( NULL != prsockpp && NULL != *prsockpp ) {
+ PR_Free( *prsockpp );
+ *prsockpp = NULL;
+ }
+}
+
+
+static void *
+prldap_safe_realloc( void *ptr, PRUint32 size )
+{
+ void *p;
+
+ if ( NULL == ptr ) {
+ p = PR_Malloc( size );
+ } else {
+ p = PR_Realloc( ptr, size );
+ }
+
+ return( p );
+}
+
+
+
+/* returns an LDAP result code */
+int
+prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp, int io_max_timeout )
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+
+ if ( NULL == prsessp ) {
+ prldap_default_io_max_timeout = io_max_timeout;
+ } else {
+ prsessp->prsess_io_max_timeout = io_max_timeout;
+ }
+
+ return( rc );
+}
+
+
+/* returns an LDAP result code */
+int
+prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp, int *io_max_timeoutp )
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+
+ if ( NULL == io_max_timeoutp ) {
+ rc = LDAP_PARAM_ERROR;
+ } else if ( NULL == prsessp ) {
+ *io_max_timeoutp = prldap_default_io_max_timeout;
+ } else {
+ *io_max_timeoutp = prsessp->prsess_io_max_timeout;
+ }
+
+ return( rc );
+}
+
+/* Check if NSPR layer has been installed for a LDAP session.
+ * Simply check whether prldap_connect() I/O function is installed
+ */
+PRBool
+prldap_is_installed( LDAP *ld )
+{
+ struct ldap_x_ext_io_fns iofns;
+
+ /* Retrieve current I/O functions */
+ memset( &iofns, 0, sizeof(iofns));
+ iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
+ if ( ld == NULL || ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
+ != 0 || iofns.lextiof_connect != prldap_connect )
+ {
+ return( PR_FALSE );
+ }
+
+ return( PR_TRUE );
+}
+
diff --git a/ldap/c-sdk/libprldap/ldappr-public.c b/ldap/c-sdk/libprldap/ldappr-public.c
new file mode 100644
index 000000000..6e9e597e6
--- /dev/null
+++ b/ldap/c-sdk/libprldap/ldappr-public.c
@@ -0,0 +1,454 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Public interface for libprldap -- use NSPR (Netscape Portable Runtime)
+ * I/O, threads, etc. with libldap.
+ *
+ */
+
+#include "ldappr-int.h"
+#include <private/pprio.h>
+
+/*
+ * Function: prldap_init().
+ *
+ * Create a new LDAP session handle, but with NSPR I/O, threading, and DNS
+ * functions installed.
+ *
+ * Pass a non-zero value for the 'shared' parameter if you plan to use
+ * this LDAP * handle from more than one thread.
+ *
+ * prldap_init() returns an LDAP session handle (or NULL if an error occurs).
+ */
+LDAP * LDAP_CALL
+prldap_init( const char *defhost, int defport, int shared )
+{
+ LDAP *ld;
+
+ if (( ld = ldap_init( defhost, defport )) != NULL ) {
+ if ( prldap_install_routines( ld, shared ) != LDAP_SUCCESS ) {
+ prldap_set_system_errno( EINVAL ); /* XXXmcs: just a guess! */
+ ldap_unbind( ld );
+ ld = NULL;
+ }
+ }
+
+ return( ld );
+}
+
+
+/*
+ * Function: prldap_install_routines().
+ *
+ * Install NSPR I/O, threading, and DNS functions so they will be used by
+ * 'ld'.
+ *
+ * If 'ld' is NULL, the functions are installed as the default functions
+ * for all new LDAP * handles).
+ *
+ * Pass a non-zero value for the 'shared' parameter if you plan to use
+ * this LDAP * handle from more than one thread.
+ *
+ * prldap_install_routines() returns an LDAP API error code (LDAP_SUCCESS
+ * if all goes well).
+ */
+int LDAP_CALL
+prldap_install_routines( LDAP *ld, int shared )
+{
+
+ if ( prldap_install_io_functions( ld, shared ) != 0
+ || prldap_install_thread_functions( ld, shared ) != 0
+ || prldap_install_dns_functions( ld ) != 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_set_session_option().
+ *
+ * Given an LDAP session handle or a session argument such is passed to
+ * SOCKET, POLL, NEWHANDLE, or DISPOSEHANDLE extended I/O callbacks, set
+ * an option that affects the prldap layer.
+ *
+ * If 'ld' and 'session" are both NULL, the option is set as the default
+ * for all new prldap sessions.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL
+prldap_set_session_option( LDAP *ld, void *sessionarg, int option, ... )
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+ PRLDAPIOSessionArg *prsessp = NULL;
+ va_list ap;
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+ return( rc );
+ }
+ } else if ( NULL != sessionarg ) {
+ prsessp = (PRLDAPIOSessionArg *)sessionarg;
+ }
+
+ va_start( ap, option );
+ switch ( option ) {
+ case PRLDAP_OPT_IO_MAX_TIMEOUT:
+ rc = prldap_set_io_max_timeout( prsessp, va_arg( ap, int ));
+ break;
+ default:
+ rc = LDAP_PARAM_ERROR;
+ }
+ va_end( ap );
+
+ return( rc );
+}
+
+
+/*
+ * Function: prldap_get_session_option().
+ *
+ * Given an LDAP session handle or a session argument such is passed to
+ * SOCKET, POLL, NEWHANDLE, or DISPOSEHANDLE extended I/O callbacks, retrieve
+ * the setting for an option that affects the prldap layer.
+ *
+ * If 'ld' and 'session" are both NULL, the default option value for all new
+ * new prldap sessions is retrieved.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL prldap_get_session_option( LDAP *ld, void *sessionarg,
+ int option, ... )
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+ PRLDAPIOSessionArg *prsessp = NULL;
+ va_list ap;
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+ return( rc );
+ }
+ } else if ( NULL != sessionarg ) {
+ prsessp = (PRLDAPIOSessionArg *)sessionarg;
+ }
+
+ va_start( ap, option );
+ switch ( option ) {
+ case PRLDAP_OPT_IO_MAX_TIMEOUT:
+ rc = prldap_get_io_max_timeout( prsessp, va_arg( ap, int * ));
+ break;
+ default:
+ rc = LDAP_PARAM_ERROR;
+ }
+ va_end( ap );
+
+ return( rc );
+}
+
+
+/*
+ * Function: prldap_set_session_info().
+ *
+ * Given an LDAP session handle, set some application-specific data.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ */
+int LDAP_CALL
+prldap_set_session_info( LDAP *ld, void *sessionarg, PRLDAPSessionInfo *seip )
+{
+ int rc;
+ PRLDAPIOSessionArg *prsessp;
+
+ if ( seip == NULL || PRLDAP_SESSIONINFO_SIZE != seip->seinfo_size ) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+ return( rc );
+ }
+ } else if ( NULL != sessionarg ) {
+ prsessp = (PRLDAPIOSessionArg *)sessionarg;
+ } else {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ prsessp->prsess_appdata = seip->seinfo_appdata;
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_get_session_info().
+ *
+ * Given an LDAP session handle, retrieve some application-specific data.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that seip points to are filled in).
+ */
+int LDAP_CALL
+prldap_get_session_info( LDAP *ld, void *sessionarg, PRLDAPSessionInfo *seip )
+{
+ int rc;
+ PRLDAPIOSessionArg *prsessp;
+
+ if ( seip == NULL || PRLDAP_SESSIONINFO_SIZE != seip->seinfo_size ) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+ return( rc );
+ }
+ } else if ( NULL != sessionarg ) {
+ prsessp = (PRLDAPIOSessionArg *)sessionarg;
+ } else {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ seip->seinfo_appdata = prsessp->prsess_appdata;
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_set_socket_info().
+ *
+ * Given an integer fd and a void * argument such as those passed to the
+ * extended I/O callback functions, set socket specific information.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well).
+ *
+ * Note: it is only safe to change soinfo_prfd from within the SOCKET
+ * extended I/O callback function.
+ */
+int LDAP_CALL
+prldap_set_socket_info( int fd, void *socketarg, PRLDAPSocketInfo *soip )
+{
+ PRLDAPIOSocketArg *prsockp;
+
+ if ( NULL == socketarg || NULL == soip ||
+ PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ prsockp = (PRLDAPIOSocketArg *)socketarg;
+ prsockp->prsock_prfd = soip->soinfo_prfd;
+ prsockp->prsock_appdata = soip->soinfo_appdata;
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_get_socket_info().
+ *
+ * Given an integer fd and a void * argument such as those passed to the
+ * extended I/O callback functions, retrieve socket specific information.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL
+prldap_get_socket_info( int fd, void *socketarg, PRLDAPSocketInfo *soip )
+{
+ PRLDAPIOSocketArg *prsockp;
+
+ if ( NULL == socketarg || NULL == soip ||
+ PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+ return( LDAP_PARAM_ERROR );
+ }
+
+ prsockp = (PRLDAPIOSocketArg *)socketarg;
+ soip->soinfo_prfd = prsockp->prsock_prfd;
+ soip->soinfo_appdata = prsockp->prsock_appdata;
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_get_default_socket_info().
+ *
+ * Given an LDAP session handle, retrieve socket specific information.
+ * If ld is NULL, LDAP_PARAM_ERROR is returned.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL
+prldap_get_default_socket_info( LDAP *ld, PRLDAPSocketInfo *soip )
+{
+ int rc;
+ PRLDAPIOSocketArg *prsockp;
+
+
+ if ( NULL == soip || PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_socket_arg_from_ld( ld, &prsockp ))) {
+ return( rc );
+ }
+ } else {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ soip->soinfo_prfd = prsockp->prsock_prfd;
+ soip->soinfo_appdata = prsockp->prsock_appdata;
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_set_default_socket_info().
+ *
+ * Given an LDAP session handle, set socket specific information.
+ * If ld is NULL, LDAP_PARAM_ERROR is returned.
+ *
+ * Returns an LDAP API error code (LDAP_SUCCESS if all goes well, in
+ * which case the fields in the structure that soip points to are filled in).
+ */
+int LDAP_CALL
+prldap_set_default_socket_info( LDAP *ld, PRLDAPSocketInfo *soip )
+{
+ int rc;
+ PRLDAPIOSocketArg *prsockp;
+
+
+ if ( NULL == soip || PRLDAP_SOCKETINFO_SIZE != soip->soinfo_size ) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( NULL != ld ) {
+ if ( LDAP_SUCCESS !=
+ ( rc = prldap_socket_arg_from_ld( ld, &prsockp ))) {
+ return( rc );
+ }
+ } else {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ prsockp->prsock_prfd = soip->soinfo_prfd;
+ prsockp->prsock_appdata = soip->soinfo_appdata;
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+* Function: prldap_import_connection().
+*
+* Given the LDAP handle the connection parameters for the
+* file descriptor are imported into NSPR layer.
+*
+* Returns an LDAP API code (LDAP_SUCCESS) if all goes well.
+*/
+int LDAP_CALL
+prldap_import_connection (LDAP *ld)
+{
+ int rc = LDAP_SUCCESS; /* optimistic */
+ int shared = 1; /* Assume shared init */
+ LBER_SOCKET orig_socket = -1;
+ PRLDAPIOSessionArg *prsessp = NULL;
+ PRLDAPIOSocketArg *prsockp = NULL;
+ PRFileDesc *pr_socket = NULL;
+
+ /* Check for invalid ld handle */
+ if ( ld == NULL) {
+ ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ /* Retrieve TCP socket's integer file descriptor */
+ if ( ldap_get_option( ld, LDAP_OPT_DESC, &orig_socket ) < 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ /* Check for NSPR functions on ld */
+ if ( prldap_is_installed(ld)) { /* Error : NSPR already Installed */
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ if (LDAP_SUCCESS != (rc = prldap_install_routines(ld, shared))) {
+ return( rc );
+ }
+
+ if (LDAP_SUCCESS != (rc = prldap_session_arg_from_ld( ld, &prsessp ))) {
+ return( rc );
+ }
+
+ /* Get NSPR Socket Arg */
+ if ( NULL == ( prsockp = prldap_socket_arg_alloc( prsessp ))) {
+ ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
+ return( LDAP_NO_MEMORY );
+ }
+
+ /* Import file descriptor of connection made via ldap_init() */
+ if (NULL == (pr_socket = PR_ImportTCPSocket(orig_socket)) ) {
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ prsockp->prsock_prfd = pr_socket;
+
+ /* Set Socket Arg in Extended I/O Layer */
+ if ( ldap_set_option( ld, LDAP_X_OPT_SOCKETARG, prsockp) != 0 ) {
+ return( ldap_get_lderrno( ld, NULL, NULL ));
+ }
+
+ return( rc );
+}
diff --git a/ldap/c-sdk/libprldap/ldappr-threads.c b/ldap/c-sdk/libprldap/ldappr-threads.c
new file mode 100644
index 000000000..1cfdc9263
--- /dev/null
+++ b/ldap/c-sdk/libprldap/ldappr-threads.c
@@ -0,0 +1,643 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Thread callback functions for libldap that use the NSPR (Netscape
+ * Portable Runtime) thread API.
+ *
+ */
+
+#include "ldappr-int.h"
+
+/*
+ * Macros:
+ */
+/*
+ * Grow thread private data arrays 10 elements at a time.
+ */
+#define PRLDAP_TPD_ARRAY_INCREMENT 10
+
+/*
+ * Structures and types:
+ */
+/*
+ * Structure used by libldap thread callbacks to maintain error information.
+ */
+typedef struct prldap_errorinfo {
+ int plei_magic; /* must be first in the structure */
+ int plei_lderrno;
+ char *plei_matched;
+ char *plei_errmsg;
+} PRLDAP_ErrorInfo;
+
+#define PRLDAP_ERRORINFO_MAGIC 0x4D4F5A45 /* 'MOZE' */
+
+
+/*
+ * Structure used to maintain thread-private data. At the present time,
+ * only error info. is thread-private. One of these structures is allocated
+ * for each thread.
+ */
+typedef struct prldap_tpd_header {
+ int ptpdh_tpd_count; /* # of data items allocated */
+ void **ptpdh_dataitems; /* array of data items */
+} PRLDAP_TPDHeader;
+
+/*
+ * Structure used by associate a PRLDAP thread-private data index with an
+ * LDAP session handle. One of these exists for each active LDAP session
+ * handle.
+ */
+typedef struct prldap_tpd_map {
+ LDAP *prtm_ld; /* non-NULL if in use */
+ PRUintn prtm_index; /* index into TPD array */
+ struct prldap_tpd_map *prtm_next;
+} PRLDAP_TPDMap;
+
+
+
+/*
+ * Static Variables:
+ */
+/*
+ * prldap_map_list points to all of the PRLDAP_TPDMap structures
+ * we have ever allocated. We recycle them as we open and close LDAP
+ * sessions.
+ */
+static PRLDAP_TPDMap *prldap_map_list = NULL;
+
+
+/*
+ * The prldap_map_mutex is used to protect access to the prldap_map_list.
+ */
+static PRLock *prldap_map_mutex = NULL;
+
+/*
+ * The prldap_tpd_maxindex value is used to track the largest TPD array
+ * index we have used.
+ */
+static PRInt32 prldap_tpd_maxindex = -1;
+
+/*
+ * prldap_tpdindex is an NSPR thread private data index we use to
+ * maintain our own thread-private data. It is initialized inside
+ * prldap_init_tpd().
+ */
+static PRUintn prldap_tpdindex = 0;
+
+/*
+ * The prldap_callonce_init_tpd structure is used by NSPR to ensure
+ * that prldap_init_tpd() is called at most once.
+ */
+static PRCallOnceType prldap_callonce_init_tpd = { 0, 0, 0 };
+
+
+/*
+ * Private function prototypes:
+ */
+static void prldap_set_ld_error( int err, char *matched, char *errmsg,
+ void *errorarg );
+static int prldap_get_ld_error( char **matchedp, char **errmsgp,
+ void *errorarg );
+static void *prldap_mutex_alloc( void );
+static void prldap_mutex_free( void *mutex );
+static int prldap_mutex_lock( void *mutex );
+static int prldap_mutex_unlock( void *mutex );
+static void *prldap_get_thread_id( void );
+static PRStatus prldap_init_tpd( void );
+static PRLDAP_TPDMap *prldap_allocate_map( LDAP *ld );
+static void prldap_return_map( PRLDAP_TPDMap *map );
+static PRUintn prldap_new_tpdindex( void );
+static int prldap_set_thread_private( PRInt32 tpdindex, void *priv );
+static void *prldap_get_thread_private( PRInt32 tpdindex );
+static PRLDAP_TPDHeader *prldap_tsd_realloc( PRLDAP_TPDHeader *tsdhdr,
+ int maxindex );
+static void prldap_tsd_destroy( void *priv );
+
+
+/*
+ * Install NSPR thread functions into ld (if ld is NULL, they are installed
+ * as the default functions for new LDAP * handles).
+ *
+ * Returns 0 if all goes well and -1 if not.
+ */
+int
+prldap_install_thread_functions( LDAP *ld, int shared )
+{
+ struct ldap_thread_fns tfns;
+ struct ldap_extra_thread_fns xtfns;
+
+ if ( PR_CallOnce( &prldap_callonce_init_tpd, prldap_init_tpd )
+ != PR_SUCCESS ) {
+ ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
+ return( -1 );
+ }
+
+ /* set thread function pointers */
+ memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
+ tfns.ltf_get_errno = prldap_get_system_errno;
+ tfns.ltf_set_errno = prldap_set_system_errno;
+ if ( shared ) {
+ tfns.ltf_mutex_alloc = prldap_mutex_alloc;
+ tfns.ltf_mutex_free = prldap_mutex_free;
+ tfns.ltf_mutex_lock = prldap_mutex_lock;
+ tfns.ltf_mutex_unlock = prldap_mutex_unlock;
+ tfns.ltf_get_lderrno = prldap_get_ld_error;
+ tfns.ltf_set_lderrno = prldap_set_ld_error;
+ if ( ld != NULL ) {
+ /*
+ * If this is a real ld (i.e., we are not setting the global
+ * defaults) allocate thread private data for error information.
+ * If ld is NULL we do not do this here but it is done in
+ * prldap_thread_new_handle().
+ */
+ if (( tfns.ltf_lderrno_arg = (void *)prldap_allocate_map( ld ))
+ == NULL ) {
+ return( -1 );
+ }
+ }
+ }
+
+ if ( ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS,
+ (void *)&tfns ) != 0 ) {
+ prldap_return_map( (PRLDAP_TPDMap *)tfns.ltf_lderrno_arg );
+ return( -1 );
+ }
+
+ /* set extended thread function pointers */
+ memset( &xtfns, '\0', sizeof(struct ldap_extra_thread_fns) );
+ xtfns.ltf_threadid_fn = prldap_get_thread_id;
+ if ( ldap_set_option( ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
+ (void *)&xtfns ) != 0 ) {
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+static void *
+prldap_mutex_alloc( void )
+{
+ return( (void *)PR_NewLock());
+}
+
+
+static void
+prldap_mutex_free( void *mutex )
+{
+ PR_DestroyLock( (PRLock *)mutex );
+}
+
+
+static int
+prldap_mutex_lock( void *mutex )
+{
+ PR_Lock( (PRLock *)mutex );
+ return( 0 );
+}
+
+
+static int
+prldap_mutex_unlock( void *mutex )
+{
+ if ( PR_Unlock( (PRLock *)mutex ) == PR_FAILURE ) {
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+static void *
+prldap_get_thread_id( void )
+{
+ return( (void *)PR_GetCurrentThread());
+}
+
+
+static int
+prldap_get_ld_error( char **matchedp, char **errmsgp, void *errorarg )
+{
+ PRLDAP_TPDMap *map;
+ PRLDAP_ErrorInfo *eip;
+
+ if (( map = (PRLDAP_TPDMap *)errorarg ) != NULL && ( eip =
+ (PRLDAP_ErrorInfo *)prldap_get_thread_private(
+ map->prtm_index )) != NULL ) {
+ if ( matchedp != NULL ) {
+ *matchedp = eip->plei_matched;
+ }
+ if ( errmsgp != NULL ) {
+ *errmsgp = eip->plei_errmsg;
+ }
+ return( eip->plei_lderrno );
+ } else {
+ if ( matchedp != NULL ) {
+ *matchedp = NULL;
+ }
+ if ( errmsgp != NULL ) {
+ *errmsgp = NULL;
+ }
+ return( LDAP_LOCAL_ERROR ); /* punt */
+ }
+}
+
+
+static void
+prldap_set_ld_error( int err, char *matched, char *errmsg, void *errorarg )
+{
+ PRLDAP_TPDMap *map;
+ PRLDAP_ErrorInfo *eip;
+
+ if (( map = (PRLDAP_TPDMap *)errorarg ) != NULL ) {
+ if (( eip = (PRLDAP_ErrorInfo *)prldap_get_thread_private(
+ map->prtm_index )) == NULL ) {
+ /*
+ * Error info. has not yet been allocated for this thread.
+ * Do so now. Note that we free this memory only for the
+ * thread that calls prldap_thread_dispose_handle(), which
+ * should be the one that called ldap_unbind() -- see
+ * prldap_return_map(). Not freeing the memory used by
+ * other threads is deemed acceptable since it will be
+ * recycled and used by other LDAP sessions. All of the
+ * thread-private memory is freed when a thread exits
+ * (inside the prldap_tsd_destroy() function).
+ */
+ eip = (PRLDAP_ErrorInfo *)PR_Calloc( 1,
+ sizeof( PRLDAP_ErrorInfo ));
+ if ( eip == NULL ) {
+ return; /* punt */
+ }
+ eip->plei_magic = PRLDAP_ERRORINFO_MAGIC;
+ (void)prldap_set_thread_private( map->prtm_index, eip );
+ }
+
+ eip->plei_lderrno = err;
+
+ if ( eip->plei_matched != NULL ) {
+ ldap_memfree( eip->plei_matched );
+ }
+ eip->plei_matched = matched;
+
+ if ( eip->plei_errmsg != NULL ) {
+ ldap_memfree( eip->plei_errmsg );
+ }
+ eip->plei_errmsg = errmsg;
+ }
+}
+
+
+/*
+ * Utility function to free a PRLDAP_ErrorInfo structure and everything
+ * it contains.
+ */
+static void
+prldap_free_errorinfo( PRLDAP_ErrorInfo *eip )
+{
+ if ( NULL != eip && PRLDAP_ERRORINFO_MAGIC == eip->plei_magic ) {
+ if ( eip->plei_matched != NULL ) {
+ ldap_memfree( eip->plei_matched );
+ }
+ if ( eip->plei_errmsg != NULL ) {
+ ldap_memfree( eip->plei_errmsg );
+ }
+
+ PR_Free( eip );
+ }
+}
+
+
+/*
+ * Called when a new LDAP * session handle is allocated.
+ * Allocate thread-private data for error information, but only if
+ * it has not already been allocated and the get_ld_error callback has
+ * been installed. If ld is not NULL when prldap_install_thread_functions()
+ * is called, we will have already allocated the thread-private data there.
+ */
+int
+prldap_thread_new_handle( LDAP *ld, void *sessionarg )
+{
+ struct ldap_thread_fns tfns;
+
+ if ( ldap_get_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *)&tfns ) != 0 ) {
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ if ( tfns.ltf_lderrno_arg == NULL && tfns.ltf_get_lderrno != NULL ) {
+ if (( tfns.ltf_lderrno_arg = (void *)prldap_allocate_map( ld )) == NULL
+ || ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS,
+ (void *)&tfns ) != 0 ) {
+ return( LDAP_LOCAL_ERROR );
+ }
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Called when an LDAP * session handle is being destroyed.
+ * Clean up our thread private data map.
+ */
+void
+prldap_thread_dispose_handle( LDAP *ld, void *sessionarg )
+{
+ struct ldap_thread_fns tfns;
+
+ if ( ldap_get_option( ld, LDAP_OPT_THREAD_FN_PTRS,
+ (void *)&tfns ) == 0 &&
+ tfns.ltf_lderrno_arg != NULL ) {
+ prldap_return_map( (PRLDAP_TPDMap *)tfns.ltf_lderrno_arg );
+ }
+}
+
+
+static PRStatus
+prldap_init_tpd( void )
+{
+ if (( prldap_map_mutex = PR_NewLock()) == NULL || PR_NewThreadPrivateIndex(
+ &prldap_tpdindex, prldap_tsd_destroy ) != PR_SUCCESS ) {
+ return( PR_FAILURE );
+ }
+
+ prldap_map_list = NULL;
+
+ return( PR_SUCCESS );
+}
+
+
+/*
+ * Function: prldap_allocate_map()
+ * Description: allocate a thread-private data map to use for a new
+ * LDAP session handle.
+ * Returns: a pointer to the TPD map or NULL if none available.
+ */
+static PRLDAP_TPDMap *
+prldap_allocate_map( LDAP *ld )
+{
+ PRLDAP_TPDMap *map, *prevmap;
+
+ PR_Lock( prldap_map_mutex );
+
+ /*
+ * first look for a map that is already allocated but free to be re-used
+ */
+ prevmap = NULL;
+ for ( map = prldap_map_list; map != NULL; map = map->prtm_next ) {
+ if ( map->prtm_ld == NULL ) {
+ break;
+ }
+ prevmap = map;
+ }
+
+ /*
+ * if none was found (map == NULL), try to allocate a new one and add it
+ * to the end of our global list.
+ */
+ if ( map == NULL ) {
+ PRUintn tpdindex;
+
+ tpdindex = prldap_new_tpdindex();
+ map = (PRLDAP_TPDMap *)PR_Malloc( sizeof( PRLDAP_TPDMap ));
+ if ( map != NULL ) {
+ map->prtm_index = tpdindex;
+ map->prtm_next = NULL;
+ if ( prevmap == NULL ) {
+ prldap_map_list = map;
+ } else {
+ prevmap->prtm_next = map;
+ }
+ }
+ }
+
+ if ( map != NULL ) {
+ map->prtm_ld = ld; /* now marked as "in use" */
+
+ /*
+ * If old thread-private error information exists, reset it. It may
+ * have been left behind by an old LDAP session that was used by
+ * this thread but disposed of by a different thread.
+ */
+ if ( NULL != prldap_get_thread_private( map->prtm_index )) {
+ prldap_set_ld_error( LDAP_SUCCESS, NULL, NULL, map );
+ }
+ }
+
+ PR_Unlock( prldap_map_mutex );
+
+ return( map );
+}
+
+
+/*
+ * Function: prldap_return_map()
+ * Description: return a thread-private data map to the pool of ones
+ * available for re-use.
+ */
+static void
+prldap_return_map( PRLDAP_TPDMap *map )
+{
+ PRLDAP_ErrorInfo *eip;
+
+ PR_Lock( prldap_map_mutex );
+
+ /*
+ * Dispose of thread-private LDAP error information. Note that this
+ * only disposes of the memory consumed on THIS thread, but that is
+ * okay. See the comment in prldap_set_ld_error() for the reason why.
+ */
+ if (( eip = (PRLDAP_ErrorInfo *)prldap_get_thread_private(
+ map->prtm_index )) != NULL &&
+ prldap_set_thread_private( map->prtm_index, NULL ) == 0 ) {
+ prldap_free_errorinfo( eip );
+ }
+
+ /* mark map as available for re-use */
+ map->prtm_ld = NULL;
+
+ PR_Unlock( prldap_map_mutex );
+}
+
+
+/*
+ * Function: prldap_new_tpdindex()
+ * Description: allocate a thread-private data index.
+ * Returns: the new index.
+ */
+static PRUintn
+prldap_new_tpdindex( void )
+{
+ PRUintn tpdindex;
+
+ tpdindex = (PRUintn)PR_AtomicIncrement( &prldap_tpd_maxindex );
+ return( tpdindex );
+}
+
+
+/*
+ * Function: prldap_set_thread_private()
+ * Description: store a piece of thread-private data.
+ * Returns: 0 if successful and -1 if not.
+ */
+static int
+prldap_set_thread_private( PRInt32 tpdindex, void *priv )
+{
+ PRLDAP_TPDHeader *tsdhdr;
+
+ if ( tpdindex > prldap_tpd_maxindex ) {
+ return( -1 ); /* bad index */
+ }
+
+ tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
+ if ( tsdhdr == NULL || tpdindex >= tsdhdr->ptpdh_tpd_count ) {
+ tsdhdr = prldap_tsd_realloc( tsdhdr, tpdindex );
+ if ( tsdhdr == NULL ) {
+ return( -1 ); /* realloc failed */
+ }
+ }
+
+ tsdhdr->ptpdh_dataitems[ tpdindex ] = priv;
+ return( 0 );
+}
+
+
+/*
+ * Function: prldap_get_thread_private()
+ * Description: retrieve a piece of thread-private data. If not set,
+ * NULL is returned.
+ * Returns: 0 if successful and -1 if not.
+ */
+static void *
+prldap_get_thread_private( PRInt32 tpdindex )
+{
+ PRLDAP_TPDHeader *tsdhdr;
+
+ tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
+ if ( tsdhdr == NULL ) {
+ return( NULL ); /* no thread private data */
+ }
+
+ if ( tpdindex >= tsdhdr->ptpdh_tpd_count
+ || tsdhdr->ptpdh_dataitems == NULL ) {
+ return( NULL ); /* fewer data items than requested index */
+ }
+
+ return( tsdhdr->ptpdh_dataitems[ tpdindex ] );
+}
+
+
+/*
+ * Function: prldap_tsd_realloc()
+ * Description: enlarge the thread-private data array.
+ * Returns: the new PRLDAP_TPDHeader value (non-NULL if successful).
+ * Note: tsdhdr can be NULL (allocates a new PRLDAP_TPDHeader).
+ */
+static PRLDAP_TPDHeader *
+prldap_tsd_realloc( PRLDAP_TPDHeader *tsdhdr, int maxindex )
+{
+ void *newdataitems = NULL;
+ int count;
+
+ if ( tsdhdr == NULL ) {
+ /* allocate a new thread private data header */
+ if (( tsdhdr = PR_Calloc( 1, sizeof( PRLDAP_TPDHeader ))) == NULL ) {
+ return( NULL );
+ }
+ (void)PR_SetThreadPrivate( prldap_tpdindex, tsdhdr );
+ }
+
+ /*
+ * Make the size of the new array the next highest multiple of
+ * the array increment value that is greater than maxindex.
+ */
+ count = PRLDAP_TPD_ARRAY_INCREMENT *
+ ( 1 + ( maxindex / PRLDAP_TPD_ARRAY_INCREMENT ));
+
+ /* increase the size of the data item array if necessary */
+ if ( count > tsdhdr->ptpdh_tpd_count ) {
+ newdataitems = (PRLDAP_ErrorInfo *)PR_Calloc( count, sizeof( void * ));
+ if ( newdataitems == NULL ) {
+ return( NULL );
+ }
+ if ( tsdhdr->ptpdh_dataitems != NULL ) { /* preserve old data */
+ memcpy( newdataitems, tsdhdr->ptpdh_dataitems,
+ tsdhdr->ptpdh_tpd_count * sizeof( void * ));
+ PR_Free( tsdhdr->ptpdh_dataitems );
+ }
+
+ tsdhdr->ptpdh_tpd_count = count;
+ tsdhdr->ptpdh_dataitems = newdataitems;
+ }
+
+ return( tsdhdr );
+}
+
+
+/*
+ * Function: prldap_tsd_destroy()
+ * Description: Free a thread-private data array. Installed as an NSPR TPD
+ * destructor function
+ * Returns: nothing.
+ */
+static void
+prldap_tsd_destroy( void *priv )
+{
+ PRLDAP_TPDHeader *tsdhdr;
+ PRLDAP_ErrorInfo *eip;
+ int i;
+
+ tsdhdr = (PRLDAP_TPDHeader *)priv;
+ if ( tsdhdr != NULL ) {
+ if ( tsdhdr->ptpdh_dataitems != NULL ) {
+ for ( i = 0; i < tsdhdr->ptpdh_tpd_count; ++i ) {
+ if ( tsdhdr->ptpdh_dataitems[ i ] != NULL ) {
+ eip = (PRLDAP_ErrorInfo *)tsdhdr->ptpdh_dataitems[ i ];
+ if ( PRLDAP_ERRORINFO_MAGIC == eip->plei_magic ) {
+ prldap_free_errorinfo( eip );
+ } else {
+ PR_Free( tsdhdr->ptpdh_dataitems[ i ] );
+ }
+ tsdhdr->ptpdh_dataitems[ i ] = NULL;
+ }
+ }
+ PR_Free( tsdhdr->ptpdh_dataitems );
+ tsdhdr->ptpdh_dataitems = NULL;
+ }
+ PR_Free( tsdhdr );
+ }
+}
diff --git a/ldap/c-sdk/libprldap/libprldap.def b/ldap/c-sdk/libprldap/libprldap.def
new file mode 100644
index 000000000..a18e7ee82
--- /dev/null
+++ b/ldap/c-sdk/libprldap/libprldap.def
@@ -0,0 +1,59 @@
+;
+; ***** BEGIN LICENSE BLOCK *****
+; Version: MPL 1.1/GPL 2.0/LGPL 2.1
+;
+; The contents of this file are subject to the Mozilla Public License Version
+; 1.1 (the "License"); you may not use this file except in compliance with
+; the License. You may obtain a copy of the License at
+; http://www.mozilla.org/MPL/
+;
+; Software distributed under the License is distributed on an "AS IS" basis,
+; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+; for the specific language governing rights and limitations under the
+; License.
+;
+; The Original Code is Mozilla Communicator client code.
+;
+; The Initial Developer of the Original Code is
+; Netscape Communications Corporation.
+; Portions created by the Initial Developer are Copyright (C) 1996-1999
+; the Initial Developer. All Rights Reserved.
+;
+; Contributor(s):
+;
+; Alternatively, the contents of this file may be used under the terms of
+; either of the GNU General Public License Version 2 or later (the "GPL"),
+; or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+; in which case the provisions of the GPL or the LGPL are applicable instead
+; of those above. If you wish to allow use of your version of this file only
+; under the terms of either the GPL or the LGPL, and not to allow others to
+; use your version of this file under the terms of the MPL, indicate your
+; decision by deleting the provisions above and replace them with the notice
+; and other provisions required by the GPL or the LGPL. If you do not delete
+; the provisions above, a recipient may use your version of this file under
+; the terms of any one of the MPL, the GPL or the LGPL.
+;
+; ***** END LICENSE BLOCK *****
+
+LIBRARY PRLDAP60
+VERSION 6.0
+HEAPSIZE 4096
+
+EXPORTS
+; exports list (generated by genexports.pl)
+;
+
+ prldap_init
+ prldap_install_routines
+ prldap_set_session_info
+ prldap_get_session_info
+ prldap_set_socket_info
+ prldap_get_socket_info
+ prldap_set_session_option
+ prldap_get_session_option
+ prldap_is_installed
+ prldap_import_connection
+ prldap_set_default_socket_info
+ prldap_get_default_socket_info
+;
+; end of generated exports list.
diff --git a/ldap/c-sdk/libprldap/moz.build b/ldap/c-sdk/libprldap/moz.build
new file mode 100644
index 000000000..4b096a73f
--- /dev/null
+++ b/ldap/c-sdk/libprldap/moz.build
@@ -0,0 +1,31 @@
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+include('../common.mozbuild')
+
+SharedLibrary('prldap60')
+
+SOURCES += [
+ 'ldappr-dns.c',
+ 'ldappr-error.c',
+ 'ldappr-io.c',
+ 'ldappr-public.c',
+ 'ldappr-threads.c',
+]
+
+if CONFIG['OS_ARCH'] == 'WINNT':
+ DEFFILE = SRCDIR + '/libprldap.def'
+
+DEFINES['USE_WAITPID'] = True
+DEFINES['NEEDPROTOS'] = True
+
+LOCAL_INCLUDES += [
+ '../include'
+]
+
+USE_LIBS += [
+ 'ldap60',
+ 'nspr'
+]