cb_conn_stateless.c 38 KB

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