1
0

xmlrpc_curl_transport.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. /*=============================================================================
  2. xmlrpc_curl_transport
  3. ===============================================================================
  4. Curl-based client transport for Xmlrpc-c
  5. By Bryan Henderson 04.12.10.
  6. Contributed to the public domain by its author.
  7. =============================================================================*/
  8. #include "xmlrpc_config.h"
  9. #include "bool.h"
  10. #include "mallocvar.h"
  11. #include "linklist.h"
  12. #include "casprintf.h"
  13. #include "xmlrpc.h"
  14. #include "xmlrpc_int.h"
  15. #include "xmlrpc_client.h"
  16. #include "xmlrpc_client_int.h"
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <errno.h>
  20. #if defined(HAVE_PTHREADS)
  21. # include "xmlrpc_pthreads.h"
  22. #endif
  23. #include <cmcurl/curl/curl.h>
  24. #include <cmcurl/curl/types.h>
  25. #include <cmcurl/curl/easy.h>
  26. #ifndef WIN32
  27. # include <unistd.h>
  28. #endif
  29. #if defined (WIN32) && defined(_DEBUG)
  30. # include <crtdbg.h>
  31. # define new DEBUG_NEW
  32. # define malloc(size) _malloc_dbg( size, _NORMAL_BLOCK, __FILE__, __LINE__)
  33. # undef THIS_FILE
  34. static char THIS_FILE[] = __FILE__;
  35. #endif /*WIN32 && _DEBUG*/
  36. struct clientTransport {
  37. #if defined (HAVE_PTHREADS)
  38. pthread_mutex_t listLock;
  39. #endif
  40. struct list_head rpcList;
  41. /* List of all RPCs that exist for this transport. An RPC exists
  42. from the time the user requests it until the time the user
  43. acknowledges it is done.
  44. */
  45. };
  46. typedef struct {
  47. /* This is all stuff that really ought to be in the CURL object,
  48. but the Curl library is a little too simple for that. So we
  49. build a layer on top of it, and call it a "transaction," as
  50. distinct from the Curl "session" represented by the CURL object.
  51. */
  52. CURL * curlSessionP;
  53. /* Handle for Curl library session object */
  54. char curlError[CURL_ERROR_SIZE];
  55. /* Error message from Curl */
  56. struct curl_slist * headerList;
  57. /* The HTTP headers for the transaction */
  58. const char * serverUrl; /* malloc'ed - belongs to this object */
  59. } curlTransaction;
  60. typedef struct {
  61. struct list_head link; /* link in transport's list of RPCs */
  62. curlTransaction * curlTransactionP;
  63. /* The object which does the HTTP transaction, with no knowledge
  64. of XML-RPC or Xmlrpc-c.
  65. */
  66. xmlrpc_mem_block * responseXmlP;
  67. xmlrpc_bool threadExists;
  68. #if defined(HAVE_PTHREADS)
  69. pthread_t thread;
  70. #endif
  71. transport_asynch_complete complete;
  72. /* Routine to call to complete the RPC after it is complete HTTP-wise.
  73. NULL if none.
  74. */
  75. struct call_info * callInfoP;
  76. /* User's identifier for this RPC */
  77. } rpc;
  78. static size_t
  79. collect(void * const ptr,
  80. size_t const size,
  81. size_t const nmemb,
  82. FILE * const stream) {
  83. /*----------------------------------------------------------------------------
  84. This is a Curl output function. Curl calls this to deliver the
  85. HTTP response body. Curl thinks it's writing to a POSIX stream.
  86. -----------------------------------------------------------------------------*/
  87. xmlrpc_mem_block * const responseXmlP = (xmlrpc_mem_block *) stream;
  88. char * const buffer = ptr;
  89. size_t const length = nmemb * size;
  90. size_t retval;
  91. xmlrpc_env env;
  92. xmlrpc_env_init(&env);
  93. xmlrpc_mem_block_append(&env, responseXmlP, buffer, length);
  94. if (env.fault_occurred)
  95. retval = (size_t)-1;
  96. else
  97. /* Really? Shouldn't it be like fread() and return 'nmemb'? */
  98. retval = length;
  99. return retval;
  100. }
  101. static void
  102. initWindowsStuff(xmlrpc_env * const envP) {
  103. #if defined (WIN32)
  104. /* This is CRITICAL so that cURL-Win32 works properly! */
  105. WORD wVersionRequested;
  106. WSADATA wsaData;
  107. int err;
  108. wVersionRequested = MAKEWORD(1, 1);
  109. err = WSAStartup(wVersionRequested, &wsaData);
  110. (void)err;
  111. if (LOBYTE(wsaData.wVersion) != 1 ||
  112. HIBYTE( wsaData.wVersion) != 1) {
  113. /* Tell the user that we couldn't find a useable */
  114. /* winsock.dll. */
  115. WSACleanup();
  116. xmlrpc_env_set_fault_formatted(
  117. envP, XMLRPC_INTERNAL_ERROR, "Winsock reported that "
  118. "it does not implement the requested version 1.1.");
  119. }
  120. #else
  121. if (0)
  122. envP->fault_occurred = TRUE; /* Avoid unused parm warning */
  123. #endif
  124. }
  125. static void
  126. create(xmlrpc_env * const envP,
  127. int const flags ATTR_UNUSED,
  128. const char * const appname ATTR_UNUSED,
  129. const char * const appversion ATTR_UNUSED,
  130. struct clientTransport ** const handlePP) {
  131. /*----------------------------------------------------------------------------
  132. This does the 'create' operation for a Curl client transport.
  133. -----------------------------------------------------------------------------*/
  134. struct clientTransport * transportP;
  135. initWindowsStuff(envP);
  136. MALLOCVAR(transportP);
  137. if (transportP == NULL)
  138. xmlrpc_env_set_fault_formatted(
  139. envP, XMLRPC_INTERNAL_ERROR,
  140. "Unable to allocate transport descriptor.");
  141. else {
  142. #ifdef HAVE_PTHREADS
  143. pthread_mutex_init(&transportP->listLock, NULL);
  144. #endif
  145. list_make_empty(&transportP->rpcList);
  146. /*
  147. * This is the main global constructor for the app. Call this before
  148. * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
  149. * used, or havoc may be the result.
  150. */
  151. curl_global_init(CURL_GLOBAL_ALL);
  152. /* The above makes it look like Curl is not re-entrant. We should
  153. check into that.
  154. */
  155. *handlePP = transportP;
  156. }
  157. }
  158. static void
  159. termWindowStuff(void) {
  160. #if defined (WIN32)
  161. WSACleanup();
  162. #endif
  163. }
  164. static void
  165. destroy(struct clientTransport * const clientTransportP) {
  166. /*----------------------------------------------------------------------------
  167. This does the 'destroy' operation for a Libwww client transport.
  168. -----------------------------------------------------------------------------*/
  169. XMLRPC_ASSERT(clientTransportP != NULL);
  170. XMLRPC_ASSERT(list_is_empty(&clientTransportP->rpcList));
  171. #if defined(HAVE_PTHREADS)
  172. pthread_mutex_destroy(&clientTransportP->listLock);
  173. #endif
  174. curl_global_cleanup();
  175. termWindowStuff();
  176. free(clientTransportP);
  177. }
  178. static void
  179. createCurlHeaderList(xmlrpc_env * const envP,
  180. xmlrpc_server_info * const serverP,
  181. struct curl_slist ** const headerListP) {
  182. struct curl_slist * headerList;
  183. headerList = NULL; /* initial value */
  184. headerList = curl_slist_append(headerList, "Content-Type: text/xml");
  185. if (headerList == NULL)
  186. xmlrpc_env_set_fault_formatted(
  187. envP, XMLRPC_INTERNAL_ERROR,
  188. "Could not add header. curl_slist_append() failed.");
  189. else {
  190. /* Send an authorization header if we need one. */
  191. if (serverP->_http_basic_auth) {
  192. /* Make the authentication header "Authorization: " */
  193. /* we need 15 + length of _http_basic_auth + 1 for null */
  194. char * const authHeader =
  195. malloc(strlen(serverP->_http_basic_auth) + 15 + 1);
  196. if (authHeader == NULL)
  197. xmlrpc_env_set_fault_formatted(
  198. envP, XMLRPC_INTERNAL_ERROR,
  199. "Couldn't allocate memory for authentication header");
  200. else {
  201. memcpy(authHeader,"Authorization: ", 15);
  202. memcpy(authHeader + 15, serverP->_http_basic_auth,
  203. strlen(serverP->_http_basic_auth) + 1);
  204. headerList = curl_slist_append(headerList, authHeader);
  205. if (headerList == NULL)
  206. xmlrpc_env_set_fault_formatted(
  207. envP, XMLRPC_INTERNAL_ERROR,
  208. "Could not add authentication header. "
  209. "curl_slist_append() failed.");
  210. free(authHeader);
  211. }
  212. }
  213. if (envP->fault_occurred)
  214. free(headerList);
  215. }
  216. *headerListP = headerList;
  217. }
  218. static void
  219. setupCurlSession(xmlrpc_env * const envP,
  220. CURL * const curlSessionP,
  221. curlTransaction * const curlTransactionP,
  222. xmlrpc_mem_block * const callXmlP,
  223. xmlrpc_mem_block * const responseXmlP) {
  224. static char proxy[1024];
  225. static char proxyUser[1024];
  226. int proxy_type = 0;
  227. if ( getenv("HTTP_PROXY") )
  228. {
  229. proxy_type = 1;
  230. if (getenv("HTTP_PROXY_PORT") )
  231. {
  232. sprintf(proxy, "%s:%s", getenv("HTTP_PROXY"), getenv("HTTP_PROXY_PORT"));
  233. }
  234. else
  235. {
  236. sprintf(proxy, "%s", getenv("HTTP_PROXY"));
  237. }
  238. if ( getenv("HTTP_PROXY_TYPE") )
  239. {
  240. /* HTTP/SOCKS4/SOCKS5 */
  241. if ( strcmp(getenv("HTTP_PROXY_TYPE"), "HTTP") == 0 )
  242. {
  243. proxy_type = 1;
  244. }
  245. else if ( strcmp(getenv("HTTP_PROXY_TYPE"), "SOCKS4") == 0 )
  246. {
  247. proxy_type = 2;
  248. }
  249. else if ( strcmp(getenv("HTTP_PROXY_TYPE"), "SOCKS5") == 0 )
  250. {
  251. proxy_type = 3;
  252. }
  253. }
  254. if ( getenv("HTTP_PROXY_USER") )
  255. {
  256. strcpy(proxyUser, getenv("HTTP_PROXY_USER"));
  257. }
  258. if ( getenv("HTTP_PROXY_PASSWD") )
  259. {
  260. strcat(proxyUser, ":");
  261. strcat(proxyUser, getenv("HTTP_PROXY_PASSWD"));
  262. }
  263. }
  264. /* Using proxy */
  265. if ( proxy_type > 0 )
  266. {
  267. curl_easy_setopt(curlSessionP, CURLOPT_PROXY, proxy);
  268. switch (proxy_type)
  269. {
  270. case 2:
  271. curl_easy_setopt(curlSessionP, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
  272. break;
  273. case 3:
  274. curl_easy_setopt(curlSessionP, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
  275. break;
  276. default:
  277. curl_easy_setopt(curlSessionP, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
  278. if (*proxyUser)
  279. {
  280. curl_easy_setopt(curlSessionP, CURLOPT_PROXYUSERPWD, proxyUser);
  281. }
  282. }
  283. }
  284. curl_easy_setopt(curlSessionP, CURLOPT_POST, 1 );
  285. curl_easy_setopt(curlSessionP, CURLOPT_URL, curlTransactionP->serverUrl);
  286. XMLRPC_MEMBLOCK_APPEND(char, envP, callXmlP, "\0", 1);
  287. if (!envP->fault_occurred) {
  288. curl_easy_setopt(curlSessionP, CURLOPT_POSTFIELDS,
  289. XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP));
  290. curl_easy_setopt(curlSessionP, CURLOPT_FILE, responseXmlP);
  291. curl_easy_setopt(curlSessionP, CURLOPT_HEADER, 0 );
  292. curl_easy_setopt(curlSessionP, CURLOPT_WRITEFUNCTION, collect);
  293. curl_easy_setopt(curlSessionP, CURLOPT_ERRORBUFFER,
  294. curlTransactionP->curlError);
  295. curl_easy_setopt(curlSessionP, CURLOPT_NOPROGRESS, 1);
  296. curl_easy_setopt(curlSessionP, CURLOPT_HTTPHEADER,
  297. curlTransactionP->headerList);
  298. }
  299. }
  300. static void
  301. createCurlTransaction(xmlrpc_env * const envP,
  302. xmlrpc_server_info * const serverP,
  303. xmlrpc_mem_block * const callXmlP,
  304. xmlrpc_mem_block * const responseXmlP,
  305. curlTransaction ** const curlTransactionPP) {
  306. curlTransaction * curlTransactionP;
  307. MALLOCVAR(curlTransactionP);
  308. if (curlTransactionP == NULL)
  309. xmlrpc_env_set_fault_formatted(
  310. envP, XMLRPC_INTERNAL_ERROR,
  311. "No memory to create Curl transaction.");
  312. else {
  313. CURL * const curlSessionP = curl_easy_init();
  314. if (curlSessionP == NULL)
  315. xmlrpc_env_set_fault_formatted(
  316. envP, XMLRPC_INTERNAL_ERROR,
  317. "Could not create Curl session. curl_easy_init() failed.");
  318. else {
  319. curlTransactionP->curlSessionP = curlSessionP;
  320. curlTransactionP->serverUrl = strdup(serverP->_server_url);
  321. if (curlTransactionP->serverUrl == NULL)
  322. xmlrpc_env_set_fault_formatted(
  323. envP, XMLRPC_INTERNAL_ERROR,
  324. "Out of memory to store server URL.");
  325. else {
  326. createCurlHeaderList(envP, serverP,
  327. &curlTransactionP->headerList);
  328. if (!envP->fault_occurred)
  329. setupCurlSession(envP, curlSessionP, curlTransactionP,
  330. callXmlP, responseXmlP);
  331. if (envP->fault_occurred)
  332. strfree(curlTransactionP->serverUrl);
  333. }
  334. if (envP->fault_occurred)
  335. curl_easy_cleanup(curlSessionP);
  336. }
  337. if (envP->fault_occurred)
  338. free(curlTransactionP);
  339. }
  340. *curlTransactionPP = curlTransactionP;
  341. }
  342. static void
  343. destroyCurlTransaction(curlTransaction * const curlTransactionP) {
  344. curl_slist_free_all(curlTransactionP->headerList);
  345. strfree(curlTransactionP->serverUrl);
  346. curl_easy_cleanup(curlTransactionP->curlSessionP);
  347. free(curlTransactionP);
  348. }
  349. static void
  350. performCurlTransaction(xmlrpc_env * const envP,
  351. curlTransaction * const curlTransactionP) {
  352. CURL * const curlSessionP = curlTransactionP->curlSessionP;
  353. CURLcode res;
  354. res = curl_easy_perform(curlSessionP);
  355. if (res != CURLE_OK)
  356. xmlrpc_env_set_fault_formatted(
  357. envP, XMLRPC_NETWORK_ERROR, "Curl failed to perform "
  358. "HTTP POST request. curl_easy_perform() says: %s (%d)",
  359. curlTransactionP->curlError, res);
  360. else {
  361. CURLcode crRes;
  362. long http_result;
  363. crRes = curl_easy_getinfo(curlSessionP, CURLINFO_HTTP_CODE,
  364. &http_result);
  365. if (crRes != CURLE_OK)
  366. xmlrpc_env_set_fault_formatted(
  367. envP, XMLRPC_INTERNAL_ERROR,
  368. "Curl performed the HTTP POST request, but was "
  369. "unable to say what the HTTP result code was. "
  370. "curl_easy_getinfo(CURLINFO_HTTP_CODE) says: %s",
  371. curlTransactionP->curlError);
  372. else {
  373. if (http_result != 200)
  374. xmlrpc_env_set_fault_formatted(
  375. envP, XMLRPC_NETWORK_ERROR, "HTTP response: %ld",
  376. http_result);
  377. }
  378. }
  379. }
  380. #if defined(HAVE_PTHREADS)
  381. static void
  382. doAsyncRpc2(void * const arg) {
  383. rpc * const rpcP = arg;
  384. xmlrpc_env env;
  385. xmlrpc_env_init(&env);
  386. performCurlTransaction(&env, rpcP->curlTransactionP);
  387. rpcP->complete(rpcP->callInfoP, rpcP->responseXmlP, env);
  388. xmlrpc_env_clean(&env);
  389. }
  390. #ifdef WIN32
  391. static unsigned __stdcall
  392. doAsyncRpc(void * arg) {
  393. doAsyncRpc2(arg);
  394. return 0;
  395. }
  396. #else
  397. static void *
  398. doAsyncRpc(void * arg) {
  399. doAsyncRpc2(arg);
  400. return NULL;
  401. }
  402. #endif
  403. static void
  404. createRpcThread(xmlrpc_env * const envP,
  405. rpc * const rpcP,
  406. pthread_t * const threadP) {
  407. int rc;
  408. rc = pthread_create(threadP, NULL, doAsyncRpc, rpcP);
  409. switch (rc) {
  410. case 0:
  411. break;
  412. case EAGAIN:
  413. xmlrpc_env_set_fault_formatted(
  414. envP, XMLRPC_INTERNAL_ERROR,
  415. "pthread_create() failed: System Resources exceeded.");
  416. break;
  417. case EINVAL:
  418. xmlrpc_env_set_fault_formatted(
  419. envP, XMLRPC_INTERNAL_ERROR,
  420. "pthread_create() failed: Param Error for attr.");
  421. break;
  422. case ENOMEM:
  423. xmlrpc_env_set_fault_formatted(
  424. envP, XMLRPC_INTERNAL_ERROR,
  425. "pthread_create() failed: No memory for new thread.");
  426. break;
  427. default:
  428. xmlrpc_env_set_fault_formatted(
  429. envP, XMLRPC_INTERNAL_ERROR,
  430. "pthread_create() failed: Unrecognized error code %d.", rc);
  431. break;
  432. }
  433. }
  434. #endif
  435. static void
  436. rpcCreate(xmlrpc_env * const envP,
  437. struct clientTransport * const clientTransportP,
  438. xmlrpc_server_info * const serverP,
  439. xmlrpc_mem_block * const callXmlP,
  440. xmlrpc_mem_block * const responseXmlP,
  441. transport_asynch_complete complete,
  442. struct call_info * const callInfoP,
  443. rpc ** const rpcPP) {
  444. rpc * rpcP;
  445. MALLOCVAR(rpcP);
  446. if (rpcP == NULL)
  447. xmlrpc_env_set_fault_formatted(
  448. envP, XMLRPC_INTERNAL_ERROR,
  449. "Couldn't allocate memory for rpc object");
  450. else {
  451. rpcP->callInfoP = callInfoP;
  452. rpcP->complete = complete;
  453. rpcP->responseXmlP = responseXmlP;
  454. rpcP->threadExists = FALSE;
  455. createCurlTransaction(envP, serverP,
  456. callXmlP, responseXmlP,
  457. &rpcP->curlTransactionP);
  458. if (!envP->fault_occurred) {
  459. if (complete) {
  460. #if defined(HAVE_PTHREADS)
  461. createRpcThread(envP, rpcP, &rpcP->thread);
  462. #else
  463. abort();
  464. #endif
  465. if (!envP->fault_occurred)
  466. rpcP->threadExists = TRUE;
  467. }
  468. if (!envP->fault_occurred) {
  469. list_init_header(&rpcP->link, rpcP);
  470. #if defined(HAVE_PTHREADS)
  471. pthread_mutex_lock(&clientTransportP->listLock);
  472. #endif
  473. list_add_head(&clientTransportP->rpcList, &rpcP->link);
  474. #if defined(HAVE_PTHREADS)
  475. pthread_mutex_unlock(&clientTransportP->listLock);
  476. #endif
  477. }
  478. if (envP->fault_occurred)
  479. destroyCurlTransaction(rpcP->curlTransactionP);
  480. }
  481. if (envP->fault_occurred)
  482. free(rpcP);
  483. }
  484. *rpcPP = rpcP;
  485. }
  486. static void
  487. rpcDestroy(rpc * const rpcP) {
  488. XMLRPC_ASSERT_PTR_OK(rpcP);
  489. XMLRPC_ASSERT(!rpcP->threadExists);
  490. destroyCurlTransaction(rpcP->curlTransactionP);
  491. list_remove(&rpcP->link);
  492. free(rpcP);
  493. }
  494. static void
  495. sendRequest(xmlrpc_env * const envP,
  496. struct clientTransport * const clientTransportP,
  497. xmlrpc_server_info * const serverP,
  498. xmlrpc_mem_block * const callXmlP,
  499. transport_asynch_complete complete,
  500. struct call_info * const callInfoP) {
  501. /*----------------------------------------------------------------------------
  502. Initiate an XML-RPC rpc asynchronously. Don't wait for it to go to
  503. the server.
  504. Unless we return failure, we arrange to have complete() called when
  505. the rpc completes.
  506. This does the 'send_request' operation for a Curl client transport.
  507. -----------------------------------------------------------------------------*/
  508. rpc * rpcP;
  509. xmlrpc_mem_block * responseXmlP;
  510. responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
  511. if (!envP->fault_occurred) {
  512. rpcCreate(envP, clientTransportP, serverP, callXmlP, responseXmlP,
  513. complete, callInfoP,
  514. &rpcP);
  515. if (envP->fault_occurred)
  516. XMLRPC_MEMBLOCK_FREE(char, responseXmlP);
  517. }
  518. /* The user's eventual finish_asynch call will destroy this RPC
  519. and response buffer
  520. */
  521. }
  522. static void *
  523. finishRpc(struct list_head * const headerP,
  524. void * const context ATTR_UNUSED) {
  525. rpc * const rpcP = headerP->itemP;
  526. if (rpcP->threadExists) {
  527. #if defined(HAVE_PTHREADS)
  528. void *status;
  529. int result;
  530. result = pthread_join(rpcP->thread, &status);
  531. (void)result;
  532. #else
  533. abort();
  534. #endif
  535. rpcP->threadExists = FALSE;
  536. }
  537. XMLRPC_MEMBLOCK_FREE(char, rpcP->responseXmlP);
  538. rpcDestroy(rpcP);
  539. return NULL;
  540. }
  541. static void
  542. finishAsynch(struct clientTransport * const clientTransportP ATTR_UNUSED,
  543. enum timeoutType const timeoutType ATTR_UNUSED,
  544. timeout_t const timeout ATTR_UNUSED) {
  545. /*----------------------------------------------------------------------------
  546. Wait for the threads of all outstanding RPCs to exit and destroy those
  547. RPCs.
  548. This does the 'finish_asynch' operation for a Curl client transport.
  549. -----------------------------------------------------------------------------*/
  550. /* We ignore any timeout request. Some day, we should figure out how
  551. to set an alarm and interrupt running threads.
  552. */
  553. #if defined(HAVE_PTHREADS)
  554. pthread_mutex_lock(&clientTransportP->listLock);
  555. #else
  556. abort();
  557. #endif
  558. list_foreach(&clientTransportP->rpcList, finishRpc, NULL);
  559. #if defined(HAVE_PTHREADS)
  560. pthread_mutex_unlock(&clientTransportP->listLock);
  561. #else
  562. abort();
  563. #endif
  564. }
  565. static void
  566. call(xmlrpc_env * const envP,
  567. struct clientTransport * const clientTransportP,
  568. xmlrpc_server_info * const serverP,
  569. xmlrpc_mem_block * const callXmlP,
  570. struct call_info * const callInfoP,
  571. xmlrpc_mem_block ** const responsePP) {
  572. xmlrpc_mem_block * responseXmlP;
  573. rpc * rpcP;
  574. XMLRPC_ASSERT_ENV_OK(envP);
  575. XMLRPC_ASSERT_PTR_OK(serverP);
  576. XMLRPC_ASSERT_PTR_OK(callXmlP);
  577. XMLRPC_ASSERT_PTR_OK(callInfoP);
  578. XMLRPC_ASSERT_PTR_OK(responsePP);
  579. responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
  580. if (!envP->fault_occurred) {
  581. rpcCreate(envP, clientTransportP, serverP, callXmlP, responseXmlP,
  582. NULL, NULL, &rpcP);
  583. if (!envP->fault_occurred) {
  584. performCurlTransaction(envP, rpcP->curlTransactionP);
  585. *responsePP = responseXmlP;
  586. rpcDestroy(rpcP);
  587. }
  588. if (envP->fault_occurred)
  589. XMLRPC_MEMBLOCK_FREE(char, responseXmlP);
  590. }
  591. }
  592. struct clientTransportOps xmlrpc_curl_transport_ops = {
  593. &create,
  594. &destroy,
  595. &sendRequest,
  596. &call,
  597. &finishAsynch,
  598. };