cb_conn_stateless.c 38 KB

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