From 6513e41cb75e64384f35470d59ad6a4f88092e82 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Sun, 3 Nov 2019 13:17:15 -0500 Subject: Issue #1258 - Part 2: Use binoc-central version of ldap --- ldap/c-sdk/libprldap/ldappr-dns.c | 166 ++++++++ ldap/c-sdk/libprldap/ldappr-error.c | 335 +++++++++++++++ ldap/c-sdk/libprldap/ldappr-int.h | 139 +++++++ ldap/c-sdk/libprldap/ldappr-io.c | 744 ++++++++++++++++++++++++++++++++++ ldap/c-sdk/libprldap/ldappr-public.c | 454 +++++++++++++++++++++ ldap/c-sdk/libprldap/ldappr-threads.c | 643 +++++++++++++++++++++++++++++ ldap/c-sdk/libprldap/libprldap.def | 59 +++ ldap/c-sdk/libprldap/moz.build | 31 ++ 8 files changed, 2571 insertions(+) create mode 100644 ldap/c-sdk/libprldap/ldappr-dns.c create mode 100644 ldap/c-sdk/libprldap/ldappr-error.c create mode 100644 ldap/c-sdk/libprldap/ldappr-int.h create mode 100644 ldap/c-sdk/libprldap/ldappr-io.c create mode 100644 ldap/c-sdk/libprldap/ldappr-public.c create mode 100644 ldap/c-sdk/libprldap/ldappr-threads.c create mode 100644 ldap/c-sdk/libprldap/libprldap.def create mode 100644 ldap/c-sdk/libprldap/moz.build (limited to 'ldap/c-sdk/libprldap') 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 +#include +#include + +/* + * 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 + +/* + * 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' +] -- cgit v1.2.3