2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * The contents of this file are subject to the Netscape Public
8 * License Version 1.1 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of
10 * the License at http://www.mozilla.org/NPL/
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is Netscape
21 * Communications Corporation. Portions created by Netscape are
22 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
29 * Extended I/O callback functions for libldap that use
30 * NSPR (Netscape Portable Runtime) I/O.
32 * High level strategy: we use the socket-specific arg to hold our own data
33 * structure that includes the NSPR file handle (PRFileDesc *), among other
34 * useful information. We use the default argument to hold an LDAP session
35 * handle specific data structure.
38 #include "ldappr-int.h"
41 #define PRLDAP_POLL_ARRAY_GROWTH 5 /* grow arrays 5 elements at a time */
44 * Local function prototypes:
46 static PRIntervalTime
prldap_timeout2it( int ms_timeout
, int ms_maxtimeout
);
47 static int LDAP_CALLBACK
prldap_read( int s
, void *buf
, int bufsize
,
48 struct lextiof_socket_private
*socketarg
);
49 static int LDAP_CALLBACK
prldap_write( int s
, const void *buf
, int len
,
50 struct lextiof_socket_private
*socketarg
);
51 static int LDAP_CALLBACK
prldap_poll( LDAP_X_PollFD fds
[], int nfds
,
52 int timeout
, struct lextiof_session_private
*sessionarg
);
53 static int LDAP_CALLBACK
prldap_connect( const char *hostlist
, int defport
,
54 int timeout
, unsigned long options
,
55 struct lextiof_session_private
*sessionarg
,
56 struct lextiof_socket_private
**socketargp
61 #endif /* _SOLARIS_SDK */
62 static int LDAP_CALLBACK
prldap_close( int s
,
63 struct lextiof_socket_private
*socketarg
);
64 static int LDAP_CALLBACK
prldap_newhandle( LDAP
*ld
,
65 struct lextiof_session_private
*sessionarg
);
66 static void LDAP_CALLBACK
prldap_disposehandle( LDAP
*ld
,
67 struct lextiof_session_private
*sessionarg
);
68 static int LDAP_CALLBACK
prldap_shared_newhandle( LDAP
*ld
,
69 struct lextiof_session_private
*sessionarg
);
70 static void LDAP_CALLBACK
prldap_shared_disposehandle( LDAP
*ld
,
71 struct lextiof_session_private
*sessionarg
);
72 static PRLDAPIOSessionArg
*prldap_session_arg_alloc( void );
73 static void prldap_session_arg_free( PRLDAPIOSessionArg
**prsesspp
);
74 static PRLDAPIOSocketArg
*prldap_socket_arg_alloc( PRLDAPIOSessionArg
*sessionarg
);
75 static void prldap_socket_arg_free( PRLDAPIOSocketArg
**prsockpp
);
76 static void *prldap_safe_realloc( void *ptr
, PRUint32 size
);
83 /* given a socket-specific arg, return the corresponding PRFileDesc * */
84 #define PRLDAP_GET_PRFD( socketarg ) \
85 (((PRLDAPIOSocketArg *)(socketarg))->prsock_prfd)
90 static int prldap_default_io_max_timeout
= LDAP_X_IO_TIMEOUT_NO_TIMEOUT
;
93 * Install NSPR I/O functions into ld (if ld is NULL, they are installed
94 * as the default functions for new LDAP * handles).
96 * Returns 0 if all goes well and -1 if not.
99 prldap_install_io_functions( LDAP
*ld
, int shared
)
101 struct ldap_x_ext_io_fns iofns
;
103 memset( &iofns
, 0, sizeof(iofns
));
104 iofns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
105 iofns
.lextiof_read
= prldap_read
;
106 iofns
.lextiof_write
= prldap_write
;
107 iofns
.lextiof_poll
= prldap_poll
;
108 iofns
.lextiof_connect
= prldap_connect
;
109 iofns
.lextiof_close
= prldap_close
;
111 iofns
.lextiof_newhandle
= prldap_shared_newhandle
;
112 iofns
.lextiof_disposehandle
= prldap_shared_disposehandle
;
114 iofns
.lextiof_newhandle
= prldap_newhandle
;
115 iofns
.lextiof_disposehandle
= prldap_disposehandle
;
119 * If we are dealing with a real ld, we allocate the session specific
120 * data structure now. If not allocated here, it will be allocated
121 * inside prldap_newhandle() or prldap_shared_newhandle().
124 ( iofns
.lextiof_session_arg
= prldap_session_arg_alloc())) {
125 ldap_set_lderrno( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
129 iofns
.lextiof_session_arg
= NULL
;
132 if ( ldap_set_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, &iofns
) != 0 ) {
133 prldap_session_arg_free(
134 (PRLDAPIOSessionArg
**) &iofns
.lextiof_session_arg
);
142 static PRIntervalTime
143 prldap_timeout2it( int ms_timeout
, int ms_maxtimeout
)
147 if ( LDAP_X_IO_TIMEOUT_NO_WAIT
== ms_timeout
) {
148 prit
= PR_INTERVAL_NO_WAIT
;
149 } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT
== ms_timeout
) {
150 prit
= PR_INTERVAL_NO_TIMEOUT
;
152 prit
= PR_MillisecondsToInterval( ms_timeout
);
155 /* cap at maximum I/O timeout */
156 if ( LDAP_X_IO_TIMEOUT_NO_WAIT
== ms_maxtimeout
) {
157 prit
= LDAP_X_IO_TIMEOUT_NO_WAIT
;
158 } else if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT
!= ms_maxtimeout
) {
159 if ( LDAP_X_IO_TIMEOUT_NO_TIMEOUT
== ms_timeout
||
160 ms_timeout
> ms_maxtimeout
) {
161 prit
= PR_MillisecondsToInterval( ms_maxtimeout
);
166 if ( PR_INTERVAL_NO_WAIT
== prit
) {
167 fprintf( stderr
, "prldap_timeout2it: NO_WAIT\n" );
168 } else if ( PR_INTERVAL_NO_TIMEOUT
== prit
) {
169 fprintf( stderr
, "prldap_timeout2it: NO_TIMEOUT\n" );
171 fprintf( stderr
, "prldap_timeout2it: %dms\n",
172 PR_IntervalToMilliseconds(prit
));
174 #endif /* PRLDAP_DEBUG */
180 static int LDAP_CALLBACK
181 prldap_read( int s
, void *buf
, int bufsize
,
182 struct lextiof_socket_private
*socketarg
)
186 prit
= prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT
,
187 socketarg
->prsock_io_max_timeout
);
188 return( PR_Recv( PRLDAP_GET_PRFD(socketarg
), buf
, bufsize
, 0, prit
));
192 static int LDAP_CALLBACK
193 prldap_write( int s
, const void *buf
, int len
,
194 struct lextiof_socket_private
*socketarg
)
198 prit
= prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT
,
199 socketarg
->prsock_io_max_timeout
);
202 * Note the 4th parameter (flags) to PR_Send() has been obsoleted and
205 return( PR_Send( PRLDAP_GET_PRFD(socketarg
), buf
, len
, 0, prit
));
209 struct prldap_eventmap_entry
{
210 PRInt16 evm_nspr
; /* corresponding NSPR PR_Poll() event */
211 int evm_ldap
; /* LDAP poll event */
214 static struct prldap_eventmap_entry prldap_eventmap
[] = {
215 { PR_POLL_READ
, LDAP_X_POLLIN
},
216 { PR_POLL_EXCEPT
, LDAP_X_POLLPRI
},
217 { PR_POLL_WRITE
, LDAP_X_POLLOUT
},
218 { PR_POLL_ERR
, LDAP_X_POLLERR
},
219 { PR_POLL_HUP
, LDAP_X_POLLHUP
},
220 { PR_POLL_NVAL
, LDAP_X_POLLNVAL
},
223 #define PRLDAP_EVENTMAP_ENTRIES \
224 sizeof(prldap_eventmap)/sizeof(struct prldap_eventmap_entry )
226 static int LDAP_CALLBACK
227 prldap_poll( LDAP_X_PollFD fds
[], int nfds
, int timeout
,
228 struct lextiof_session_private
*sessionarg
)
230 PRLDAPIOSessionArg
*prsessp
= sessionarg
;
234 if ( NULL
== prsessp
) {
235 prldap_set_system_errno( EINVAL
);
239 /* allocate or resize NSPR poll descriptor array */
240 if ( prsessp
->prsess_pollds_count
< nfds
) {
241 pds
= prldap_safe_realloc( prsessp
->prsess_pollds
,
242 ( nfds
+ PRLDAP_POLL_ARRAY_GROWTH
)
243 * sizeof( PRPollDesc
));
245 prldap_set_system_errno( prldap_prerr2errno());
248 prsessp
->prsess_pollds
= pds
;
249 prsessp
->prsess_pollds_count
= nfds
+ PRLDAP_POLL_ARRAY_GROWTH
;
251 pds
= prsessp
->prsess_pollds
;
254 /* populate NSPR poll info. based on LDAP info. */
255 for ( i
= 0; i
< nfds
; ++i
) {
256 if ( NULL
== fds
[i
].lpoll_socketarg
) {
259 pds
[i
].fd
= PRLDAP_GET_PRFD( fds
[i
].lpoll_socketarg
);
261 pds
[i
].in_flags
= pds
[i
].out_flags
= 0;
262 if ( fds
[i
].lpoll_fd
>= 0 ) {
263 for ( j
= 0; j
< PRLDAP_EVENTMAP_ENTRIES
; ++j
) {
264 if (( fds
[i
].lpoll_events
& prldap_eventmap
[j
].evm_ldap
)
266 pds
[i
].in_flags
|= prldap_eventmap
[j
].evm_nspr
;
270 fds
[i
].lpoll_revents
= 0; /* clear revents */
273 /* call PR_Poll() to do the real work */
274 rc
= PR_Poll( pds
, nfds
,
275 prldap_timeout2it( timeout
, prsessp
->prsess_io_max_timeout
));
277 /* populate LDAP info. based on NSPR results */
278 for ( i
= 0; i
< nfds
; ++i
) {
279 if ( pds
[i
].fd
!= NULL
) {
280 for ( j
= 0; j
< PRLDAP_EVENTMAP_ENTRIES
; ++j
) {
281 if (( pds
[i
].out_flags
& prldap_eventmap
[j
].evm_nspr
)
283 fds
[i
].lpoll_revents
|= prldap_eventmap
[j
].evm_ldap
;
294 * Utility function to try one TCP connect()
295 * Returns 1 if successful and -1 if not. Sets the NSPR fd inside prsockp.
298 prldap_try_one_address( struct lextiof_socket_private
*prsockp
,
299 PRNetAddr
*addrp
, int port
, int timeout
, unsigned long options
)
302 * Set up address and open a TCP socket:
304 if ( PR_SUCCESS
!= PR_SetNetAddr( PR_IpAddrNull
, /* don't touch IP addr. */
305 PRLDAP_DEFAULT_ADDRESS_FAMILY
, (PRUint16
)port
, addrp
)) {
309 if (( prsockp
->prsock_prfd
= PR_OpenTCPSocket(
310 PRLDAP_DEFAULT_ADDRESS_FAMILY
)) == NULL
) {
315 * Set nonblocking option if requested:
317 if ( 0 != ( options
& LDAP_X_EXTIOF_OPT_NONBLOCKING
)) {
318 PRSocketOptionData optdata
;
320 optdata
.option
= PR_SockOpt_Nonblocking
;
321 optdata
.value
.non_blocking
= PR_TRUE
;
322 if ( PR_SetSocketOption( prsockp
->prsock_prfd
, &optdata
)
324 prldap_set_system_errno( prldap_prerr2errno());
325 PR_Close( prsockp
->prsock_prfd
);
332 char buf
[ 256 ], *p
, *fmtstr
;
334 if ( PR_SUCCESS
!= PR_NetAddrToString( addrp
, buf
, sizeof(buf
))) {
335 strcpy( buf
, "conversion failed!" );
337 if ( strncmp( buf
, "::ffff:", 7 ) == 0 ) {
338 /* IPv4 address mapped into IPv6 address space */
340 fmtstr
= "prldap_try_one_address(): Trying %s:%d...\n";
343 fmtstr
= "prldap_try_one_address(): Trying [%s]:%d...\n";
345 fprintf( stderr
, fmtstr
, p
, PR_ntohs( addrp
->ipv6
.port
));
347 #endif /* PRLDAP_DEBUG */
350 * Try to open the TCP connection itself:
352 if ( PR_SUCCESS
!= PR_Connect( prsockp
->prsock_prfd
, addrp
,
353 prldap_timeout2it( timeout
, prsockp
->prsock_io_max_timeout
))) {
354 PR_Close( prsockp
->prsock_prfd
);
355 prsockp
->prsock_prfd
= NULL
;
360 fputs( "prldap_try_one_address(): Connected.\n", stderr
);
361 #endif /* PRLDAP_DEBUG */
364 * Success. Return a valid file descriptor (1 is always valid)
371 * XXXmcs: At present, this code ignores the timeout when doing DNS lookups.
373 static int LDAP_CALLBACK
374 prldap_connect( const char *hostlist
, int defport
, int timeout
,
375 unsigned long options
, struct lextiof_session_private
*sessionarg
,
376 struct lextiof_socket_private
**socketargp
381 #endif /* _SOLARIS_SDK */
383 int rc
, parse_err
, port
;
384 char *host
, hbuf
[ PR_NETDB_BUF_SIZE
];
385 struct ldap_x_hostlist_status
*status
;
386 struct lextiof_socket_private
*prsockp
;
390 char *hostname
= NULL
;
391 char *nsldapi_strdup(char *);
392 #endif /* _SOLARIS_SDK */
394 if ( 0 != ( options
& LDAP_X_EXTIOF_OPT_SECURE
)) {
395 prldap_set_system_errno( EINVAL
);
399 if ( NULL
== ( prsockp
= prldap_socket_arg_alloc( sessionarg
))) {
400 prldap_set_system_errno( prldap_prerr2errno());
404 rc
= -1; /* pessimistic */
405 for ( parse_err
= ldap_x_hostlist_first( hostlist
, defport
, &host
, &port
,
407 rc
< 0 && LDAP_SUCCESS
== parse_err
&& NULL
!= host
;
408 parse_err
= ldap_x_hostlist_next( &host
, &port
, status
)) {
410 if ( PR_SUCCESS
== PR_StringToNetAddr( host
, &addr
)) {
412 if ( PRLDAP_DEFAULT_ADDRESS_FAMILY
== PR_AF_INET6
&&
413 PR_AF_INET
== PR_NetAddrFamily( &addr
)) {
414 PRUint32 ipv4ip
= addr
.inet
.ip
;
415 memset( &addr
, 0, sizeof(addr
));
416 PR_ConvertIPv4AddrToIPv6( ipv4ip
, &addr
.ipv6
.ip
);
417 addr
.ipv6
.family
= PR_AF_INET6
;
420 rc
= prldap_try_one_address( prsockp
, &addr
, port
,
423 if ( PR_SUCCESS
== PR_GetIPNodeByName( host
,
424 PRLDAP_DEFAULT_ADDRESS_FAMILY
, PR_AI_DEFAULT
| PR_AI_ALL
, hbuf
,
425 sizeof( hbuf
), &hent
)) {
426 PRIntn enumIndex
= 0;
428 while ( rc
< 0 && ( enumIndex
= PR_EnumerateHostEnt(
429 enumIndex
, &hent
, (PRUint16
)port
, &addr
)) > 0 ) {
430 rc
= prldap_try_one_address( prsockp
, &addr
, port
,
437 if ( NULL
!= hostname
) {
438 ldap_memfree(hostname
);
442 hostname
= nsldapi_strdup(host
);
444 #endif /* _SOLARIS_SDK */
445 ldap_memfree( host
);
448 ldap_x_hostlist_statusfree( status
);
451 prldap_set_system_errno( prldap_prerr2errno());
452 prldap_socket_arg_free( &prsockp
);
454 *socketargp
= prsockp
;
458 if ( NULL
!= hostname
&& NULL
!= dhost
) *dhost
= hostname
;
459 else if ( NULL
!= hostname
) ldap_memfree(hostname
);
460 #endif /* _SOLARIS_SDK */
466 static int LDAP_CALLBACK
467 prldap_close( int s
, struct lextiof_socket_private
*socketarg
)
472 if ( PR_Close( PRLDAP_GET_PRFD(socketarg
)) != PR_SUCCESS
) {
474 prldap_set_system_errno( prldap_prerr2errno());
476 prldap_socket_arg_free( &socketarg
);
483 * LDAP session handle creation callback.
485 * Allocate a session argument if not already done, and then call the
486 * thread's new handle function.
488 static int LDAP_CALLBACK
489 prldap_newhandle( LDAP
*ld
, struct lextiof_session_private
*sessionarg
)
492 if ( NULL
== sessionarg
) {
493 struct ldap_x_ext_io_fns iofns
;
495 memset( &iofns
, 0, sizeof(iofns
));
496 iofns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
497 if ( ldap_get_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
,
498 (void *)&iofns
) < 0 ) {
499 return( ldap_get_lderrno( ld
, NULL
, NULL
));
502 ( iofns
.lextiof_session_arg
= prldap_session_arg_alloc())) {
503 return( LDAP_NO_MEMORY
);
505 if ( ldap_set_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
,
506 (void *)&iofns
) < 0 ) {
507 return( ldap_get_lderrno( ld
, NULL
, NULL
));
511 return( LDAP_SUCCESS
);
515 /* only called/installed if shared is non-zero. */
516 static int LDAP_CALLBACK
517 prldap_shared_newhandle( LDAP
*ld
, struct lextiof_session_private
*sessionarg
)
521 if (( rc
= prldap_newhandle( ld
, sessionarg
)) == LDAP_SUCCESS
) {
522 rc
= prldap_thread_new_handle( ld
, sessionarg
);
529 static void LDAP_CALLBACK
530 prldap_disposehandle( LDAP
*ld
, struct lextiof_session_private
*sessionarg
)
532 prldap_session_arg_free( &sessionarg
);
536 /* only called/installed if shared is non-zero */
537 static void LDAP_CALLBACK
538 prldap_shared_disposehandle( LDAP
*ld
,
539 struct lextiof_session_private
*sessionarg
)
541 prldap_thread_dispose_handle( ld
, sessionarg
);
542 prldap_disposehandle( ld
, sessionarg
);
547 * Allocate a session argument.
549 static PRLDAPIOSessionArg
*
550 prldap_session_arg_alloc( void )
552 PRLDAPIOSessionArg
*prsessp
;
554 prsessp
= PR_Calloc( 1, sizeof( PRLDAPIOSessionArg
));
556 if ( NULL
!= prsessp
) {
557 /* copy global defaults to the new session handle */
558 prsessp
->prsess_io_max_timeout
= prldap_default_io_max_timeout
;
566 prldap_session_arg_free( PRLDAPIOSessionArg
**prsesspp
)
568 if ( NULL
!= prsesspp
&& NULL
!= *prsesspp
) {
569 if ( NULL
!= (*prsesspp
)->prsess_pollds
) {
570 PR_Free( (*prsesspp
)->prsess_pollds
);
571 (*prsesspp
)->prsess_pollds
= NULL
;
573 PR_Free( *prsesspp
);
580 * Given an LDAP session handle, retrieve a session argument.
581 * Returns an LDAP error code.
584 prldap_session_arg_from_ld( LDAP
*ld
, PRLDAPIOSessionArg
**sessargpp
)
586 struct ldap_x_ext_io_fns iofns
;
588 if ( NULL
== ld
|| NULL
== sessargpp
) {
589 /* XXXmcs: NULL ld's are not supported */
590 ldap_set_lderrno( ld
, LDAP_PARAM_ERROR
, NULL
, NULL
);
591 return( LDAP_PARAM_ERROR
);
594 memset( &iofns
, 0, sizeof(iofns
));
595 iofns
.lextiof_size
= LDAP_X_EXTIO_FNS_SIZE
;
596 if ( ldap_get_option( ld
, LDAP_X_OPT_EXTIO_FN_PTRS
, (void *)&iofns
) < 0 ) {
597 return( ldap_get_lderrno( ld
, NULL
, NULL
));
600 if ( NULL
== iofns
.lextiof_session_arg
) {
601 ldap_set_lderrno( ld
, LDAP_LOCAL_ERROR
, NULL
, NULL
);
602 return( LDAP_LOCAL_ERROR
);
605 *sessargpp
= iofns
.lextiof_session_arg
;
606 return( LDAP_SUCCESS
);
611 * Given an LDAP session handle, retrieve a socket argument.
612 * Returns an LDAP error code.
615 prldap_socket_arg_from_ld( LDAP
*ld
, PRLDAPIOSocketArg
**sockargpp
)
618 struct lber_x_ext_io_fns extiofns
;
620 if ( NULL
== ld
|| NULL
== sockargpp
) {
621 /* XXXmcs: NULL ld's are not supported */
622 ldap_set_lderrno( ld
, LDAP_PARAM_ERROR
, NULL
, NULL
);
623 return( LDAP_PARAM_ERROR
);
626 if ( ldap_get_option( ld
, LDAP_X_OPT_SOCKBUF
, (void *)&sbp
) < 0 ) {
627 return( ldap_get_lderrno( ld
, NULL
, NULL
));
630 memset( &extiofns
, 0, sizeof(extiofns
));
631 extiofns
.lbextiofn_size
= LBER_X_EXTIO_FNS_SIZE
;
632 if ( ber_sockbuf_get_option( sbp
, LBER_SOCKBUF_OPT_EXT_IO_FNS
,
633 (void *)&extiofns
) < 0 ) {
634 return( ldap_get_lderrno( ld
, NULL
, NULL
));
637 if ( NULL
== extiofns
.lbextiofn_socket_arg
) {
638 ldap_set_lderrno( ld
, LDAP_LOCAL_ERROR
, NULL
, NULL
);
639 return( LDAP_LOCAL_ERROR
);
642 *sockargpp
= extiofns
.lbextiofn_socket_arg
;
643 return( LDAP_SUCCESS
);
648 * Allocate a socket argument.
650 static PRLDAPIOSocketArg
*
651 prldap_socket_arg_alloc( PRLDAPIOSessionArg
*sessionarg
)
653 PRLDAPIOSocketArg
*prsockp
;
655 prsockp
= PR_Calloc( 1, sizeof( PRLDAPIOSocketArg
));
657 if ( NULL
!= prsockp
&& NULL
!= sessionarg
) {
658 /* copy socket defaults from the session */
659 prsockp
->prsock_io_max_timeout
= sessionarg
->prsess_io_max_timeout
;
667 prldap_socket_arg_free( PRLDAPIOSocketArg
**prsockpp
)
669 if ( NULL
!= prsockpp
&& NULL
!= *prsockpp
) {
670 PR_Free( *prsockpp
);
677 prldap_safe_realloc( void *ptr
, PRUint32 size
)
682 p
= PR_Malloc( size
);
684 p
= PR_Realloc( ptr
, size
);
692 /* returns an LDAP result code */
694 prldap_set_io_max_timeout( PRLDAPIOSessionArg
*prsessp
, int io_max_timeout
)
696 int rc
= LDAP_SUCCESS
; /* optimistic */
698 if ( NULL
== prsessp
) {
699 prldap_default_io_max_timeout
= io_max_timeout
;
701 prsessp
->prsess_io_max_timeout
= io_max_timeout
;
708 /* returns an LDAP result code */
710 prldap_get_io_max_timeout( PRLDAPIOSessionArg
*prsessp
, int *io_max_timeoutp
)
712 int rc
= LDAP_SUCCESS
; /* optimistic */
714 if ( NULL
== io_max_timeoutp
) {
715 rc
= LDAP_PARAM_ERROR
;
716 } else if ( NULL
== prsessp
) {
717 *io_max_timeoutp
= prldap_default_io_max_timeout
;
719 *io_max_timeoutp
= prsessp
->prsess_io_max_timeout
;