cb_conn_stateless.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright 2001 Sun Microsystems, Inc.
  3. * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. #include "cb.h"
  7. /*
  8. * Most of the complicated connection-related code lives in this file. Some
  9. * general notes about how we manage our connections to "remote" LDAP servers:
  10. *
  11. * 1) Each farm server we have a relationship with is managed independently.
  12. *
  13. * 2) We may simultaneously issue multiple requests on a single LDAP
  14. * connection. Each server has a "maxconcurrency" configuration
  15. * parameter associated with it that caps the number of outstanding operations
  16. * per connection. For each connection we maintain a "usecount"
  17. * which is used to track the number of threads using the connection.
  18. *
  19. * 3) IMPORTANT NOTE: This connexion management is stateless i.e there is no garanty that
  20. * operation from the same incoming client connections are sent to the same
  21. * outgoing connection to the farm server. Today, this is not a problem because
  22. * all controls we support are stateless. The implementation of the abandon
  23. * operation takes this limitation into account.
  24. *
  25. * 4) We may open more than one connection to a server. Each farm server
  26. * has a "maxconnections" configuration parameter associated with it
  27. * that caps the number of connections.
  28. *
  29. * 5) If no connection is available to service a request , threads
  30. * go to sleep on a condition variable and one is woken up each time
  31. * a connection's "usecount" is decremented.
  32. *
  33. * 6) If we see an LDAP_CONNECT_ERROR or LDAP_SERVER_DOWN error on a
  34. * session handle, we mark its status as CB_LDAP_STATUS_DOWN and
  35. * close it as soon as all threads using it release it. Connections
  36. * marked as "down" are not counted against the "maxconnections" limit.
  37. *
  38. * 7) We close and reopen connections that have been open for more than
  39. * the server's configured connection lifetime. This is done to ensure
  40. * that we reconnect to a primary server after failover occurs. If no
  41. * lifetime is configured or it is set to 0, we never close and reopen
  42. * connections.
  43. */
  44. static void cb_close_and_dispose_connection ( cb_outgoing_conn * conn );
  45. static void cb_check_for_stale_connections(cb_conn_pool * pool);
  46. PRUint32 PR_GetThreadID(PRThread *thread);
  47. /* returns the threadId of the current thread modulo MAX_CONN_ARRAY
  48. => gives the position of the thread in the array of secure connections */
  49. static int PR_ThreadSelf() {
  50. PRThread *thr = PR_GetCurrentThread();
  51. PRUint32 myself = PR_GetThreadID(thr);
  52. myself &= 0x000007FF ;
  53. return myself;
  54. }
  55. static int PR_MyThreadId() {
  56. PRThread *thr = PR_GetCurrentThread();
  57. PRUint32 myself = PR_GetThreadID(thr);
  58. return myself;
  59. }
  60. /*
  61. ** Close outgoing connections
  62. */
  63. void cb_close_conn_pool(cb_conn_pool * pool) {
  64. cb_outgoing_conn *conn, *nextconn;
  65. int secure = pool->secure;
  66. int i = 0;
  67. slapi_lock_mutex( pool->conn.conn_list_mutex );
  68. if (secure) {
  69. for (i=0; i< MAX_CONN_ARRAY; i++) {
  70. for (conn = pool->connarray[i]; conn != NULL; conn = nextconn) {
  71. if ( conn->status != CB_CONNSTATUS_OK ) {
  72. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  73. "cb_close_conn_pool: unexpected connection state (%d)\n",conn->status);
  74. }
  75. nextconn=conn->next;
  76. cb_close_and_dispose_connection(conn);
  77. }
  78. }
  79. }
  80. else {
  81. for ( conn = pool->conn.conn_list; conn != NULL; conn = nextconn ) {
  82. if ( conn->status != CB_CONNSTATUS_OK ) {
  83. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  84. "cb_close_conn_pool: unexpected connection state (%d)\n",conn->status);
  85. }
  86. nextconn=conn->next;
  87. cb_close_and_dispose_connection(conn);
  88. }
  89. }
  90. pool->conn.conn_list=NULL;
  91. pool->conn.conn_list_count=0;
  92. slapi_unlock_mutex( pool->conn.conn_list_mutex );
  93. }
  94. /*
  95. * Get an LDAP session handle for communicating with the farm servers.
  96. *
  97. * Returns an LDAP eror code, typically:
  98. * LDAP_SUCCESS
  99. * LDAP_TIMELIMIT_EXCEEDED
  100. * LDAP_CONNECT_ERROR
  101. * NOTE : if maxtime NULL, use operation timeout
  102. */
  103. int cb_get_connection(cb_conn_pool * pool, LDAP ** lld, cb_outgoing_conn ** cc,struct timeval * maxtime, char **errmsg) {
  104. int rc=LDAP_SUCCESS; /* optimistic */
  105. cb_outgoing_conn *conn=NULL;
  106. cb_outgoing_conn *connprev=NULL;
  107. LDAP *ld=NULL;
  108. time_t endbefore=0;
  109. int checktime=0;
  110. struct timeval bind_to, op_to;
  111. unsigned int maxconcurrency,maxconnections;
  112. char *password,*binddn,*hostname;
  113. unsigned int port;
  114. int secure;
  115. static char *error1="Can't contact remote server : %s";
  116. static char *error2="Can't bind to remote server : %s";
  117. int isMultiThread = ENABLE_MULTITHREAD_PER_CONN ; /* by default, we enable multiple operations per connection */
  118. /*
  119. ** return an error if we can't get a connection
  120. ** before the operation timeout has expired
  121. ** bind_timeout: timeout for the bind operation (if bind needed)
  122. ** ( checked in ldap_result )
  123. ** op_timeout: timeout for the op that needs a connection
  124. ** ( checked in the loop )
  125. */
  126. *cc=NULL;
  127. PR_RWLock_Rlock(pool->rwl_config_lock);
  128. maxconcurrency=pool->conn.maxconcurrency;
  129. maxconnections=pool->conn.maxconnections;
  130. bind_to.tv_sec = pool->conn.bind_timeout.tv_sec;
  131. bind_to.tv_usec = pool->conn.bind_timeout.tv_usec;
  132. op_to.tv_sec = pool->conn.op_timeout.tv_sec;
  133. op_to.tv_usec = pool->conn.op_timeout.tv_usec;
  134. /* SD 02/10/2000 temp fix */
  135. /* allow dynamic update of the binddn & password */
  136. /* host, port and security mode */
  137. /* previous values are NOT freed when changed */
  138. /* won't likely to be changed often */
  139. /* pointers put in the waste basket fields and */
  140. /* freed when the backend is stopped. */
  141. password=pool->password;
  142. binddn=pool->binddn;
  143. hostname=pool->hostname;
  144. port=pool->port;
  145. secure=pool->secure;
  146. PR_RWLock_Unlock(pool->rwl_config_lock);
  147. if (secure) {
  148. isMultiThread = DISABLE_MULTITHREAD_PER_CONN ;
  149. }
  150. /* For stupid admins */
  151. if (maxconnections <=0) {
  152. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  153. "<== cb_get_connection error (no connection available)\n");
  154. if ( errmsg ) {
  155. *errmsg = slapi_ch_malloc(CB_BUFSIZE);
  156. sprintf(*errmsg,error1,"no connection available");
  157. }
  158. return LDAP_CONNECT_ERROR;
  159. }
  160. if (maxtime) {
  161. if (maxtime->tv_sec != 0) {
  162. checktime=1;
  163. endbefore = current_time() + maxtime->tv_sec;
  164. /* make sure bind to <= operation timeout */
  165. if ((bind_to.tv_sec==0) || (bind_to.tv_sec > maxtime->tv_sec))
  166. bind_to.tv_sec=maxtime->tv_sec;
  167. }
  168. } else {
  169. if (op_to.tv_sec != 0) {
  170. checktime=1;
  171. endbefore = current_time() + op_to.tv_sec;
  172. /* make sure bind to <= operation timeout */
  173. if ((bind_to.tv_sec==0) || (bind_to.tv_sec > op_to.tv_sec))
  174. bind_to.tv_sec=op_to.tv_sec;
  175. }
  176. }
  177. /*
  178. * Close (or mark to be closed) any connections for this farm server that have
  179. * exceeded the maximum connection lifetime.
  180. */
  181. cb_check_for_stale_connections(pool);
  182. /*
  183. * Look for an available, already open connection
  184. */
  185. slapi_lock_mutex( pool->conn.conn_list_mutex );
  186. if (cb_debug_on()) {
  187. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  188. "==> cb_get_connection server %s conns: %d maxconns: %d\n",
  189. hostname, pool->conn.conn_list_count, maxconnections );
  190. }
  191. for (;;) {
  192. /* time limit mgmt */
  193. if (checktime) {
  194. if (current_time() > endbefore ) {
  195. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  196. "cb_get_connection server %s expired.\n", hostname );
  197. if ( errmsg ) {
  198. *errmsg = slapi_ch_malloc(CB_BUFSIZE);
  199. sprintf(*errmsg,error1,"timelimit exceeded");
  200. }
  201. rc=LDAP_TIMELIMIT_EXCEEDED;
  202. conn=NULL;
  203. ld=NULL;
  204. goto unlock_and_return;
  205. }
  206. }
  207. /*
  208. * First, look for an available, already open/bound connection
  209. */
  210. if (secure) {
  211. for (conn = pool->connarray[PR_ThreadSelf()]; conn != NULL; conn = conn->next) {
  212. if ((conn->ThreadId == PR_MyThreadId()) && (conn->status == CB_CONNSTATUS_OK &&
  213. conn->refcount < maxconcurrency)){
  214. if (cb_debug_on()) {
  215. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  216. "<= cb_get_connection server found conn 0x%x to use)\n", conn );
  217. }
  218. goto unlock_and_return; /* found one */
  219. }
  220. }
  221. }
  222. else {
  223. connprev = NULL;
  224. for ( conn = pool->conn.conn_list; conn != NULL; conn = conn->next ) {
  225. if (cb_debug_on()) {
  226. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  227. "list: conn 0x%x status %d refcount %d\n", conn,
  228. conn->status, conn->refcount );
  229. }
  230. if ( conn->status == CB_CONNSTATUS_OK
  231. && conn->refcount < maxconcurrency ) {
  232. if (cb_debug_on()) {
  233. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  234. "<= cb_get_connection server found conn 0x%x to use)\n", conn );
  235. }
  236. goto unlock_and_return; /* found one */
  237. }
  238. connprev = conn;
  239. }
  240. }
  241. if ( secure || pool->conn.conn_list_count <maxconnections) {
  242. int version=LDAP_VERSION3;
  243. /* check wether the security libraries are correctly initialized */
  244. if (secure && slapd_security_library_is_initialized() != 1) {
  245. slapi_log_error(
  246. SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
  247. "SSL Not Initialized, Chaining Backend over SSL FAILED\n");
  248. rc = LDAP_CONNECT_ERROR;
  249. goto unlock_and_return;
  250. }
  251. /*
  252. * we have not exceeded the maximum number of connections allowed,
  253. * so we initialize a new one and add it to the end of our list.
  254. */
  255. /* No need to lock. url can't be changed dynamically */
  256. if ((ld=slapi_ldap_init(hostname,port,secure,isMultiThread))== NULL) {
  257. if (cb_debug_on()) {
  258. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  259. "Can't contact server <%s> port <%d>.\n", hostname, port);
  260. }
  261. if ( errmsg ) {
  262. *errmsg = slapi_ch_malloc(CB_BUFSIZE);
  263. sprintf(*errmsg,error1,"unknown reason");
  264. }
  265. rc = LDAP_CONNECT_ERROR;
  266. goto unlock_and_return;
  267. }
  268. ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
  269. /* Don't chase referrals */
  270. ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
  271. /* no controls and simple bind only */
  272. /* For now, bind even if no user to detect error */
  273. /* earlier */
  274. if (pool->bindit) {
  275. int msgid;
  276. LDAPMessage *res=NULL;
  277. int parse_rc;
  278. PRErrorCode prerr = 0;
  279. LDAPControl **serverctrls=NULL;
  280. char **referrals=NULL;
  281. char *plain = NULL;
  282. int ret = -1;
  283. rc=LDAP_SUCCESS;
  284. if (cb_debug_on()) {
  285. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  286. "Bind to to server <%s> port <%d> as <%s>\n",
  287. hostname, port, binddn);
  288. }
  289. ret = pw_rever_decode(password, &plain, CB_CONFIG_USERPASSWORD);
  290. /* Pb occured in decryption: stop now, binding will fail */
  291. if ( ret == -1 )
  292. {
  293. if (cb_debug_on()) {
  294. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  295. "Internal credentials decoding error\n.",
  296. 0, 0, 0);
  297. }
  298. rc = LDAP_LOCAL_ERROR;
  299. goto unlock_and_return;
  300. }
  301. /* Password-based client authentication */
  302. if (( msgid = ldap_simple_bind( ld, binddn, plain)) <0) {
  303. rc=ldap_get_lderrno( ld, NULL, NULL );
  304. prerr=PR_GetError();
  305. }
  306. if ( ret == 0 ) free(plain); /* free plain only if it has been duplicated */
  307. if ( rc != LDAP_SUCCESS ) {
  308. if (cb_debug_on()) {
  309. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  310. "Can't bind to server <%s> port <%d>. "
  311. "(LDAP error %d - %s; "
  312. SLAPI_COMPONENT_NAME_NSPR " error %d - %s)\n",
  313. hostname, port, rc,
  314. ldap_err2string(rc),
  315. prerr, slapd_pr_strerror(prerr));
  316. }
  317. if ( errmsg ) {
  318. *errmsg = slapi_ch_malloc(CB_BUFSIZE);
  319. sprintf(*errmsg,error2, ldap_err2string(rc));
  320. }
  321. rc = LDAP_CONNECT_ERROR;
  322. goto unlock_and_return;
  323. }
  324. rc = ldap_result( ld, msgid, 0, &bind_to, &res );
  325. switch (rc) {
  326. case -1:
  327. rc = ldap_get_lderrno( ld, NULL, NULL );
  328. if (cb_debug_on()) {
  329. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  330. "Can't bind to server <%s> port <%d>. "
  331. "(LDAP error %d - %s; "
  332. SLAPI_COMPONENT_NAME_NSPR " error %d - %s)\n",
  333. hostname, port, rc,
  334. ldap_err2string(rc),
  335. prerr, slapd_pr_strerror(prerr));
  336. }
  337. if ( errmsg ) {
  338. *errmsg = slapi_ch_malloc(CB_BUFSIZE);
  339. sprintf(*errmsg,error2,ldap_err2string(rc));
  340. }
  341. rc = LDAP_CONNECT_ERROR;
  342. goto unlock_and_return;
  343. case 0:
  344. if (cb_debug_on()) {
  345. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  346. "Can't bind to server <%s> port <%d>. (%s)\n",
  347. hostname, port, "time-out expired");
  348. }
  349. rc = LDAP_CONNECT_ERROR;
  350. goto unlock_and_return;
  351. default:
  352. parse_rc = ldap_parse_result( ld, res, &rc, NULL,
  353. NULL, &referrals, &serverctrls, 1 );
  354. if ( parse_rc != LDAP_SUCCESS ) {
  355. if (cb_debug_on()) {
  356. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  357. "Can't bind to server <%s> port <%d>. (%s)\n",
  358. hostname, port, ldap_err2string(parse_rc));
  359. }
  360. if ( errmsg ) {
  361. *errmsg = slapi_ch_malloc(CB_BUFSIZE);
  362. sprintf(*errmsg,error2,ldap_err2string(parse_rc));
  363. }
  364. rc = parse_rc;
  365. goto unlock_and_return;
  366. }
  367. if ( rc != LDAP_SUCCESS ) {
  368. if (cb_debug_on()) {
  369. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  370. "Can't bind to server <%s> port <%d>. (%s)\n",
  371. hostname, port, ldap_err2string(rc));
  372. }
  373. if ( errmsg ) {
  374. *errmsg = slapi_ch_malloc(CB_BUFSIZE);
  375. sprintf(*errmsg,error2, ldap_err2string(rc));
  376. }
  377. goto unlock_and_return;
  378. }
  379. if ( serverctrls )
  380. {
  381. int i;
  382. for( i = 0; serverctrls[ i ] != NULL; ++i )
  383. {
  384. if ( !(strcmp( serverctrls[ i ]->ldctl_oid, LDAP_CONTROL_PWEXPIRED)) )
  385. {
  386. /* Bind is successful but password has expired */
  387. slapi_log_error(SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
  388. "Succesfully bound as %s to remote server %s:%d, "
  389. "but password has expired.\n",
  390. binddn, hostname, port);
  391. }
  392. else if ( !(strcmp( serverctrls[ i ]->ldctl_oid, LDAP_CONTROL_PWEXPIRING)) )
  393. {
  394. /* The password is expiring in n seconds */
  395. if ( (serverctrls[ i ]->ldctl_value.bv_val != NULL) &&
  396. (serverctrls[ i ]->ldctl_value.bv_len > 0) )
  397. {
  398. int password_expiring = atoi( serverctrls[ i ]->ldctl_value.bv_val );
  399. slapi_log_error(SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
  400. "Succesfully bound as %s to remote server %s:%d, "
  401. "but password is expiring in %d seconds.\n",
  402. binddn, hostname, port, password_expiring);
  403. }
  404. }
  405. }
  406. ldap_controls_free(serverctrls);
  407. }
  408. if (referrals)
  409. charray_free(referrals);
  410. }
  411. }
  412. conn = (cb_outgoing_conn *) slapi_ch_malloc(sizeof(cb_outgoing_conn));
  413. conn->ld=ld;
  414. conn->status=CB_CONNSTATUS_OK;
  415. conn->refcount=0; /* incremented below */
  416. conn->opentime=current_time();
  417. conn->ThreadId=PR_MyThreadId(); /* store the thread id */
  418. conn->next=NULL;
  419. if (secure) {
  420. if (pool->connarray[PR_ThreadSelf()] == NULL) {
  421. pool->connarray[PR_ThreadSelf()] = conn;
  422. }
  423. else {
  424. conn->next = pool->connarray[PR_ThreadSelf()];
  425. pool->connarray[PR_ThreadSelf()] = conn ;
  426. }
  427. }
  428. else {
  429. if ( NULL == connprev ) {
  430. pool->conn.conn_list = conn;
  431. } else {
  432. connprev->next=conn;
  433. }
  434. }
  435. ++pool->conn.conn_list_count;
  436. if (cb_debug_on()) {
  437. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  438. "<= cb_get_connection added new conn 0x%x, "
  439. "conn count now %d\n", conn->ld, pool->conn.conn_list_count );
  440. }
  441. goto unlock_and_return; /* got a new one */
  442. }
  443. if (cb_debug_on()) {
  444. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  445. "... cb_get_connection waiting for conn to free up\n" );
  446. }
  447. if (!secure) slapi_wait_condvar( pool->conn.conn_list_cv, NULL );
  448. if (cb_debug_on()) {
  449. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  450. "... cb_get_connection awake again\n" );
  451. }
  452. }
  453. unlock_and_return:
  454. if ( conn != NULL ) {
  455. ++conn->refcount;
  456. *lld=conn->ld;
  457. *cc=conn;
  458. if (cb_debug_on()) {
  459. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  460. "<== cb_get_connection ld=0x%x (concurrency now %d)\n",*lld, conn->refcount );
  461. }
  462. } else {
  463. if ( NULL != ld ) {
  464. slapi_ldap_unbind( ld );
  465. }
  466. if (cb_debug_on()) {
  467. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  468. "<== cb_get_connection error %d\n", rc );
  469. }
  470. }
  471. slapi_unlock_mutex(pool->conn.conn_list_mutex);
  472. return( rc );
  473. }
  474. /*
  475. * We are done with the connection handle because the
  476. * LDAP operation has completed.
  477. */
  478. void cb_release_op_connection(cb_conn_pool* pool, LDAP *lld, int dispose) {
  479. cb_outgoing_conn *conn;
  480. cb_outgoing_conn *connprev = NULL;
  481. int secure = pool->secure;
  482. int myself = 0;
  483. slapi_lock_mutex(pool->conn.conn_list_mutex);
  484. /*
  485. * find the connection structure this ld is part of
  486. */
  487. if (secure) {
  488. myself = PR_ThreadSelf();
  489. for (conn = pool->connarray[myself]; conn != NULL; conn = conn->next ) {
  490. if ( lld == conn->ld )
  491. break;
  492. connprev = conn;
  493. }
  494. }
  495. else {
  496. for ( conn = pool->conn.conn_list; conn != NULL; conn = conn->next ){
  497. if ( lld == conn->ld )
  498. break;
  499. connprev = conn;
  500. }
  501. }
  502. if ( conn == NULL ) { /* ld not found -- unexpected */
  503. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  504. "==> cb_release_op_connection ld=0x%x not found\n", lld );
  505. } else {
  506. --conn->refcount;
  507. if (cb_debug_on()) {
  508. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  509. "release conn 0x%x status %d refcount after release %d\n", conn,
  510. conn->status, conn->refcount );
  511. }
  512. if ( dispose ) {
  513. conn->status = CB_CONNSTATUS_DOWN;
  514. }
  515. if ( conn->status != CB_CONNSTATUS_OK && conn->refcount == 0 ) {
  516. /*
  517. * remove from server's connection list
  518. */
  519. if (!secure) {
  520. if ( connprev == NULL ) {
  521. pool->conn.conn_list = conn->next;
  522. } else {
  523. connprev->next = conn->next;
  524. }
  525. }
  526. else {
  527. if ( connprev == NULL ) {
  528. pool->connarray[myself] = conn->next;
  529. } else {
  530. connprev->next = conn->next;
  531. }
  532. }
  533. --pool->conn.conn_list_count;
  534. /*
  535. * close connection and free memory
  536. */
  537. cb_close_and_dispose_connection( conn );
  538. }
  539. }
  540. /*
  541. * wake up a thread that is waiting for a connection
  542. */
  543. if (!secure) slapi_notify_condvar( pool->conn.conn_list_cv, 0 );
  544. slapi_unlock_mutex( pool->conn.conn_list_mutex );
  545. }
  546. static void
  547. cb_close_and_dispose_connection( cb_outgoing_conn *conn )
  548. {
  549. slapi_ldap_unbind( conn->ld );
  550. conn->ld = NULL;
  551. slapi_ch_free( (void **)&conn );
  552. }
  553. static void cb_check_for_stale_connections(cb_conn_pool * pool) {
  554. cb_outgoing_conn * connprev, *conn, *conn_next;
  555. time_t curtime;
  556. int connlifetime;
  557. int myself;
  558. PR_RWLock_Rlock(pool->rwl_config_lock);
  559. connlifetime=pool->conn.connlifetime;
  560. PR_RWLock_Unlock(pool->rwl_config_lock);
  561. connprev = NULL;
  562. conn_next = NULL;
  563. slapi_lock_mutex(pool->conn.conn_list_mutex);
  564. if (connlifetime > 0)
  565. curtime=current_time();
  566. if (pool->secure) {
  567. myself = PR_ThreadSelf();
  568. for (conn = pool->connarray[myself]; conn != NULL; conn = conn_next){
  569. if ((conn->status == CB_CONNSTATUS_STALE) ||
  570. (( connlifetime > 0) && (curtime - conn->opentime > connlifetime))) {
  571. if ( conn->refcount == 0 ) {
  572. if (cb_debug_on()) {
  573. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  574. "cb_check_for_stale_connections: conn 0x%x idle and stale\n",conn);
  575. }
  576. --pool->conn.conn_list_count;
  577. if (connprev == NULL) {
  578. pool->connarray[myself] = conn->next ;
  579. }
  580. else {
  581. connprev->next = conn->next ;
  582. }
  583. conn_next = conn->next ;
  584. cb_close_and_dispose_connection( conn );
  585. continue;
  586. }
  587. /* Connection is stale but in use */
  588. /* Mark to be disposed later but let it in the backend list */
  589. /* so that it is counted as a valid connection */
  590. else {
  591. conn->status = CB_CONNSTATUS_STALE;
  592. }
  593. if (cb_debug_on()) {
  594. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  595. "cb_check_for_stale_connections: conn 0x%x stale\n",conn);
  596. }
  597. }
  598. connprev = conn ;
  599. conn_next = conn->next;
  600. }
  601. slapi_unlock_mutex(pool->conn.conn_list_mutex);
  602. return;
  603. }
  604. for ( conn = pool->conn.conn_list; conn != NULL; conn=conn_next ) {
  605. if ((conn->status == CB_CONNSTATUS_STALE) ||
  606. (( connlifetime > 0) && (curtime - conn->opentime > connlifetime))) {
  607. if ( conn->refcount == 0 ) {
  608. /* Connection idle & stale. Remove and free. */
  609. if ( NULL == connprev )
  610. pool->conn.conn_list = conn->next;
  611. else
  612. connprev->next=conn->next;
  613. if (cb_debug_on()) {
  614. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  615. "cb_check_for_stale_connections: conn 0x%x idle and stale\n",conn);
  616. }
  617. --pool->conn.conn_list_count;
  618. conn_next=conn->next;
  619. cb_close_and_dispose_connection( conn );
  620. continue;
  621. }
  622. /* Connection is stale but in use */
  623. /* Mark to be disposed later but let it in the backend list */
  624. /* so that it is counted as a valid connection */
  625. else {
  626. conn->status = CB_CONNSTATUS_STALE;
  627. }
  628. if (cb_debug_on()) {
  629. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  630. "cb_check_for_stale_connections: conn 0x%x stale\n",conn);
  631. }
  632. }
  633. connprev = conn;
  634. conn_next=conn->next;
  635. }
  636. /* Generate an event to wake up threads waiting */
  637. /* for a conn to be released. Useful to detect */
  638. /* exceeded time limit. May be expensive */
  639. slapi_notify_condvar( pool->conn.conn_list_cv, 0 );
  640. slapi_unlock_mutex(pool->conn.conn_list_mutex);
  641. }
  642. /*
  643. * close all open connections in preparation for server shutdown, etc.
  644. * WARNING: Don't wait for current operations to complete
  645. */
  646. void
  647. cb_close_all_connections( Slapi_Backend * be )
  648. {
  649. cb_outgoing_conn *conn, *next_conn;
  650. cb_backend_instance * cb= cb_get_instance(be);
  651. int i;
  652. slapi_lock_mutex(cb->pool->conn.conn_list_mutex);
  653. if (cb->pool->secure) {
  654. for (i=0; i< MAX_CONN_ARRAY; i++) {
  655. for (conn = cb->pool->connarray[i]; conn != NULL; conn = next_conn ){
  656. next_conn = conn->next;
  657. cb_close_and_dispose_connection(conn);
  658. }
  659. }
  660. } else {
  661. for ( conn = cb->pool->conn.conn_list; conn != NULL; conn = next_conn ) {
  662. next_conn=conn->next;
  663. cb_close_and_dispose_connection(conn);
  664. }
  665. }
  666. slapi_unlock_mutex(cb->pool->conn.conn_list_mutex);
  667. slapi_lock_mutex(cb->bind_pool->conn.conn_list_mutex);
  668. if (cb->bind_pool->secure) {
  669. for (i=0; i< MAX_CONN_ARRAY; i++) {
  670. for (conn = cb->bind_pool->connarray[i]; conn != NULL; conn = next_conn ){
  671. next_conn=conn->next;
  672. cb_close_and_dispose_connection(conn);
  673. }
  674. }
  675. } else {
  676. for ( conn = cb->bind_pool->conn.conn_list; conn != NULL; conn = next_conn ) {
  677. next_conn=conn->next;
  678. cb_close_and_dispose_connection(conn);
  679. }
  680. }
  681. slapi_unlock_mutex(cb->bind_pool->conn.conn_list_mutex);
  682. }
  683. /* Mark used connections as stale and close unsued connections */
  684. /* Called when the target farm url has changed */
  685. void cb_stale_all_connections( cb_backend_instance * cb)
  686. {
  687. cb_outgoing_conn *conn, *next_conn, *prev_conn;
  688. int notify=0;
  689. int i, j;
  690. cb_conn_pool *pools[3];
  691. pools[0]=cb->pool;
  692. pools[1]=cb->bind_pool;
  693. pools[2]=NULL;
  694. for (i=0; pools[i]; i++) {
  695. slapi_lock_mutex(pools[i]->conn.conn_list_mutex);
  696. for (j=0; j< MAX_CONN_ARRAY; j++) {
  697. prev_conn=NULL;
  698. for (conn = pools[i]->connarray[j]; conn != NULL; conn=next_conn) {
  699. next_conn=conn->next;
  700. if (conn->refcount > 0) {
  701. /*
  702. ** Connection is stale but in use
  703. ** Mark to be disposed later but let it in the backend list
  704. ** so that it is counted as a valid connection
  705. */
  706. conn->status = CB_CONNSTATUS_STALE;
  707. prev_conn=conn;
  708. } else {
  709. if (prev_conn == NULL) {
  710. pools[i]->connarray[j]=next_conn;
  711. } else {
  712. prev_conn->next=next_conn;
  713. }
  714. cb_close_and_dispose_connection(conn);
  715. pools[i]->conn.conn_list_count--;
  716. }
  717. }
  718. }
  719. prev_conn = NULL ;
  720. for ( conn = pools[i]->conn.conn_list; conn != NULL; conn = next_conn ) {
  721. next_conn=conn->next;
  722. if (conn->refcount > 0) {
  723. /*
  724. ** Connection is stale but in use
  725. ** Mark to be disposed later but let it in the backend list
  726. ** so that it is counted as a valid connection
  727. */
  728. conn->status = CB_CONNSTATUS_STALE;
  729. prev_conn=conn;
  730. }
  731. else {
  732. if (conn==pools[i]->conn.conn_list) {
  733. pools[i]->conn.conn_list=next_conn;
  734. } else {
  735. prev_conn->next=next_conn;
  736. }
  737. cb_close_and_dispose_connection(conn);
  738. pools[i]->conn.conn_list_count--;
  739. notify=1;
  740. }
  741. }
  742. if (notify && (! pools[i]->secure)) {
  743. slapi_notify_condvar( pools[i]->conn.conn_list_cv, 0 );
  744. }
  745. slapi_unlock_mutex(pools[i]->conn.conn_list_mutex);
  746. }
  747. }
  748. /**************************************************************************/
  749. /* Need to use our own connect function until we've switched to C-SDK 4.1 */
  750. /* to have a timeout in the connect system call. */
  751. /**************************************************************************/
  752. static int global_connect_to;
  753. #if 0
  754. /* Taken from C-SDK 4.1 */
  755. #include <fcntl.h>
  756. #include <errno.h>
  757. #define LDAP_X_IO_TIMEOUT_NO_TIMEOUT (-1)
  758. static int
  759. nsldapi_os_connect_with_to(LBER_SOCKET sockfd, struct sockaddr *saptr,
  760. int salen)
  761. {
  762. #ifndef _WIN32
  763. int flags;
  764. #endif /* _WIN32 */
  765. int n, error;
  766. int len;
  767. fd_set rset, wset;
  768. struct timeval tval;
  769. #ifdef _WIN32
  770. int nonblock = 1;
  771. int block = 0;
  772. fd_set eset;
  773. #endif /* _WIN32 */
  774. int msec=global_connect_to; /* global */
  775. #ifdef _WIN32
  776. ioctlsocket(sockfd, FIONBIO, &nonblock);
  777. #else
  778. flags = fcntl(sockfd, F_GETFL, 0);
  779. fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
  780. #endif /* _WIN32 */
  781. error = 0;
  782. if ((n = connect(sockfd, saptr, salen)) < 0)
  783. #ifdef _WIN32
  784. if ((n != SOCKET_ERROR) && (WSAGetLastError() != WSAEWOULDBLOCK)) {
  785. #else
  786. if (errno != EINPROGRESS) {
  787. #endif /* _WIN32 */
  788. return (-1);
  789. }
  790. /* success */
  791. if (n == 0)
  792. goto done;
  793. FD_ZERO(&rset);
  794. FD_SET(sockfd, &rset);
  795. wset = rset;
  796. #ifdef _WIN32
  797. eset = rset;
  798. #endif /* _WIN32 */
  799. if (msec < 0 && msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) {
  800. msec = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
  801. } else {
  802. if (msec != 0)
  803. tval.tv_sec = msec / 1000;
  804. else
  805. tval.tv_sec = 0;
  806. tval.tv_usec = 0;
  807. }
  808. /* if timeval structure == NULL, select will block indefinitely */
  809. /* != NULL, and value == 0, select will */
  810. /* not block */
  811. /* Windows is a bit quirky on how it behaves w.r.t nonblocking */
  812. /* connects. If the connect fails, the exception fd, eset, is */
  813. /* set to show the failure. The first argument in select is */
  814. /* ignored */
  815. #ifdef _WIN32
  816. if ((n = select(sockfd +1, &rset, &wset, &eset,
  817. (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
  818. errno = WSAETIMEDOUT;
  819. return (-1);
  820. }
  821. /* if wset is set, the connect worked */
  822. if (FD_ISSET(sockfd, &wset) || FD_ISSET(sockfd, &rset)) {
  823. len = sizeof(error);
  824. if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
  825. < 0)
  826. return (-1);
  827. goto done;
  828. }
  829. /* if eset is set, the connect failed */
  830. if (FD_ISSET(sockfd, &eset)) {
  831. return (-1);
  832. }
  833. /* failure on select call */
  834. if (n == SOCKET_ERROR) {
  835. return (-1);
  836. }
  837. #else
  838. if ((n = select(sockfd +1, &rset, &wset, NULL,
  839. (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
  840. errno = ETIMEDOUT;
  841. return (-1);
  842. }
  843. if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
  844. len = sizeof(error);
  845. if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
  846. < 0)
  847. return (-1);
  848. }
  849. #endif /* _WIN32 */
  850. done:
  851. #ifdef _WIN32
  852. ioctlsocket(sockfd, FIONBIO, &block);
  853. #else
  854. fcntl(sockfd, F_SETFL, flags);
  855. #endif /* _WIN32 */
  856. if (error) {
  857. errno = error;
  858. return (-1);
  859. }
  860. return (0);
  861. }
  862. #endif
  863. /* Try to figure out if a farm server is still alive */
  864. int cb_ping_farm(cb_backend_instance *cb, cb_outgoing_conn * cnx,time_t end_time) {
  865. char *attrs[] ={"1.1",NULL};
  866. int rc;
  867. struct timeval timeout;
  868. LDAP *ld;
  869. LDAPMessage *result;
  870. #if 0
  871. struct ldap_io_fns iof;
  872. #endif
  873. time_t now;
  874. if (cb->max_idle_time <=0) /* Heart-beat disabled */
  875. return LDAP_SUCCESS;
  876. if (cnx && (cnx->status != CB_CONNSTATUS_OK )) /* Known problem */
  877. return LDAP_SERVER_DOWN;
  878. now = current_time();
  879. if (end_time && ((now <= end_time) || (end_time <0))) return LDAP_SUCCESS;
  880. ld=slapi_ldap_init(cb->pool->hostname,cb->pool->port,cb->pool->secure,0);
  881. if (NULL == ld) {
  882. cb_update_failed_conn_cpt( cb );
  883. return LDAP_SERVER_DOWN;
  884. }
  885. #if 0
  886. memset(&iof,0,sizeof(struct ldap_io_fns));
  887. if (LDAP_SUCCESS !=ldap_get_option(ld,LDAP_OPT_IO_FN_PTRS,&iof)) {
  888. slapi_ldap_unbind( ld );
  889. cb_update_failed_conn_cpt( cb );
  890. return LDAP_SERVER_DOWN;
  891. }
  892. iof.liof_connect = nsldapi_os_connect_with_to;
  893. if (LDAP_SUCCESS !=ldap_set_option(ld,LDAP_OPT_IO_FN_PTRS,&iof)) {
  894. slapi_ldap_unbind( ld );
  895. cb_update_failed_conn_cpt( cb );
  896. return LDAP_SERVER_DOWN;
  897. }
  898. #endif
  899. timeout.tv_sec=cb->max_test_time;
  900. timeout.tv_usec=0;
  901. global_connect_to=cb->max_test_time * 1000; /* Reuse the same for the connect */
  902. rc=ldap_search_ext_s(ld ,NULL,LDAP_SCOPE_BASE,"objectclass=*",attrs,1,NULL,
  903. NULL, &timeout, 1,&result);
  904. if ( LDAP_SUCCESS != rc ) {
  905. slapi_ldap_unbind( ld );
  906. cb_update_failed_conn_cpt( cb );
  907. return LDAP_SERVER_DOWN;
  908. }
  909. ldap_msgfree(result);
  910. slapi_ldap_unbind( ld );
  911. cb_reset_conn_cpt( cb );
  912. return LDAP_SUCCESS;
  913. }
  914. void cb_update_failed_conn_cpt ( cb_backend_instance *cb ) {
  915. /* if the chaining BE is already unavailable, we do nothing*/
  916. time_t now;
  917. if (cb->monitor_availability.farmserver_state == FARMSERVER_AVAILABLE) {
  918. slapi_lock_mutex(cb->monitor_availability.cpt_lock);
  919. cb->monitor_availability.cpt ++;
  920. slapi_unlock_mutex(cb->monitor_availability.cpt_lock);
  921. if (cb->monitor_availability.cpt >= CB_NUM_CONN_BEFORE_UNAVAILABILITY ) {
  922. /* we reach the limit of authorized failed connections => we setup the chaining BE state to unavailable */
  923. now = current_time();
  924. slapi_lock_mutex(cb->monitor_availability.lock_timeLimit);
  925. cb->monitor_availability.unavailableTimeLimit = now + CB_UNAVAILABLE_PERIOD ;
  926. slapi_unlock_mutex(cb->monitor_availability.lock_timeLimit);
  927. cb->monitor_availability.farmserver_state = FARMSERVER_UNAVAILABLE ;
  928. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  929. "cb_update_failed_conn_cpt: Farm server unavailable");
  930. }
  931. }
  932. }
  933. void cb_reset_conn_cpt( cb_backend_instance *cb ) {
  934. if (cb->monitor_availability.cpt > 0) {
  935. slapi_lock_mutex(cb->monitor_availability.cpt_lock);
  936. cb->monitor_availability.cpt = 0 ;
  937. if (cb->monitor_availability.farmserver_state == FARMSERVER_UNAVAILABLE) {
  938. cb->monitor_availability.farmserver_state = FARMSERVER_AVAILABLE ;
  939. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  940. "cb_reset_conn_cpt: Farm server is back");
  941. }
  942. slapi_unlock_mutex(cb->monitor_availability.cpt_lock);
  943. }
  944. }
  945. int cb_check_availability( cb_backend_instance *cb, Slapi_PBlock *pb ) {
  946. /* check wether the farmserver is available or not */
  947. int rc ;
  948. time_t now ;
  949. if ( cb->monitor_availability.farmserver_state == FARMSERVER_UNAVAILABLE ){
  950. slapi_lock_mutex(cb->monitor_availability.lock_timeLimit);
  951. now = current_time();
  952. if (now >= cb->monitor_availability.unavailableTimeLimit) {
  953. cb->monitor_availability.unavailableTimeLimit = now + CB_INFINITE_TIME ; /* to be sure only one thread can do the test */
  954. slapi_unlock_mutex(cb->monitor_availability.lock_timeLimit);
  955. }
  956. else {
  957. slapi_unlock_mutex(cb->monitor_availability.lock_timeLimit);
  958. cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, "FARM SERVER TEMPORARY UNAVAILABLE", 0, NULL) ;
  959. return FARMSERVER_UNAVAILABLE ;
  960. }
  961. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  962. "cb_check_availability: ping the farm server and check if it's still unavailable");
  963. if ((rc = cb_ping_farm(cb, NULL, 0)) != LDAP_SUCCESS) { /* farm still unavailable... Just change the timelimit */
  964. slapi_lock_mutex(cb->monitor_availability.lock_timeLimit);
  965. now = current_time();
  966. cb->monitor_availability.unavailableTimeLimit = now + CB_UNAVAILABLE_PERIOD ;
  967. slapi_unlock_mutex(cb->monitor_availability.lock_timeLimit);
  968. cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, "FARM SERVER TEMPORARY UNAVAILABLE", 0, NULL) ;
  969. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  970. "cb_check_availability: Farm server still unavailable");
  971. return FARMSERVER_UNAVAILABLE ;
  972. }
  973. else {
  974. /* farm is back !*/
  975. slapi_lock_mutex(cb->monitor_availability.lock_timeLimit);
  976. now = current_time();
  977. cb->monitor_availability.unavailableTimeLimit = now ; /* the unavailable period is finished */
  978. slapi_unlock_mutex(cb->monitor_availability.lock_timeLimit);
  979. /* The farmer server state backs to FARMSERVER_AVAILABLE, but this already done in cb_ping_farm, and also the reset of cpt*/
  980. return FARMSERVER_AVAILABLE ;
  981. }
  982. }
  983. return FARMSERVER_AVAILABLE ;
  984. }