diff options
Diffstat (limited to 'Utilities/cmxmlrpc/xmlrpc_curl_transport.c')
-rw-r--r-- | Utilities/cmxmlrpc/xmlrpc_curl_transport.c | 759 |
1 files changed, 0 insertions, 759 deletions
diff --git a/Utilities/cmxmlrpc/xmlrpc_curl_transport.c b/Utilities/cmxmlrpc/xmlrpc_curl_transport.c deleted file mode 100644 index 5726663..0000000 --- a/Utilities/cmxmlrpc/xmlrpc_curl_transport.c +++ /dev/null @@ -1,759 +0,0 @@ -/*============================================================================= - xmlrpc_curl_transport -=============================================================================== - Curl-based client transport for Xmlrpc-c - - By Bryan Henderson 04.12.10. - - Contributed to the public domain by its author. -=============================================================================*/ - -#include "xmlrpc_config.h" - -#if defined(__BEOS__) -/* Some helpful system header has char==bool, then bool.h does int==bool. */ -#define HAVE_BOOL 1 -#endif - -#include "bool.h" -#include "mallocvar.h" -#include "linklist.h" -#include "casprintf.h" -#include "xmlrpc.h" -#include "xmlrpc_int.h" -#include "xmlrpc_client.h" -#include "xmlrpc_client_int.h" - -#include <string.h> -#include <stdlib.h> -#include <errno.h> - -#if defined(HAVE_PTHREADS) -# include "xmlrpc_pthreads.h" -#endif - -#include <cmcurl/curl/curl.h> -#include <cmcurl/curl/types.h> -#include <cmcurl/curl/easy.h> - -#ifndef WIN32 -# include <unistd.h> -#endif - -#if defined (WIN32) && defined(_DEBUG) -# include <crtdbg.h> -# define new DEBUG_NEW -# define malloc(size) _malloc_dbg( size, _NORMAL_BLOCK, __FILE__, __LINE__) -# undef THIS_FILE - static char THIS_FILE[] = __FILE__; -#endif /*WIN32 && _DEBUG*/ - -static void xmlrpc_abort(void) -{ - abort(); -} - -struct clientTransport { -#if defined (HAVE_PTHREADS) - pthread_mutex_t listLock; -#endif - struct list_head rpcList; - /* List of all RPCs that exist for this transport. An RPC exists - from the time the user requests it until the time the user - acknowledges it is done. - */ -}; - -typedef struct { - /* This is all stuff that really ought to be in the CURL object, - but the Curl library is a little too simple for that. So we - build a layer on top of it, and call it a "transaction," as - distinct from the Curl "session" represented by the CURL object. - */ - CURL * curlSessionP; - /* Handle for Curl library session object */ - char curlError[CURL_ERROR_SIZE]; - /* Error message from Curl */ - struct curl_slist * headerList; - /* The HTTP headers for the transaction */ - const char * serverUrl; /* malloc'ed - belongs to this object */ -} curlTransaction; - - - -typedef struct { - struct list_head link; /* link in transport's list of RPCs */ - curlTransaction * curlTransactionP; - /* The object which does the HTTP transaction, with no knowledge - of XML-RPC or Xmlrpc-c. - */ - xmlrpc_mem_block * responseXmlP; - xmlrpc_bool threadExists; -#if defined(HAVE_PTHREADS) - pthread_t thread; -#endif - transport_asynch_complete complete; - /* Routine to call to complete the RPC after it is complete HTTP-wise. - NULL if none. - */ - struct call_info * callInfoP; - /* User's identifier for this RPC */ -} rpc; - - - -static size_t -collect(void * const ptr, - size_t const size, - size_t const nmemb, - FILE * const stream) { -/*---------------------------------------------------------------------------- - This is a Curl output function. Curl calls this to deliver the - HTTP response body. Curl thinks it's writing to a POSIX stream. ------------------------------------------------------------------------------*/ - xmlrpc_mem_block * const responseXmlP = (xmlrpc_mem_block *) stream; - char * const buffer = ptr; - size_t const length = nmemb * size; - - size_t retval; - xmlrpc_env env; - - xmlrpc_env_init(&env); - xmlrpc_mem_block_append(&env, responseXmlP, buffer, length); - if (env.fault_occurred) - retval = (size_t)-1; - else - /* Really? Shouldn't it be like fread() and return 'nmemb'? */ - retval = length; - - return retval; -} - - - -static void -initWindowsStuff(xmlrpc_env * const envP) { - -#if defined (WIN32) - /* This is CRITICAL so that cURL-Win32 works properly! */ - WORD wVersionRequested; - WSADATA wsaData; - int err; - wVersionRequested = MAKEWORD(1, 1); - - err = WSAStartup(wVersionRequested, &wsaData); - (void)err; - if (LOBYTE(wsaData.wVersion) != 1 || - HIBYTE( wsaData.wVersion) != 1) { - /* Tell the user that we couldn't find a useable */ - /* winsock.dll. */ - WSACleanup(); - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, "Winsock reported that " - "it does not implement the requested version 1.1."); - } -#else - if (0) - envP->fault_occurred = TRUE; /* Avoid unused parm warning */ -#endif -} - - -static void -create(xmlrpc_env * const envP, - int const flags ATTR_UNUSED, - const char * const appname ATTR_UNUSED, - const char * const appversion ATTR_UNUSED, - struct clientTransport ** const handlePP) { -/*---------------------------------------------------------------------------- - This does the 'create' operation for a Curl client transport. ------------------------------------------------------------------------------*/ - struct clientTransport * transportP; - - initWindowsStuff(envP); - - MALLOCVAR(transportP); - if (transportP == NULL) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "Unable to allocate transport descriptor."); - else { -#ifdef HAVE_PTHREADS - pthread_mutex_init(&transportP->listLock, NULL); -#endif - - list_make_empty(&transportP->rpcList); - - /* - * This is the main global constructor for the app. Call this before - * _any_ libcurl usage. If this fails, *NO* libcurl functions may be - * used, or havoc may be the result. - */ - curl_global_init(CURL_GLOBAL_ALL); - - /* The above makes it look like Curl is not re-entrant. We should - check into that. - */ - - *handlePP = transportP; - } -} - - -static void -termWindowStuff(void) { - -#if defined (WIN32) - WSACleanup(); -#endif -} - - - -static void -destroy(struct clientTransport * const clientTransportP) { -/*---------------------------------------------------------------------------- - This does the 'destroy' operation for a Libwww client transport. ------------------------------------------------------------------------------*/ - XMLRPC_ASSERT(clientTransportP != NULL); - - XMLRPC_ASSERT(list_is_empty(&clientTransportP->rpcList)); - -#if defined(HAVE_PTHREADS) - pthread_mutex_destroy(&clientTransportP->listLock); -#endif - - curl_global_cleanup(); - - termWindowStuff(); - - free(clientTransportP); -} - - - -static void -createCurlHeaderList(xmlrpc_env * const envP, - xmlrpc_server_info * const serverP, - struct curl_slist ** const headerListP) { - - struct curl_slist * headerList; - - headerList = NULL; /* initial value */ - - headerList = curl_slist_append(headerList, "Content-Type: text/xml"); - - if (headerList == NULL) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "Could not add header. curl_slist_append() failed."); - else { - /* Send an authorization header if we need one. */ - if (serverP->_http_basic_auth) { - /* Make the authentication header "Authorization: " */ - /* we need 15 + length of _http_basic_auth + 1 for null */ - - char * const authHeader = - malloc(strlen(serverP->_http_basic_auth) + 15 + 1); - - if (authHeader == NULL) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "Couldn't allocate memory for authentication header"); - else { - memcpy(authHeader,"Authorization: ", 15); - memcpy(authHeader + 15, serverP->_http_basic_auth, - strlen(serverP->_http_basic_auth) + 1); - - headerList = curl_slist_append(headerList, authHeader); - if (headerList == NULL) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "Could not add authentication header. " - "curl_slist_append() failed."); - free(authHeader); - } - } - if (envP->fault_occurred) - free(headerList); - } - *headerListP = headerList; -} - - - -static void -setupCurlSession(xmlrpc_env * const envP, - CURL * const curlSessionP, - curlTransaction * const curlTransactionP, - xmlrpc_mem_block * const callXmlP, - xmlrpc_mem_block * const responseXmlP) { - - static char proxy[1024]; - static char proxyUser[1024]; - int proxy_type = 0; - - if ( getenv("HTTP_PROXY") ) - { - proxy_type = 1; - if (getenv("HTTP_PROXY_PORT") ) - { - sprintf(proxy, "%s:%s", getenv("HTTP_PROXY"), getenv("HTTP_PROXY_PORT")); - } - else - { - sprintf(proxy, "%s", getenv("HTTP_PROXY")); - } - if ( getenv("HTTP_PROXY_TYPE") ) - { - /* HTTP/SOCKS4/SOCKS5 */ - if ( strcmp(getenv("HTTP_PROXY_TYPE"), "HTTP") == 0 ) - { - proxy_type = 1; - } - else if ( strcmp(getenv("HTTP_PROXY_TYPE"), "SOCKS4") == 0 ) - { - proxy_type = 2; - } - else if ( strcmp(getenv("HTTP_PROXY_TYPE"), "SOCKS5") == 0 ) - { - proxy_type = 3; - } - } - if ( getenv("HTTP_PROXY_USER") ) - { - strcpy(proxyUser, getenv("HTTP_PROXY_USER")); - } - if ( getenv("HTTP_PROXY_PASSWD") ) - { - strcat(proxyUser, ":"); - strcat(proxyUser, getenv("HTTP_PROXY_PASSWD")); - } - } - /* Using proxy */ - if ( proxy_type > 0 ) - { - curl_easy_setopt(curlSessionP, CURLOPT_PROXY, proxy); - switch (proxy_type) - { - case 2: - curl_easy_setopt(curlSessionP, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); - break; - case 3: - curl_easy_setopt(curlSessionP, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); - break; - default: - curl_easy_setopt(curlSessionP, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); - if (*proxyUser) - { - curl_easy_setopt(curlSessionP, CURLOPT_PROXYUSERPWD, proxyUser); - } - } - } - - curl_easy_setopt(curlSessionP, CURLOPT_POST, 1 ); - curl_easy_setopt(curlSessionP, CURLOPT_URL, curlTransactionP->serverUrl); - XMLRPC_MEMBLOCK_APPEND(char, envP, callXmlP, "\0", 1); - if (!envP->fault_occurred) { - curl_easy_setopt(curlSessionP, CURLOPT_POSTFIELDS, - XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP)); - - curl_easy_setopt(curlSessionP, CURLOPT_FILE, responseXmlP); - curl_easy_setopt(curlSessionP, CURLOPT_HEADER, 0 ); - curl_easy_setopt(curlSessionP, CURLOPT_WRITEFUNCTION, collect); - curl_easy_setopt(curlSessionP, CURLOPT_ERRORBUFFER, - curlTransactionP->curlError); - curl_easy_setopt(curlSessionP, CURLOPT_NOPROGRESS, 1); - - curl_easy_setopt(curlSessionP, CURLOPT_HTTPHEADER, - curlTransactionP->headerList); - } -} - - - -static void -createCurlTransaction(xmlrpc_env * const envP, - xmlrpc_server_info * const serverP, - xmlrpc_mem_block * const callXmlP, - xmlrpc_mem_block * const responseXmlP, - curlTransaction ** const curlTransactionPP) { - - curlTransaction * curlTransactionP; - - MALLOCVAR(curlTransactionP); - if (curlTransactionP == NULL) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "No memory to create Curl transaction."); - else { - CURL * const curlSessionP = curl_easy_init(); - - if (curlSessionP == NULL) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "Could not create Curl session. curl_easy_init() failed."); - else { - curlTransactionP->curlSessionP = curlSessionP; - - curlTransactionP->serverUrl = strdup(serverP->_server_url); - if (curlTransactionP->serverUrl == NULL) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "Out of memory to store server URL."); - else { - createCurlHeaderList(envP, serverP, - &curlTransactionP->headerList); - - if (!envP->fault_occurred) - setupCurlSession(envP, curlSessionP, curlTransactionP, - callXmlP, responseXmlP); - - if (envP->fault_occurred) - strfree(curlTransactionP->serverUrl); - } - if (envP->fault_occurred) - curl_easy_cleanup(curlSessionP); - } - if (envP->fault_occurred) - free(curlTransactionP); - } - *curlTransactionPP = curlTransactionP; -} - - - -static void -destroyCurlTransaction(curlTransaction * const curlTransactionP) { - - curl_slist_free_all(curlTransactionP->headerList); - strfree(curlTransactionP->serverUrl); - curl_easy_cleanup(curlTransactionP->curlSessionP); - free(curlTransactionP); -} - - -static void -performCurlTransaction(xmlrpc_env * const envP, - curlTransaction * const curlTransactionP) { - - CURL * const curlSessionP = curlTransactionP->curlSessionP; - - CURLcode res; - - res = curl_easy_perform(curlSessionP); - - if (res != CURLE_OK) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_NETWORK_ERROR, "Curl failed to perform " - "HTTP POST request. curl_easy_perform() says: %s (%d)", - curlTransactionP->curlError, res); - else { - CURLcode crRes; - long http_result; - crRes = curl_easy_getinfo(curlSessionP, CURLINFO_HTTP_CODE, - &http_result); - - if (crRes != CURLE_OK) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "Curl performed the HTTP POST request, but was " - "unable to say what the HTTP result code was. " - "curl_easy_getinfo(CURLINFO_HTTP_CODE) says: %s", - curlTransactionP->curlError); - else { - if (http_result != 200) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_NETWORK_ERROR, "HTTP response: %ld", - http_result); - } - } -} - - -#if defined(HAVE_PTHREADS) - -static void -doAsyncRpc2(void * const arg) { - - rpc * const rpcP = arg; - - xmlrpc_env env; - - xmlrpc_env_init(&env); - - performCurlTransaction(&env, rpcP->curlTransactionP); - - rpcP->complete(rpcP->callInfoP, rpcP->responseXmlP, env); - - xmlrpc_env_clean(&env); -} - - - -#ifdef WIN32 - -static unsigned __stdcall -doAsyncRpc(void * arg) { - doAsyncRpc2(arg); - return 0; -} - -#else - -static void * -doAsyncRpc(void * arg) { - doAsyncRpc2(arg); - return NULL; -} - -#endif - - -static void -createRpcThread(xmlrpc_env * const envP, - rpc * const rpcP, - pthread_t * const threadP) { - - int rc; - - rc = pthread_create(threadP, NULL, doAsyncRpc, rpcP); - switch (rc) { - case 0: - break; - case EAGAIN: - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "pthread_create() failed: System Resources exceeded."); - break; - case EINVAL: - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "pthread_create() failed: Param Error for attr."); - break; - case ENOMEM: - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "pthread_create() failed: No memory for new thread."); - break; - default: - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "pthread_create() failed: Unrecognized error code %d.", rc); - break; - } -} -#endif - - - -static void -rpcCreate(xmlrpc_env * const envP, - struct clientTransport * const clientTransportP, - xmlrpc_server_info * const serverP, - xmlrpc_mem_block * const callXmlP, - xmlrpc_mem_block * const responseXmlP, - transport_asynch_complete complete, - struct call_info * const callInfoP, - rpc ** const rpcPP) { - - rpc * rpcP; - - MALLOCVAR(rpcP); - if (rpcP == NULL) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_INTERNAL_ERROR, - "Couldn't allocate memory for rpc object"); - else { - rpcP->callInfoP = callInfoP; - rpcP->complete = complete; - rpcP->responseXmlP = responseXmlP; - rpcP->threadExists = FALSE; - - createCurlTransaction(envP, serverP, - callXmlP, responseXmlP, - &rpcP->curlTransactionP); - if (!envP->fault_occurred) { - if (complete) { -#if defined(HAVE_PTHREADS) - createRpcThread(envP, rpcP, &rpcP->thread); -#else - xmlrpc_abort(); -#endif - if (!envP->fault_occurred) - rpcP->threadExists = TRUE; - } - if (!envP->fault_occurred) { - list_init_header(&rpcP->link, rpcP); -#if defined(HAVE_PTHREADS) - pthread_mutex_lock(&clientTransportP->listLock); -#endif - list_add_head(&clientTransportP->rpcList, &rpcP->link); -#if defined(HAVE_PTHREADS) - pthread_mutex_unlock(&clientTransportP->listLock); -#endif - } - if (envP->fault_occurred) - destroyCurlTransaction(rpcP->curlTransactionP); - } - if (envP->fault_occurred) - { - free(rpcP); - rpcP = 0; /* set this to null as it is used later on */ - } - } - *rpcPP = rpcP; -} - - -static void -rpcDestroy(rpc * const rpcP) { - - XMLRPC_ASSERT_PTR_OK(rpcP); - XMLRPC_ASSERT(!rpcP->threadExists); - - destroyCurlTransaction(rpcP->curlTransactionP); - - list_remove(&rpcP->link); - - free(rpcP); -} - - -static void -sendRequest(xmlrpc_env * const envP, - struct clientTransport * const clientTransportP, - xmlrpc_server_info * const serverP, - xmlrpc_mem_block * const callXmlP, - transport_asynch_complete complete, - struct call_info * const callInfoP) { -/*---------------------------------------------------------------------------- - Initiate an XML-RPC rpc asynchronously. Don't wait for it to go to - the server. - - Unless we return failure, we arrange to have complete() called when - the rpc completes. - - This does the 'send_request' operation for a Curl client transport. ------------------------------------------------------------------------------*/ - rpc * rpcP; - xmlrpc_mem_block * responseXmlP; - - responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); - if (!envP->fault_occurred) { - rpcCreate(envP, clientTransportP, serverP, callXmlP, responseXmlP, - complete, callInfoP, - &rpcP); - - if (envP->fault_occurred) - XMLRPC_MEMBLOCK_FREE(char, responseXmlP); - } - /* The user's eventual finish_asynch call will destroy this RPC - and response buffer - */ -} - - - -static void * -finishRpc(struct list_head * const headerP, - void * const context ATTR_UNUSED) { - - rpc * const rpcP = headerP->itemP; - - if (rpcP->threadExists) { -#if defined(HAVE_PTHREADS) - void *status; - int result; - - result = pthread_join(rpcP->thread, &status); - (void)result; -#else - xmlrpc_abort(); -#endif - - rpcP->threadExists = FALSE; - } - - XMLRPC_MEMBLOCK_FREE(char, rpcP->responseXmlP); - - rpcDestroy(rpcP); - - return NULL; -} - - - -static void -finishAsynch(struct clientTransport * const clientTransportP ATTR_UNUSED, - enum timeoutType const timeoutType ATTR_UNUSED, - timeout_t const timeout ATTR_UNUSED) { -/*---------------------------------------------------------------------------- - Wait for the threads of all outstanding RPCs to exit and destroy those - RPCs. - - This does the 'finish_asynch' operation for a Curl client transport. ------------------------------------------------------------------------------*/ - /* We ignore any timeout request. Some day, we should figure out how - to set an alarm and interrupt running threads. - */ - -#if defined(HAVE_PTHREADS) - pthread_mutex_lock(&clientTransportP->listLock); -#else - xmlrpc_abort(); -#endif - - list_foreach(&clientTransportP->rpcList, finishRpc, NULL); - -#if defined(HAVE_PTHREADS) - pthread_mutex_unlock(&clientTransportP->listLock); -#else - xmlrpc_abort(); -#endif -} - - - -static void -call(xmlrpc_env * const envP, - struct clientTransport * const clientTransportP, - xmlrpc_server_info * const serverP, - xmlrpc_mem_block * const callXmlP, - struct call_info * const callInfoP, - xmlrpc_mem_block ** const responsePP) { - - xmlrpc_mem_block * responseXmlP; - rpc * rpcP; - - XMLRPC_ASSERT_ENV_OK(envP); - XMLRPC_ASSERT_PTR_OK(serverP); - XMLRPC_ASSERT_PTR_OK(callXmlP); - XMLRPC_ASSERT_PTR_OK(callInfoP); - XMLRPC_ASSERT_PTR_OK(responsePP); - - responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); - if (!envP->fault_occurred) { - rpcCreate(envP, clientTransportP, serverP, callXmlP, responseXmlP, - NULL, NULL, &rpcP); - if (!envP->fault_occurred) { - performCurlTransaction(envP, rpcP->curlTransactionP); - - *responsePP = responseXmlP; - - rpcDestroy(rpcP); - } - if (envP->fault_occurred) - XMLRPC_MEMBLOCK_FREE(char, responseXmlP); - } -} - - - -struct clientTransportOps xmlrpc_curl_transport_ops = { - &create, - &destroy, - &sendRequest, - &call, - &finishAsynch, -}; |