1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
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/
11 *
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.
16 *
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
19 *
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
23 * Rights Reserved.
24 *
25 * Contributor(s):
26 */
27
28 /*
29 * Extended I/O callback functions for libldap that use
30 * NSPR (Netscape Portable Runtime) I/O.
31 *
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.
36 */
37
38 #include "ldappr-int.h"
39 #include <string.h>
40
41 #define PRLDAP_POLL_ARRAY_GROWTH 5 /* grow arrays 5 elements at a time */
42
43 /*
44 * Local function prototypes:
45 */
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
57 #ifdef _SOLARIS_SDK
58 , void **dhost );
59 #else
60 );
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 );
77
78
79
80 /*
81 * Local macros:
82 */
83 /* given a socket-specific arg, return the corresponding PRFileDesc * */
84 #define PRLDAP_GET_PRFD( socketarg ) \
85 (((PRLDAPIOSocketArg *)(socketarg))->prsock_prfd)
86
87 /*
88 * Static variables.
89 */
90 static int prldap_default_io_max_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
91
92 /*
93 * Install NSPR I/O functions into ld (if ld is NULL, they are installed
94 * as the default functions for new LDAP * handles).
95 *
96 * Returns 0 if all goes well and -1 if not.
97 */
98 int
prldap_install_io_functions(LDAP * ld,int shared)99 prldap_install_io_functions( LDAP *ld, int shared )
100 {
101 struct ldap_x_ext_io_fns iofns;
102
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;
110 if ( shared ) {
111 iofns.lextiof_newhandle = prldap_shared_newhandle;
112 iofns.lextiof_disposehandle = prldap_shared_disposehandle;
113 } else {
114 iofns.lextiof_newhandle = prldap_newhandle;
115 iofns.lextiof_disposehandle = prldap_disposehandle;
116 }
117 if ( NULL != ld ) {
118 /*
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().
122 */
123 if ( NULL ==
124 ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
125 ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
126 return( -1 );
127 }
128 } else {
129 iofns.lextiof_session_arg = NULL;
130 }
131
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 );
135 return( -1 );
136 }
137
138 return( 0 );
139 }
140
141
142 static PRIntervalTime
prldap_timeout2it(int ms_timeout,int ms_maxtimeout)143 prldap_timeout2it( int ms_timeout, int ms_maxtimeout )
144 {
145 PRIntervalTime prit;
146
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;
151 } else {
152 prit = PR_MillisecondsToInterval( ms_timeout );
153 }
154
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 );
162 }
163 }
164
165 #ifdef PRLDAP_DEBUG
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" );
170 } else {
171 fprintf( stderr, "prldap_timeout2it: %dms\n",
172 PR_IntervalToMilliseconds(prit));
173 }
174 #endif /* PRLDAP_DEBUG */
175
176 return( prit );
177 }
178
179
180 static int LDAP_CALLBACK
prldap_read(int s,void * buf,int bufsize,struct lextiof_socket_private * socketarg)181 prldap_read( int s, void *buf, int bufsize,
182 struct lextiof_socket_private *socketarg )
183 {
184 PRIntervalTime prit;
185
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 ));
189 }
190
191
192 static int LDAP_CALLBACK
prldap_write(int s,const void * buf,int len,struct lextiof_socket_private * socketarg)193 prldap_write( int s, const void *buf, int len,
194 struct lextiof_socket_private *socketarg )
195 {
196 PRIntervalTime prit;
197
198 prit = prldap_timeout2it( LDAP_X_IO_TIMEOUT_NO_TIMEOUT,
199 socketarg->prsock_io_max_timeout );
200
201 /*
202 * Note the 4th parameter (flags) to PR_Send() has been obsoleted and
203 * must always be 0
204 */
205 return( PR_Send( PRLDAP_GET_PRFD(socketarg), buf, len, 0, prit ));
206 }
207
208
209 struct prldap_eventmap_entry {
210 PRInt16 evm_nspr; /* corresponding NSPR PR_Poll() event */
211 int evm_ldap; /* LDAP poll event */
212 };
213
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 },
221 };
222
223 #define PRLDAP_EVENTMAP_ENTRIES \
224 sizeof(prldap_eventmap)/sizeof(struct prldap_eventmap_entry )
225
226 static int LDAP_CALLBACK
prldap_poll(LDAP_X_PollFD fds[],int nfds,int timeout,struct lextiof_session_private * sessionarg)227 prldap_poll( LDAP_X_PollFD fds[], int nfds, int timeout,
228 struct lextiof_session_private *sessionarg )
229 {
230 PRLDAPIOSessionArg *prsessp = sessionarg;
231 PRPollDesc *pds;
232 int i, j, rc;
233
234 if ( NULL == prsessp ) {
235 prldap_set_system_errno( EINVAL );
236 return( -1 );
237 }
238
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 ));
244 if ( NULL == pds ) {
245 prldap_set_system_errno( prldap_prerr2errno());
246 return( -1 );
247 }
248 prsessp->prsess_pollds = pds;
249 prsessp->prsess_pollds_count = nfds + PRLDAP_POLL_ARRAY_GROWTH;
250 } else {
251 pds = prsessp->prsess_pollds;
252 }
253
254 /* populate NSPR poll info. based on LDAP info. */
255 for ( i = 0; i < nfds; ++i ) {
256 if ( NULL == fds[i].lpoll_socketarg ) {
257 pds[i].fd = NULL;
258 } else {
259 pds[i].fd = PRLDAP_GET_PRFD( fds[i].lpoll_socketarg );
260 }
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 )
265 != 0 ) {
266 pds[i].in_flags |= prldap_eventmap[j].evm_nspr;
267 }
268 }
269 }
270 fds[i].lpoll_revents = 0; /* clear revents */
271 }
272
273 /* call PR_Poll() to do the real work */
274 rc = PR_Poll( pds, nfds,
275 prldap_timeout2it( timeout, prsessp->prsess_io_max_timeout ));
276
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 )
282 != 0 ) {
283 fds[i].lpoll_revents |= prldap_eventmap[j].evm_ldap;
284 }
285 }
286 }
287 }
288
289 return( rc );
290 }
291
292
293 /*
294 * Utility function to try one TCP connect()
295 * Returns 1 if successful and -1 if not. Sets the NSPR fd inside prsockp.
296 */
297 static int
prldap_try_one_address(struct lextiof_socket_private * prsockp,PRNetAddr * addrp,int port,int timeout,unsigned long options)298 prldap_try_one_address( struct lextiof_socket_private *prsockp,
299 PRNetAddr *addrp, int port, int timeout, unsigned long options )
300 {
301 /*
302 * Set up address and open a TCP socket:
303 */
304 if ( PR_SUCCESS != PR_SetNetAddr( PR_IpAddrNull, /* don't touch IP addr. */
305 PRLDAP_DEFAULT_ADDRESS_FAMILY, (PRUint16)port, addrp )) {
306 return( -1 );
307 }
308
309 if (( prsockp->prsock_prfd = PR_OpenTCPSocket(
310 PRLDAP_DEFAULT_ADDRESS_FAMILY )) == NULL ) {
311 return( -1 );
312 }
313
314 /*
315 * Set nonblocking option if requested:
316 */
317 if ( 0 != ( options & LDAP_X_EXTIOF_OPT_NONBLOCKING )) {
318 PRSocketOptionData optdata;
319
320 optdata.option = PR_SockOpt_Nonblocking;
321 optdata.value.non_blocking = PR_TRUE;
322 if ( PR_SetSocketOption( prsockp->prsock_prfd, &optdata )
323 != PR_SUCCESS ) {
324 prldap_set_system_errno( prldap_prerr2errno());
325 PR_Close( prsockp->prsock_prfd );
326 return( -1 );
327 }
328 }
329
330 #ifdef PRLDAP_DEBUG
331 {
332 char buf[ 256 ], *p, *fmtstr;
333
334 if ( PR_SUCCESS != PR_NetAddrToString( addrp, buf, sizeof(buf ))) {
335 strcpy( buf, "conversion failed!" );
336 }
337 if ( strncmp( buf, "::ffff:", 7 ) == 0 ) {
338 /* IPv4 address mapped into IPv6 address space */
339 p = buf + 7;
340 fmtstr = "prldap_try_one_address(): Trying %s:%d...\n";
341 } else {
342 p = buf;
343 fmtstr = "prldap_try_one_address(): Trying [%s]:%d...\n";
344 }
345 fprintf( stderr, fmtstr, p, PR_ntohs( addrp->ipv6.port ));
346 }
347 #endif /* PRLDAP_DEBUG */
348
349 /*
350 * Try to open the TCP connection itself:
351 */
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;
356 return( -1 );
357 }
358
359 #ifdef PRLDAP_DEBUG
360 fputs( "prldap_try_one_address(): Connected.\n", stderr );
361 #endif /* PRLDAP_DEBUG */
362
363 /*
364 * Success. Return a valid file descriptor (1 is always valid)
365 */
366 return( 1 );
367 }
368
369
370 /*
371 * XXXmcs: At present, this code ignores the timeout when doing DNS lookups.
372 */
373 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,void ** dhost)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
377 #ifdef _SOLARIS_SDK
378 , void **dhost )
379 #else
380 )
381 #endif /* _SOLARIS_SDK */
382 {
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;
387 PRNetAddr addr;
388 PRHostEnt hent;
389 #ifdef _SOLARIS_SDK
390 char *hostname = NULL;
391 char *nsldapi_strdup(char *);
392 #endif /* _SOLARIS_SDK */
393
394 if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
395 prldap_set_system_errno( EINVAL );
396 return( -1 );
397 }
398
399 if ( NULL == ( prsockp = prldap_socket_arg_alloc( sessionarg ))) {
400 prldap_set_system_errno( prldap_prerr2errno());
401 return( -1 );
402 }
403
404 rc = -1; /* pessimistic */
405 for ( parse_err = ldap_x_hostlist_first( hostlist, defport, &host, &port,
406 &status );
407 rc < 0 && LDAP_SUCCESS == parse_err && NULL != host;
408 parse_err = ldap_x_hostlist_next( &host, &port, status )) {
409
410 if ( PR_SUCCESS == PR_StringToNetAddr( host, &addr )) {
411
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;
418
419 }
420 rc = prldap_try_one_address( prsockp, &addr, port,
421 timeout, options );
422 } else {
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;
427
428 while ( rc < 0 && ( enumIndex = PR_EnumerateHostEnt(
429 enumIndex, &hent, (PRUint16)port, &addr )) > 0 ) {
430 rc = prldap_try_one_address( prsockp, &addr, port,
431 timeout, options );
432 }
433 }
434 }
435
436 #ifdef _SOLARIS_SDK
437 if ( NULL != hostname ) {
438 ldap_memfree(hostname);
439 hostname = NULL;
440 }
441 if ( rc >= 0 ) {
442 hostname = nsldapi_strdup(host);
443 }
444 #endif /* _SOLARIS_SDK */
445 ldap_memfree( host );
446 }
447
448 ldap_x_hostlist_statusfree( status );
449
450 if ( rc < 0 ) {
451 prldap_set_system_errno( prldap_prerr2errno());
452 prldap_socket_arg_free( &prsockp );
453 } else {
454 *socketargp = prsockp;
455 }
456
457 #ifdef _SOLARIS_SDK
458 if ( NULL != hostname && NULL != dhost ) *dhost = hostname;
459 else if ( NULL != hostname ) ldap_memfree(hostname);
460 #endif /* _SOLARIS_SDK */
461
462 return( rc );
463 }
464
465
466 static int LDAP_CALLBACK
prldap_close(int s,struct lextiof_socket_private * socketarg)467 prldap_close( int s, struct lextiof_socket_private *socketarg )
468 {
469 int rc;
470
471 rc = 0;
472 if ( PR_Close( PRLDAP_GET_PRFD(socketarg)) != PR_SUCCESS ) {
473 rc = -1;
474 prldap_set_system_errno( prldap_prerr2errno());
475 }
476 prldap_socket_arg_free( &socketarg );
477
478 return( rc );
479 }
480
481
482 /*
483 * LDAP session handle creation callback.
484 *
485 * Allocate a session argument if not already done, and then call the
486 * thread's new handle function.
487 */
488 static int LDAP_CALLBACK
prldap_newhandle(LDAP * ld,struct lextiof_session_private * sessionarg)489 prldap_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
490 {
491
492 if ( NULL == sessionarg ) {
493 struct ldap_x_ext_io_fns iofns;
494
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 ));
500 }
501 if ( NULL ==
502 ( iofns.lextiof_session_arg = prldap_session_arg_alloc())) {
503 return( LDAP_NO_MEMORY );
504 }
505 if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS,
506 (void *)&iofns ) < 0 ) {
507 return( ldap_get_lderrno( ld, NULL, NULL ));
508 }
509 }
510
511 return( LDAP_SUCCESS );
512 }
513
514
515 /* only called/installed if shared is non-zero. */
516 static int LDAP_CALLBACK
prldap_shared_newhandle(LDAP * ld,struct lextiof_session_private * sessionarg)517 prldap_shared_newhandle( LDAP *ld, struct lextiof_session_private *sessionarg )
518 {
519 int rc;
520
521 if (( rc = prldap_newhandle( ld, sessionarg )) == LDAP_SUCCESS ) {
522 rc = prldap_thread_new_handle( ld, sessionarg );
523 }
524
525 return( rc );
526 }
527
528
529 static void LDAP_CALLBACK
prldap_disposehandle(LDAP * ld,struct lextiof_session_private * sessionarg)530 prldap_disposehandle( LDAP *ld, struct lextiof_session_private *sessionarg )
531 {
532 prldap_session_arg_free( &sessionarg );
533 }
534
535
536 /* only called/installed if shared is non-zero */
537 static void LDAP_CALLBACK
prldap_shared_disposehandle(LDAP * ld,struct lextiof_session_private * sessionarg)538 prldap_shared_disposehandle( LDAP *ld,
539 struct lextiof_session_private *sessionarg )
540 {
541 prldap_thread_dispose_handle( ld, sessionarg );
542 prldap_disposehandle( ld, sessionarg );
543 }
544
545
546 /*
547 * Allocate a session argument.
548 */
549 static PRLDAPIOSessionArg *
prldap_session_arg_alloc(void)550 prldap_session_arg_alloc( void )
551 {
552 PRLDAPIOSessionArg *prsessp;
553
554 prsessp = PR_Calloc( 1, sizeof( PRLDAPIOSessionArg ));
555
556 if ( NULL != prsessp ) {
557 /* copy global defaults to the new session handle */
558 prsessp->prsess_io_max_timeout = prldap_default_io_max_timeout;
559 }
560
561 return( prsessp );
562 }
563
564
565 static void
prldap_session_arg_free(PRLDAPIOSessionArg ** prsesspp)566 prldap_session_arg_free( PRLDAPIOSessionArg **prsesspp )
567 {
568 if ( NULL != prsesspp && NULL != *prsesspp ) {
569 if ( NULL != (*prsesspp)->prsess_pollds ) {
570 PR_Free( (*prsesspp)->prsess_pollds );
571 (*prsesspp)->prsess_pollds = NULL;
572 }
573 PR_Free( *prsesspp );
574 *prsesspp = NULL;
575 }
576 }
577
578
579 /*
580 * Given an LDAP session handle, retrieve a session argument.
581 * Returns an LDAP error code.
582 */
583 int
prldap_session_arg_from_ld(LDAP * ld,PRLDAPIOSessionArg ** sessargpp)584 prldap_session_arg_from_ld( LDAP *ld, PRLDAPIOSessionArg **sessargpp )
585 {
586 struct ldap_x_ext_io_fns iofns;
587
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 );
592 }
593
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 ));
598 }
599
600 if ( NULL == iofns.lextiof_session_arg ) {
601 ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
602 return( LDAP_LOCAL_ERROR );
603 }
604
605 *sessargpp = iofns.lextiof_session_arg;
606 return( LDAP_SUCCESS );
607 }
608
609
610 /*
611 * Given an LDAP session handle, retrieve a socket argument.
612 * Returns an LDAP error code.
613 */
614 int
prldap_socket_arg_from_ld(LDAP * ld,PRLDAPIOSocketArg ** sockargpp)615 prldap_socket_arg_from_ld( LDAP *ld, PRLDAPIOSocketArg **sockargpp )
616 {
617 Sockbuf *sbp;
618 struct lber_x_ext_io_fns extiofns;
619
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 );
624 }
625
626 if ( ldap_get_option( ld, LDAP_X_OPT_SOCKBUF, (void *)&sbp ) < 0 ) {
627 return( ldap_get_lderrno( ld, NULL, NULL ));
628 }
629
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 ));
635 }
636
637 if ( NULL == extiofns.lbextiofn_socket_arg ) {
638 ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
639 return( LDAP_LOCAL_ERROR );
640 }
641
642 *sockargpp = extiofns.lbextiofn_socket_arg;
643 return( LDAP_SUCCESS );
644 }
645
646
647 /*
648 * Allocate a socket argument.
649 */
650 static PRLDAPIOSocketArg *
prldap_socket_arg_alloc(PRLDAPIOSessionArg * sessionarg)651 prldap_socket_arg_alloc( PRLDAPIOSessionArg *sessionarg )
652 {
653 PRLDAPIOSocketArg *prsockp;
654
655 prsockp = PR_Calloc( 1, sizeof( PRLDAPIOSocketArg ));
656
657 if ( NULL != prsockp && NULL != sessionarg ) {
658 /* copy socket defaults from the session */
659 prsockp->prsock_io_max_timeout = sessionarg->prsess_io_max_timeout;
660 }
661
662 return( prsockp );
663 }
664
665
666 static void
prldap_socket_arg_free(PRLDAPIOSocketArg ** prsockpp)667 prldap_socket_arg_free( PRLDAPIOSocketArg **prsockpp )
668 {
669 if ( NULL != prsockpp && NULL != *prsockpp ) {
670 PR_Free( *prsockpp );
671 *prsockpp = NULL;
672 }
673 }
674
675
676 static void *
prldap_safe_realloc(void * ptr,PRUint32 size)677 prldap_safe_realloc( void *ptr, PRUint32 size )
678 {
679 void *p;
680
681 if ( NULL == ptr ) {
682 p = PR_Malloc( size );
683 } else {
684 p = PR_Realloc( ptr, size );
685 }
686
687 return( p );
688 }
689
690
691
692 /* returns an LDAP result code */
693 int
prldap_set_io_max_timeout(PRLDAPIOSessionArg * prsessp,int io_max_timeout)694 prldap_set_io_max_timeout( PRLDAPIOSessionArg *prsessp, int io_max_timeout )
695 {
696 int rc = LDAP_SUCCESS; /* optimistic */
697
698 if ( NULL == prsessp ) {
699 prldap_default_io_max_timeout = io_max_timeout;
700 } else {
701 prsessp->prsess_io_max_timeout = io_max_timeout;
702 }
703
704 return( rc );
705 }
706
707
708 /* returns an LDAP result code */
709 int
prldap_get_io_max_timeout(PRLDAPIOSessionArg * prsessp,int * io_max_timeoutp)710 prldap_get_io_max_timeout( PRLDAPIOSessionArg *prsessp, int *io_max_timeoutp )
711 {
712 int rc = LDAP_SUCCESS; /* optimistic */
713
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;
718 } else {
719 *io_max_timeoutp = prsessp->prsess_io_max_timeout;
720 }
721
722 return( rc );
723 }
724