connection.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $TOG: connection.c /main/4 1999/10/14 17:47:12 mgreess $ */
  24. /*
  25. * (c) Copyright 1993, 1994 Hewlett-Packard Company
  26. * (c) Copyright 1993, 1994 International Business Machines Corp.
  27. * (c) Copyright 1993, 1994 Novell, Inc.
  28. * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
  29. */
  30. /*
  31. * This file manages server connections.
  32. */
  33. #include <EUSCompat.h>
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <time.h>
  38. #include <unistd.h>
  39. #include <fcntl.h>
  40. #ifdef HPUX
  41. #include <sys/resource.h>
  42. #endif
  43. #include "connection.h"
  44. #include "rtable2.h"
  45. #include "rtable3.h"
  46. #include "rtable4.h"
  47. #include "cm.h"
  48. #include "debug.h"
  49. #include "agent.h"
  50. #include "convert2-4.h"
  51. #include "convert3-4.h"
  52. #include "rpccalls.h"
  53. #ifdef HPUX
  54. #define MAX_COUNT 10
  55. #else
  56. #define MAX_COUNT 40
  57. #endif
  58. static struct timeval timeout_tv;
  59. static struct timeval retry_tv;
  60. static AUTH *unix_credential = NULL;
  61. static tcp_count = 0;
  62. static cl_count = 0;
  63. static _DtCm_Client_Info *client_cache_head = NULL;
  64. static _DtCm_Client_Info *client_cache_tail = NULL;
  65. /*****************************************************************************
  66. * forward declaration of static functions.
  67. *****************************************************************************/
  68. static void create_auth(CLIENT *cl);
  69. static void destroy_auth(CLIENT *cl);
  70. static _DtCm_Client_Info * get_client_info(char *host, int version);
  71. static void destroy_target_list(_DtCm_Target_List *tlist);
  72. static void destroy_client_info(_DtCm_Client_Info *ci);
  73. static void insert_client_info(_DtCm_Client_Info *ci);
  74. static void delete_client_info(_DtCm_Client_Info *oldci);
  75. static void cleanup_some_connection(_DtCm_Client_Info *dontclose);
  76. static void check_registration(_DtCm_Connection *conn);
  77. static _DtCm_Client_Info * get_new_client_handle(_DtCm_Connection *conn);
  78. static CSA_return_code get_client_handle(const char *host, const u_long prognum,
  79. u_long *vers_outp, const u_long vers_low,
  80. const u_long vers_high, char *nettype,
  81. CLIENT **clnt);
  82. static CSA_return_code regstat4_to_dtcmstatus(Registration_Status_4 stat4);
  83. extern CSA_return_code
  84. _DtCm_create_udp_client(
  85. char *host,
  86. int version,
  87. int timeout,
  88. _DtCm_Client_Info **clnt)
  89. {
  90. CSA_return_code stat;
  91. _DtCm_Client_Info *ci;
  92. u_long vers_out;
  93. CLIENT *cl=NULL;
  94. if (host == NULL || clnt == NULL)
  95. return (CSA_E_INVALID_PARAMETER);
  96. /* if client info is found, we have at least the udp handle */
  97. if (((*clnt) = get_client_info(host, version)) != NULL) {
  98. return (CSA_SUCCESS);
  99. }
  100. #if defined(SunOS)
  101. cl = clnt_create_vers(host, TABLEPROG,
  102. &vers_out, TABLEVERS_2, version, "udp");
  103. if (cl==NULL) {
  104. _DtCm_print_errmsg(clnt_spcreateerror(host));
  105. return (_DtCm_clntstat_to_csastat(rpc_createerr.cf_stat));
  106. }
  107. #else
  108. stat = get_client_handle(host, (u_int)TABLEPROG, &vers_out, TABLEVERS_2,
  109. version, "udp", &cl);
  110. if (stat != CSA_SUCCESS)
  111. return (stat);
  112. #endif
  113. /* if version is lower than requested, check the list again */
  114. if (vers_out < version) {
  115. if ((ci = get_client_info(host, vers_out)) != NULL) {
  116. clnt_destroy(cl);
  117. *clnt = ci;
  118. return (CSA_SUCCESS);
  119. }
  120. }
  121. create_auth(cl);
  122. /* Adjust Timeout */
  123. if (timeout==0) timeout = _DtCM_DEFAULT_TIMEOUT;
  124. timeout_tv.tv_sec = timeout;
  125. timeout_tv.tv_usec = 0;
  126. clnt_control(cl, CLSET_TIMEOUT, (char*)&timeout_tv);
  127. /* UDP only!
  128. time rpc waits for server to reply before retransmission =
  129. 'timeout'. since the retry timeout is set to timeout + 10;
  130. this guarantees there won't
  131. be any retransmisssions resulting in duplicate
  132. transactions in the database.
  133. */
  134. retry_tv.tv_sec = timeout + 10;
  135. retry_tv.tv_usec = 0;
  136. clnt_control(cl, CLSET_RETRY_TIMEOUT, (char*)&retry_tv);
  137. if ((ci = (_DtCm_Client_Info *)calloc(1, sizeof(_DtCm_Client_Info))) == NULL) {
  138. destroy_auth(cl);
  139. clnt_destroy(cl);
  140. return (CSA_E_INSUFFICIENT_MEMORY);
  141. }
  142. if ((ci->host = strdup(host)) == NULL) {
  143. destroy_auth(cl);
  144. clnt_destroy(cl);
  145. free(ci);
  146. return (CSA_E_INSUFFICIENT_MEMORY);
  147. }
  148. ci->udpcl = cl;
  149. ci->vers_out = vers_out;
  150. insert_client_info(ci);
  151. *clnt = ci;
  152. return (CSA_SUCCESS);
  153. }
  154. /*
  155. * Creates tcp client handle. Used for calls that potentially return
  156. * large amount of data. If it fails to create a tcp client handle,
  157. * a udp client handle will be returned.
  158. */
  159. extern CSA_return_code
  160. _DtCm_create_tcp_client(
  161. char *host,
  162. int version,
  163. int timeout,
  164. _DtCm_Client_Info **clnt)
  165. {
  166. CSA_return_code stat;
  167. _DtCm_Client_Info *ci;
  168. u_long vers_out;
  169. CLIENT *cl=NULL;
  170. if (host == NULL || clnt == NULL)
  171. return (CSA_E_INVALID_PARAMETER);
  172. /* Get a udp client handle. This serves two purposes: */
  173. /* - to get a udp handle for an old server which talks only udp */
  174. /* - to invoke a server through inetd since only udp is registered.*/
  175. if ((stat = _DtCm_create_udp_client(host, version, timeout, &ci))
  176. != CSA_SUCCESS) {
  177. return (stat);
  178. } else if (ci->tcpcl) {
  179. *clnt = ci;
  180. return (CSA_SUCCESS);
  181. } else {
  182. /* create tcp connection */
  183. #if defined(SunOS)
  184. cl = clnt_create_vers(host, TABLEPROG, &vers_out,
  185. TABLEVERS_2, version, "tcp");
  186. #else
  187. stat = get_client_handle(host, (u_int)TABLEPROG, &vers_out,
  188. TABLEVERS_2, version, "tcp", &cl);
  189. #endif
  190. /* if can't create tcp connection, use udp */
  191. if (cl==NULL) {
  192. _DtCm_print_errmsg(clnt_spcreateerror(host));
  193. *clnt = ci;
  194. return (CSA_SUCCESS);
  195. }
  196. create_auth(cl);
  197. /* Adjust Timeout */
  198. if (timeout==0) timeout = _DtCM_DEFAULT_TIMEOUT;
  199. timeout_tv.tv_sec = timeout;
  200. timeout_tv.tv_usec = 0;
  201. clnt_control(cl, CLSET_TIMEOUT, (char*)&timeout_tv);
  202. /* don't need to set vers_out since it should
  203. * be the same as that of the udp transport
  204. */
  205. ci->tcpcl = cl;
  206. if (++tcp_count > MAX_COUNT)
  207. /* clean up tcp connections */
  208. cleanup_some_connection(ci);
  209. *clnt = ci;
  210. return (CSA_SUCCESS);
  211. }
  212. }
  213. /*
  214. * Used instead of clnt_call by rtableX_clnt.c
  215. *
  216. * Might need locking for the client handle here since
  217. * it might be purged if something's wrong
  218. */
  219. extern enum clnt_stat
  220. _DtCm_clnt_call(
  221. _DtCm_Connection *conn,
  222. u_long proc,
  223. xdrproc_t inproc,
  224. caddr_t in,
  225. xdrproc_t outproc,
  226. caddr_t out,
  227. struct timeval tout)
  228. {
  229. _DtCm_Client_Info *ci;
  230. _DtCm_Transport_Type ttype;
  231. enum clnt_stat status = RPC_FAILED;
  232. int retry = conn->retry;
  233. while (B_TRUE) {
  234. if (conn->ci == NULL)
  235. break;
  236. else {
  237. ci = conn->ci;
  238. ci->last_used = time(0);
  239. }
  240. if (conn->use == udp_transport || ci->tcpcl == NULL)
  241. ttype = udp_transport;
  242. else
  243. ttype = tcp_transport;
  244. status = clnt_call((ttype == tcp_transport ? ci->tcpcl :
  245. ci->udpcl), proc, inproc, in,
  246. outproc, out, tout);
  247. if ((ttype == udp_transport && status == RPC_TIMEDOUT) ||
  248. (status == RPC_CANTRECV)) {
  249. if (retry) {
  250. retry--;
  251. /* don't retry when stat is RPC_TIMEDOUT
  252. * and transpart is tcp since if the server
  253. * is down, stat would be something else
  254. * like RPC_CANTRECV
  255. */
  256. /* get new client handle */
  257. if (get_new_client_handle(conn) == NULL)
  258. break;
  259. } else {
  260. /* purge the client handle */
  261. delete_client_info(conn->ci);
  262. conn->ci = NULL;
  263. break;
  264. }
  265. } else
  266. break;
  267. }
  268. if (status != RPC_SUCCESS && conn->ci != NULL) {
  269. _DtCm_print_errmsg(clnt_sperror((ttype == tcp_transport ? ci->tcpcl :
  270. ci->udpcl), ci->host));
  271. }
  272. conn->stat = status;
  273. return status;
  274. }
  275. extern CSA_return_code
  276. _DtCm_add_registration(
  277. _DtCm_Client_Info *ci,
  278. char *cal,
  279. unsigned long update_type)
  280. {
  281. _DtCm_Target_List *listp, *prev;
  282. _DtCm_Target_List *listitem;
  283. int result;
  284. if (ci == NULL || cal == NULL)
  285. return (CSA_E_INVALID_PARAMETER);
  286. for (listp = prev = ci->tlist; listp != NULL;
  287. prev = listp, listp = listp->next) {
  288. if ((result = strcmp(listp->cal, cal)) == 0) {
  289. /* registered already */
  290. return (CSA_SUCCESS);
  291. } else if (result > 0)
  292. break;
  293. }
  294. /* register the first time, insert in list in ascending order */
  295. if ((listitem = (_DtCm_Target_List *)calloc(1, sizeof(_DtCm_Target_List))) == NULL)
  296. return (CSA_E_INSUFFICIENT_MEMORY);
  297. if ((listitem->cal = strdup(cal)) == NULL) {
  298. free(listitem);
  299. return (CSA_E_INSUFFICIENT_MEMORY);
  300. }
  301. listitem->update_type = update_type;
  302. if (prev == NULL || listp == prev)
  303. ci->tlist = listitem;
  304. else
  305. prev->next = listitem;
  306. listitem->next = listp;
  307. ci->nregistered++;
  308. return (CSA_SUCCESS);
  309. }
  310. extern void
  311. _DtCm_remove_registration(_DtCm_Client_Info *ci, char *cal)
  312. {
  313. _DtCm_Target_List *listp, *prev;
  314. _DtCm_Client_Info *c;
  315. int result;
  316. if (cal == NULL) return;
  317. /* if found, just increment the number of registration */
  318. for (listp = prev = ci->tlist; listp != NULL;
  319. prev = listp, listp = listp->next) {
  320. if ((result = strcmp(listp->cal, cal)) == 0) {
  321. if (listp == prev)
  322. ci->tlist = listp->next;
  323. else
  324. prev->next = listp->next;
  325. /* free target item */
  326. free(listp->cal);
  327. free(listp);
  328. /*
  329. * if no calendar is registered, close tcp connection
  330. */
  331. if (--(ci->nregistered) == 0) {
  332. if (ci->tcpcl) {
  333. destroy_auth(ci->tcpcl);
  334. clnt_destroy(ci->tcpcl);
  335. ci->tcpcl = NULL;
  336. tcp_count--;
  337. }
  338. /* find other tcp connection for the
  339. * same host
  340. */
  341. for (c = client_cache_head; c != NULL;
  342. c = c->next) {
  343. if ((result = strcmp(c->host,
  344. ci->host)) == 0) {
  345. if (c->nregistered == 0 &&
  346. c->tcpcl) {
  347. destroy_auth(c->tcpcl);
  348. clnt_destroy(c->tcpcl);
  349. c->tcpcl = NULL;
  350. tcp_count--;
  351. }
  352. } else if (result > 0)
  353. break;
  354. }
  355. }
  356. return;
  357. } else if (result > 0)
  358. break;
  359. }
  360. /* not found; impossible */
  361. }
  362. extern CSA_return_code
  363. _DtCm_get_server_rpc_version(char *host, int *version)
  364. {
  365. CSA_return_code stat;
  366. _DtCm_Client_Info *ci;
  367. if (host == NULL) {
  368. return (CSA_E_INVALID_PARAMETER);
  369. }
  370. if ((stat = _DtCm_create_tcp_client(host, TABLEVERS,
  371. _DtCM_INITIAL_TIMEOUT, &ci)) == CSA_SUCCESS)
  372. *version = ci->vers_out;
  373. return (stat);
  374. }
  375. extern CSA_return_code
  376. _DtCm_clntstat_to_csastat(enum clnt_stat clntstat)
  377. {
  378. switch (clntstat) {
  379. #if defined(SunOS)
  380. case RPC_N2AXLATEFAILURE:
  381. #endif
  382. case RPC_UNKNOWNHOST:
  383. return (CSA_X_DT_E_INVALID_SERVER_LOCATION);
  384. case RPC_PROGNOTREGISTERED:
  385. return (CSA_X_DT_E_SERVICE_NOT_REGISTERED);
  386. case RPC_TIMEDOUT:
  387. return (CSA_X_DT_E_SERVER_TIMEOUT);
  388. default:
  389. return (CSA_E_SERVICE_UNAVAILABLE);
  390. }
  391. }
  392. /*****************************************************************************
  393. * static functions used within the file
  394. *****************************************************************************/
  395. static void
  396. create_auth(CLIENT *cl)
  397. {
  398. /* Always cache the Unix style credentials. */
  399. if (unix_credential == NULL)
  400. #if defined(SunOS)
  401. unix_credential = authsys_create_default ();
  402. #else
  403. unix_credential = authunix_create_default ();
  404. #endif
  405. cl->cl_auth = unix_credential;
  406. }
  407. static void
  408. destroy_auth(CLIENT *cl)
  409. {
  410. /* It is a no-op for unix-authentication because we always cache it.
  411. * But we have to destroy it when secure RPC is used.
  412. */
  413. }
  414. /*
  415. * Given a host name, find the _DtCm_Client_Info structure which contains
  416. * both udp and tcp handle to the server running in the host.
  417. */
  418. static _DtCm_Client_Info *
  419. get_client_info(char *host, int version)
  420. {
  421. _DtCm_Client_Info *ci;
  422. int result;
  423. if (host==NULL) return(NULL);
  424. for (ci = client_cache_head; ci != NULL; ci = ci->next) {
  425. if ((result = strcmp(ci->host, host)) == 0) {
  426. if (ci->vers_out <= version)
  427. return(ci);
  428. } else if (result > 0)
  429. break;
  430. }
  431. return(NULL);
  432. }
  433. static void
  434. destroy_target_list(_DtCm_Target_List *tlist)
  435. {
  436. _DtCm_Target_List *listp, *listitem;
  437. for (listp = tlist; listp != NULL; ) {
  438. listitem = listp;
  439. listp = listp->next;
  440. if (listitem->cal)
  441. free(listitem->cal);
  442. free(listitem);
  443. }
  444. }
  445. static void
  446. destroy_client_info(_DtCm_Client_Info *ci)
  447. {
  448. if (ci==NULL) return;
  449. if (ci->host != NULL)
  450. free(ci->host);
  451. if (ci->tcpcl) {
  452. destroy_auth(ci->tcpcl);
  453. clnt_destroy(ci->tcpcl);
  454. tcp_count--;
  455. }
  456. if (ci->udpcl) {
  457. destroy_auth(ci->udpcl);
  458. clnt_destroy(ci->udpcl);
  459. }
  460. destroy_target_list(ci->tlist);
  461. free(ci);
  462. cl_count--;
  463. }
  464. /*
  465. * Don't limit the number of cached connections right now.
  466. * Udp client handle does not use up file descriptor only space.
  467. * Tcp client handle is kept open only when there's at least one
  468. * calendar registered with the host and the user probably won't
  469. * be browsing more than 50 calendar at the same time.
  470. */
  471. static void
  472. insert_client_info(_DtCm_Client_Info *ci)
  473. {
  474. _DtCm_Client_Info *citem;
  475. if (++cl_count > MAX_COUNT)
  476. cleanup_some_connection(ci);
  477. /* insert new item alphabetically */
  478. for (citem = client_cache_head; citem != NULL; citem = citem->next) {
  479. /* there shouldn't be an entry with the same host name
  480. * if there's, it would be picked up in get_client_info()
  481. */
  482. if (strcmp(citem->host, ci->host) > 0)
  483. break;
  484. }
  485. if (citem == NULL) {
  486. if (client_cache_head == NULL)
  487. client_cache_head = client_cache_tail = ci;
  488. else {
  489. ci->prev = client_cache_tail;
  490. client_cache_tail->next = ci;
  491. client_cache_tail = ci;
  492. }
  493. } else {
  494. ci->next = citem;
  495. ci->prev = citem->prev;
  496. if (citem == client_cache_head)
  497. client_cache_head = ci;
  498. else
  499. citem->prev->next = ci;
  500. citem->prev = ci;
  501. }
  502. #ifdef CM_DEBUG
  503. fprintf(stderr, "%s: head = %d, tail = %d, newitem = %d\n",
  504. "insert_client_info", client_cache_head,
  505. client_cache_tail, ci);
  506. fprintf(stderr, "tcp_count = %d, cl_count = %d\n", tcp_count, cl_count);
  507. #endif
  508. }
  509. /*
  510. * remove the client info structure from the list
  511. */
  512. static void
  513. delete_client_info(_DtCm_Client_Info *oldci)
  514. {
  515. if (oldci == NULL) return;
  516. if (oldci == client_cache_head) {
  517. client_cache_head = oldci->next;
  518. if (client_cache_head)
  519. client_cache_head->prev = NULL;
  520. } else if (oldci == client_cache_tail) {
  521. client_cache_tail = oldci->prev;
  522. if (client_cache_tail)
  523. client_cache_tail->next = NULL;
  524. } else {
  525. oldci->prev->next = oldci->next;
  526. oldci->next->prev = oldci->prev;
  527. }
  528. if (oldci == client_cache_tail)
  529. client_cache_tail = NULL;
  530. destroy_client_info(oldci);
  531. #ifdef CM_DEBUG
  532. fprintf(stderr, "%s: head = %d, tail = %d, olditem = %d\n",
  533. "delete_client_info", client_cache_head,
  534. client_cache_tail, oldci);
  535. #endif
  536. }
  537. /*
  538. * Number of open tcp connections reaches the maximum.
  539. * This is very unlikely in the normal case since
  540. * a tcp connection is kept open if at least one calendar
  541. * is registered with the host and a user would not be
  542. * browsing a large number of calendars at one time.
  543. * However, when a calendar is deselected in the calendar
  544. * list on the multi-browser window, a lookup call using
  545. * the tcp connection is made after the calendar is
  546. * deregistered. This keeps the tcp connection open
  547. * even if that's the last calendar registered with the
  548. * host. This routine is used to clean up such tcp connections.
  549. * This is a good time to clean up connections that are not
  550. * used for a long time.
  551. */
  552. static void
  553. cleanup_some_connection(_DtCm_Client_Info *dontclose)
  554. {
  555. _DtCm_Client_Info *ci, *oldci;
  556. int total = 0, deleted = 0, done = 0;
  557. for (ci = client_cache_head; ci != NULL; )
  558. {
  559. total++;
  560. #ifdef HPUX
  561. /* clean up whole list */
  562. if (ci != dontclose && ci->nregistered == 0) {
  563. #else
  564. if (ci != dontclose && ci->nregistered == 0 &&
  565. (ci->tcpcl || (!done && ci->tcpcl == NULL) ||
  566. (ci->tcpcl==NULL && (time(NULL) - ci->last_used)>DAYSEC)))
  567. {
  568. if (!done) done = 1;
  569. #endif
  570. deleted++;
  571. oldci = ci;
  572. ci = ci->next;
  573. delete_client_info(oldci);
  574. } else
  575. ci = ci->next;
  576. }
  577. #ifdef CM_DEBUG
  578. fprintf(stderr, "%s: total = %d, deleted = %d\n",
  579. "cleanup_tcp_connection", total, deleted);
  580. #endif
  581. }
  582. /*
  583. * check registration
  584. * Deergister the first target:
  585. * if it succeeded, the old server is still running, just re-register it;
  586. * else assume that it's a new server so re-register the whole list again.
  587. */
  588. static void
  589. check_registration(_DtCm_Connection *conn)
  590. {
  591. _DtCm_Target_List *listp, *prev;
  592. _DtCm_Transport_Type olduse;
  593. CSA_return_code stat;
  594. if (conn->ci->tlist == NULL)
  595. return;
  596. olduse = conn->use;
  597. conn->use = udp_transport;
  598. conn->retry = B_FALSE;
  599. if ((stat = _DtCm_do_unregistration(conn, conn->ci->tlist->cal,
  600. conn->ci->tlist->update_type)) == CSA_SUCCESS) {
  601. if (_DtCm_do_registration(conn, conn->ci->tlist->cal,
  602. conn->ci->tlist->update_type) != CSA_SUCCESS)
  603. {
  604. conn->ci->nregistered--;
  605. listp = conn->ci->tlist;
  606. conn->ci->tlist = listp->next;
  607. free(listp->cal);
  608. free(listp);
  609. }
  610. } else if (stat == CSA_E_CALLBACK_NOT_REGISTERED || stat == CSA_E_FAILURE) {
  611. for (listp = prev = conn->ci->tlist; listp != NULL; ) {
  612. if (_DtCm_do_registration(conn, listp->cal,
  613. listp->update_type) != CSA_SUCCESS)
  614. {
  615. conn->ci->nregistered--;
  616. if (listp == prev)
  617. conn->ci->tlist = prev = listp->next;
  618. else
  619. prev->next = listp->next;
  620. /* free target item */
  621. free(listp->cal);
  622. free(listp);
  623. listp = (prev ? prev->next : NULL);
  624. } else {
  625. prev = listp;
  626. listp = listp->next;
  627. }
  628. }
  629. }
  630. conn->use = olduse;
  631. }
  632. static _DtCm_Client_Info *
  633. get_new_client_handle(_DtCm_Connection *conn)
  634. {
  635. CLIENT *cl;
  636. int oldver;
  637. if (conn == NULL) return(NULL);
  638. oldver = conn->ci->vers_out;
  639. /* always get a udp client handle first */
  640. #if defined(SunOS)
  641. cl = clnt_create_vers(conn->ci->host, TABLEPROG, &(conn->ci->vers_out),
  642. TABLEVERS_2, oldver, "udp");
  643. if (cl == NULL) {
  644. _DtCm_print_errmsg(clnt_spcreateerror(conn->ci->host));
  645. }
  646. #else
  647. (void) get_client_handle(conn->ci->host, (u_int)TABLEPROG,
  648. &(conn->ci->vers_out), TABLEVERS_2, oldver,
  649. "udp", &cl);
  650. #endif
  651. if (cl == NULL) {
  652. delete_client_info(conn->ci);
  653. conn->ci = NULL;
  654. return(NULL);
  655. } else {
  656. create_auth(cl);
  657. /* adjust timeout */
  658. timeout_tv.tv_sec = _DtCM_INITIAL_TIMEOUT;
  659. timeout_tv.tv_usec = 0;
  660. clnt_control(cl, CLSET_TIMEOUT, (char *)&timeout_tv);
  661. retry_tv.tv_sec = _DtCM_INITIAL_TIMEOUT + 10;
  662. retry_tv.tv_usec = 0;
  663. clnt_control(cl, CLSET_RETRY_TIMEOUT, (char *)&retry_tv);
  664. destroy_auth(conn->ci->udpcl);
  665. clnt_destroy(conn->ci->udpcl);
  666. conn->ci->udpcl = cl;
  667. }
  668. /* check registration */
  669. /* if there's anything wrong, nregistered could be zero */
  670. check_registration(conn);
  671. /* ci might be set to NULL if an rpc call failed */
  672. if (conn->ci == NULL)
  673. return (NULL);
  674. /* now deal with tcp handle */
  675. /* get rid of old handle first */
  676. if (conn->ci->tcpcl) {
  677. destroy_auth(conn->ci->tcpcl);
  678. clnt_destroy(conn->ci->tcpcl);
  679. tcp_count--;
  680. conn->ci->tcpcl = NULL;
  681. }
  682. if (conn->use == udp_transport) {
  683. return(conn->ci);
  684. } else {
  685. /* get a tcp client handle */
  686. oldver = conn->ci->vers_out;
  687. #if defined(SunOS)
  688. cl = clnt_create_vers(conn->ci->host, TABLEPROG,
  689. &(conn->ci->vers_out), TABLEVERS_2, oldver, "tcp");
  690. if (cl == NULL)
  691. _DtCm_print_errmsg(clnt_spcreateerror(conn->ci->host));
  692. #else
  693. (void) get_client_handle(conn->ci->host, (u_int)TABLEPROG,
  694. &(conn->ci->vers_out), TABLEVERS_2, oldver, "tcp",
  695. &cl);
  696. #endif
  697. if (cl == NULL) {
  698. conn->ci->vers_out = oldver;
  699. return(NULL);
  700. } else {
  701. create_auth(cl);
  702. /* adjust timeout */
  703. timeout_tv.tv_sec = _DtCM_INITIAL_TIMEOUT;
  704. timeout_tv.tv_usec = 0;
  705. clnt_control(cl, CLSET_TIMEOUT, (char *)&timeout_tv);
  706. conn->ci->tcpcl = cl;
  707. tcp_count++;
  708. return(conn->ci);
  709. }
  710. }
  711. }
  712. /*
  713. * Get a client handle to a server that supports the highest
  714. * version between the given range.
  715. */
  716. static CSA_return_code
  717. get_client_handle(
  718. const char *host,
  719. const u_long prognum,
  720. u_long *vers_outp,
  721. const u_long vers_low,
  722. const u_long vers_high,
  723. char *nettype,
  724. CLIENT **clnt)
  725. {
  726. CLIENT *cl;
  727. u_int vers;
  728. struct timeval tv;
  729. enum clnt_stat status;
  730. #ifdef HPUX
  731. static int bumped = 0;
  732. struct rlimit rl;
  733. if (bumped == 0) {
  734. bumped = 1;
  735. /* raise the soft limit of number of file descriptor */
  736. getrlimit(RLIMIT_NOFILE, &rl);
  737. rl.rlim_cur = rl.rlim_max;
  738. setrlimit(RLIMIT_NOFILE, &rl);
  739. }
  740. #endif
  741. tv.tv_sec = 1;
  742. tv.tv_usec = 0;
  743. *clnt = NULL;
  744. for (vers = vers_high; vers >= vers_low; vers--) {
  745. #if defined(__hpux)
  746. if ((cl = clnt_create((char *)host, prognum, vers, nettype)) != NULL) {
  747. #else
  748. if ((cl = clnt_create(host, prognum, vers, nettype)) != NULL) {
  749. #endif
  750. clnt_control(cl, CLSET_TIMEOUT, (char *)&tv);
  751. status = clnt_call(cl, 0, (xdrproc_t) xdr_void,
  752. (char *)NULL, (xdrproc_t) xdr_void,
  753. (char *)NULL, tv);
  754. if (status == RPC_SUCCESS) {
  755. *vers_outp = vers;
  756. *clnt = cl;
  757. return (CSA_SUCCESS);
  758. } else if (status != RPC_PROGVERSMISMATCH) {
  759. return (_DtCm_clntstat_to_csastat(status));
  760. }
  761. } else {
  762. _DtCm_print_errmsg(clnt_spcreateerror((char *) host));
  763. return (_DtCm_clntstat_to_csastat(rpc_createerr.cf_stat));
  764. }
  765. }
  766. /* cannot find a server that supports a version in the given range */
  767. /* Probably will never get here */
  768. return (CSA_E_SERVICE_UNAVAILABLE);
  769. }
  770. static CSA_return_code
  771. regstat4_to_dtcmstatus(Registration_Status_4 stat4)
  772. {
  773. switch (stat4) {
  774. case registered_4:
  775. return (CSA_SUCCESS);
  776. case deregistered_4:
  777. return (CSA_SUCCESS);
  778. case reg_notable_4:
  779. return (CSA_E_CALENDAR_NOT_EXIST);
  780. case failed_4:
  781. case confused_4:
  782. return (CSA_E_FAILURE);
  783. }
  784. }