123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977 |
- /*=============================================================================
- xmlrpc_wininet_transport
- ===============================================================================
- WinInet-based client transport for Xmlrpc-c. Copyright information at
- the bottom of this file.
-
- =============================================================================*/
- #include "xmlrpc_config.h"
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <stddef.h>
- #include <windows.h>
- #include <wininet.h>
- #include "bool.h"
- #include "mallocvar.h"
- #include "linklist.h"
- #include "casprintf.h"
- #include "pthreadx.h"
- #include "xmlrpc-c/base.h"
- #include "xmlrpc-c/base_int.h"
- #include "xmlrpc-c/client.h"
- #include "xmlrpc-c/client_int.h"
- #include "xmlrpc-c/transport.h"
- #if 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
- static HINTERNET hSyncInternetSession = NULL;
- /* Declare WinInet status callback. */
- void CALLBACK
- statusCallback(HINTERNET const hInternet,
- unsigned long const dwContext,
- unsigned long const dwInternetStatus,
- void * const lpvStatusInformation,
- unsigned long const dwStatusInformationLength);
- struct xmlrpc_client_transport {
- pthread_mutex_t listLock;
- 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.
- */
- int allowInvalidSSLCerts;
- /* Flag to specify if we ignore invalid SSL Certificates. If this
- is set to zero, calling a XMLRPC server with an invalid SSL
- certificate will fail. This is the default behavior of the other
- transports, but invalid certificates were allowed in pre 1.2
- wininet xmlrpc-c transports.
- */
- };
- typedef struct {
- unsigned long http_status;
- HINTERNET hHttpRequest;
- HINTERNET hURL;
- INTERNET_PORT nPort;
- char szHostName[255];
- char szUrlPath[255];
- BOOL bUseSSL;
- char * headerList;
- BYTE * pSendData;
- xmlrpc_mem_block * pResponseData;
- } winInetTransaction;
- typedef struct {
- struct list_head link; /* link in transport's list of RPCs */
- winInetTransaction * winInetTransactionP;
- /* The object which does the HTTP transaction, with no knowledge
- of XML-RPC or Xmlrpc-c.
- */
- xmlrpc_mem_block * responseXmlP;
- xmlrpc_bool threadExists;
- pthread_t thread;
- xmlrpc_transport_asynch_complete complete;
- /* Routine to call to complete the RPC after it is complete HTTP-wise.
- NULL if none.
- */
- struct xmlrpc_call_info * callInfoP;
- /* User's identifier for this RPC */
- struct xmlrpc_client_transport * clientTransportP;
- } rpc;
- static void
- createWinInetHeaderList(xmlrpc_env * const envP,
- const xmlrpc_server_info * const serverP,
- char ** const headerListP) {
- const char * const szContentType = "Content-Type: text/xml\r\n";
- char * szHeaderList;
- /* Send an authorization header if we need one. */
- if (serverP->allowedAuth.basic) {
- /* Make the header with content type and authorization */
- /* NOTE: A newline is required between each added header */
- szHeaderList = malloc(strlen(szContentType) + 17 +
- strlen(serverP->basicAuthHdrValue) + 1);
-
- if (szHeaderList == NULL)
- xmlrpc_faultf(envP,
- "Couldn't allocate memory for authorization header");
- else {
- memcpy(szHeaderList, szContentType, strlen(szContentType));
- memcpy(szHeaderList + strlen(szContentType),"\r\nAuthorization: ",
- 17);
- memcpy(szHeaderList + strlen(szContentType) + 17,
- serverP->basicAuthHdrValue,
- strlen(serverP->basicAuthHdrValue) + 1);
- }
- } else {
- /* Just the content type header is needed */
- szHeaderList = malloc(strlen(szContentType) + 1);
-
- if (szHeaderList == NULL)
- xmlrpc_faultf(envP,
- "Couldn't allocate memory for standard header");
- else
- memcpy(szHeaderList, szContentType, strlen(szContentType) + 1);
- }
- *headerListP = szHeaderList;
- }
- static void
- createWinInetTransaction(xmlrpc_env * const envP,
- const xmlrpc_server_info * const serverP,
- xmlrpc_mem_block * const callXmlP,
- xmlrpc_mem_block * const responseXmlP,
- winInetTransaction ** const winInetTranPP) {
- winInetTransaction * winInetTransactionP;
- MALLOCVAR(winInetTransactionP);
- if (winInetTransactionP == NULL)
- xmlrpc_faultf(envP, "No memory to create WinInet transaction.");
- else {
- char szExtraInfo[255];
- char szScheme[100];
- URL_COMPONENTS uc;
- BOOL succeeded;
- /* Init to defaults */
- winInetTransactionP->http_status = 0;
- winInetTransactionP->hHttpRequest = NULL;
- winInetTransactionP->hURL = NULL;
- winInetTransactionP->headerList = NULL;
- winInetTransactionP->pSendData = NULL;
- winInetTransactionP->pResponseData = responseXmlP;
- /* Parse the URL and store results into the winInetTransaction */
- memset(&uc, 0, sizeof(uc));
- uc.dwStructSize = sizeof (uc);
- uc.lpszScheme = szScheme;
- uc.dwSchemeLength = 100;
- uc.lpszHostName = winInetTransactionP->szHostName;
- uc.dwHostNameLength = 255;
- uc.lpszUrlPath = winInetTransactionP->szUrlPath;
- uc.dwUrlPathLength = 255;
- uc.lpszExtraInfo = szExtraInfo;
- uc.dwExtraInfoLength = 255;
- succeeded = InternetCrackUrl(serverP->serverUrl,
- strlen(serverP->serverUrl),
- ICU_ESCAPE, &uc);
- if (!succeeded)
- xmlrpc_faultf(envP, "Unable to parse the server URL.");
- else {
- winInetTransactionP->nPort =
- uc.nPort ? uc.nPort : INTERNET_DEFAULT_HTTP_PORT;
- if (_strnicmp(uc.lpszScheme, "https", 5) == 0)
- winInetTransactionP->bUseSSL=TRUE;
- else
- winInetTransactionP->bUseSSL=FALSE;
- createWinInetHeaderList(envP, serverP,
- &winInetTransactionP->headerList);
- XMLRPC_MEMBLOCK_APPEND(char, envP, callXmlP, "\0", 1);
- if (!envP->fault_occurred) {
- winInetTransactionP->pSendData =
- XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP);
- }
- }
-
- if (envP->fault_occurred)
- free(winInetTransactionP);
- }
- *winInetTranPP = winInetTransactionP;
- }
- static void
- destroyWinInetTransaction(winInetTransaction * const winInetTransactionP) {
- XMLRPC_ASSERT_PTR_OK(winInetTransactionP);
- if (winInetTransactionP->hHttpRequest)
- InternetCloseHandle(winInetTransactionP->hHttpRequest);
- if (winInetTransactionP->hURL)
- InternetCloseHandle(winInetTransactionP->hURL);
- if (winInetTransactionP->headerList)
- free(winInetTransactionP->headerList);
- free(winInetTransactionP);
- }
- static void
- get_wininet_response(xmlrpc_env * const envP,
- winInetTransaction * const winInetTransactionP) {
- unsigned long dwLen;
- INTERNET_BUFFERS inetBuffer;
- unsigned long dwFlags;
- unsigned long dwErr;
- unsigned long nExpected;
- void * body;
- BOOL bOK;
- PVOID pMsgMem;
- pMsgMem = NULL; /* initial value */
- dwErr = 0; /* initial value */
- body = NULL; /* initial value */
- dwLen = sizeof(unsigned long); /* initial value */
- inetBuffer.dwStructSize = sizeof (INTERNET_BUFFERS);
- inetBuffer.Next = NULL;
- inetBuffer.lpcszHeader = NULL;
- inetBuffer.dwHeadersTotal = 0;
- inetBuffer.dwHeadersLength = 0;
- inetBuffer.dwOffsetHigh = 0;
- inetBuffer.dwOffsetLow = 0;
- inetBuffer.dwBufferLength = 0;
- /* Note that while Content-Length is optional in HTTP 1.1, it is
- required by XML-RPC. Following fails if server didn't send it.
- */
- bOK = HttpQueryInfo(winInetTransactionP->hHttpRequest,
- HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER,
- &inetBuffer.dwBufferTotal, &dwLen, NULL);
- if (!bOK) {
- LPTSTR pMsg;
- dwErr = GetLastError ();
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- dwErr,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &pMsgMem,
- 1024,NULL);
- pMsg = pMsgMem ? (LPTSTR)pMsgMem : "Sync HttpQueryInfo failed.";
- XMLRPC_FAIL(envP, XMLRPC_NETWORK_ERROR, pMsg);
- }
- if (inetBuffer.dwBufferTotal == 0)
- XMLRPC_FAIL(envP, XMLRPC_NETWORK_ERROR, "WinInet returned no data");
- inetBuffer.lpvBuffer = calloc(inetBuffer.dwBufferTotal, sizeof(TCHAR));
- body = inetBuffer.lpvBuffer;
- dwFlags = IRF_SYNC;
- nExpected = inetBuffer.dwBufferTotal;
- inetBuffer.dwBufferLength = nExpected;
- InternetQueryDataAvailable(winInetTransactionP->hHttpRequest,
- &inetBuffer.dwBufferLength, 0, 0);
-
- /* Read Response from InternetFile */
- do {
- if (inetBuffer.dwBufferLength != 0)
- bOK = InternetReadFileEx(winInetTransactionP->hHttpRequest,
- &inetBuffer, dwFlags, 1);
- if (!bOK)
- dwErr = GetLastError();
- if (dwErr) {
- if (dwErr == WSAEWOULDBLOCK || dwErr == ERROR_IO_PENDING) {
- /* Non-block socket operation wait 10 msecs */
- SleepEx(10, TRUE);
- /* Reset dwErr to zero for next pass */
- dwErr = 0;
- } else {
- LPTSTR pMsg;
- FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- dwErr,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &pMsgMem,
- 1024,NULL);
- pMsg = pMsgMem ?
- (LPTSTR)pMsgMem : "ASync InternetReadFileEx failed.";
- XMLRPC_FAIL(envP, XMLRPC_NETWORK_ERROR, pMsg);
- }
- }
-
- if (inetBuffer.dwBufferLength) {
- TCHAR * const oldBufptr = inetBuffer.lpvBuffer;
- inetBuffer.lpvBuffer = oldBufptr + inetBuffer.dwBufferLength;
- nExpected -= inetBuffer.dwBufferLength;
- /* Adjust inetBuffer.dwBufferLength when it is greater than the */
- /* expected end of file */
- if (inetBuffer.dwBufferLength > nExpected)
- inetBuffer.dwBufferLength = nExpected;
- } else
- inetBuffer.dwBufferLength = nExpected;
- dwErr = 0;
- } while (nExpected != 0);
- /* Add to the response buffer. */
- xmlrpc_mem_block_append(envP, winInetTransactionP->pResponseData, body,
- inetBuffer.dwBufferTotal);
- XMLRPC_FAIL_IF_FAULT(envP);
- cleanup:
- /* Since the XMLRPC_FAIL calls goto cleanup, we must handle */
- /* the free'ing of the memory here. */
- if (pMsgMem != NULL)
- LocalFree(pMsgMem);
- if (body)
- free(body);
- }
- static void
- performWinInetTransaction(
- xmlrpc_env * const envP,
- winInetTransaction * const winInetTransactionP,
- struct xmlrpc_client_transport * const clientTransportP) {
- const char * const acceptTypes[] = {"text/xml", NULL};
- unsigned long queryLen;
- LPVOID pMsgMem;
- BOOL succeeded;
- unsigned long lastErr;
- unsigned long reqFlags;
- pMsgMem = NULL; /* initial value */
- reqFlags = INTERNET_FLAG_NO_UI; /* initial value */
-
- winInetTransactionP->hURL =
- InternetConnect(hSyncInternetSession,
- winInetTransactionP->szHostName,
- winInetTransactionP->nPort,
- NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
- /* Start our request running. */
- if (winInetTransactionP->bUseSSL == TRUE)
- reqFlags |=
- INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
- winInetTransactionP->hHttpRequest =
- HttpOpenRequest(winInetTransactionP->hURL, "POST",
- winInetTransactionP->szUrlPath, "HTTP/1.1", NULL,
- (const char **)&acceptTypes,
- reqFlags, 1);
-
- XMLRPC_FAIL_IF_NULL(winInetTransactionP->hHttpRequest, envP,
- XMLRPC_INTERNAL_ERROR,
- "Unable to open the requested URL.");
- succeeded =
- HttpAddRequestHeaders(winInetTransactionP->hHttpRequest,
- winInetTransactionP->headerList,
- strlen (winInetTransactionP->headerList),
- HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
- if (!succeeded)
- XMLRPC_FAIL(envP, XMLRPC_INTERNAL_ERROR,
- "Could not set Content-Type.");
- {
- /* By default, a request times out after 30 seconds. We don't want
- it to timeout at all, since we don't know what the user is doing.
- */
- DWORD dwTimeOut = 0x7FFFFFFF; /* Approximation of infinity */
- InternetSetOption(winInetTransactionP->hHttpRequest,
- INTERNET_OPTION_RECEIVE_TIMEOUT,
- &dwTimeOut, sizeof(dwTimeOut));
- }
- Again:
- /* Send the requested XML remote procedure command */
- succeeded = HttpSendRequest(winInetTransactionP->hHttpRequest, NULL, 0,
- winInetTransactionP->pSendData,
- strlen(winInetTransactionP->pSendData));
- if (!succeeded) {
- LPTSTR pMsg;
- lastErr = GetLastError();
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- lastErr,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &pMsgMem,
- 0, NULL);
- if (pMsgMem == NULL) {
- switch (lastErr) {
- case ERROR_INTERNET_CANNOT_CONNECT:
- pMsg = "Sync HttpSendRequest failed: Connection refused.";
- break;
- case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
- pMsg = "Sync HttpSendRequest failed: "
- "Client authorization certificate needed.";
- break;
- /* The following conditions are recommendations that microsoft */
- /* provides in their knowledge base. */
- /* HOWTO: Handle Invalid Certificate Authority Error with
- WinInet (Q182888)
- */
- case ERROR_INTERNET_INVALID_CA:
- if (clientTransportP->allowInvalidSSLCerts){
- OutputDebugString(
- "Sync HttpSendRequest failed: "
- "The function is unfamiliar with the certificate "
- "authority that generated the server's certificate. ");
- reqFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
- InternetSetOption(winInetTransactionP->hHttpRequest,
- INTERNET_OPTION_SECURITY_FLAGS,
- &reqFlags, sizeof(reqFlags));
- goto Again;
- } else
- pMsg = "Invalid or unknown/untrusted "
- "SSL Certificate Authority.";
- break;
- /* HOWTO: Make SSL Requests Using WinInet (Q168151) */
- case ERROR_INTERNET_SEC_CERT_CN_INVALID:
- if (clientTransportP->allowInvalidSSLCerts) {
- OutputDebugString(
- "Sync HttpSendRequest failed: "
- "The SSL certificate common name (host name field) "
- "is incorrect\r\n "
- "for example, if you entered www.server.com "
- "and the common name "
- "on the certificate says www.different.com. ");
-
- reqFlags = INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
- InternetSetOption(winInetTransactionP->hHttpRequest,
- INTERNET_OPTION_SECURITY_FLAGS,
- &reqFlags, sizeof(reqFlags));
-
- goto Again;
- } else
- pMsg = "The SSL certificate common name "
- "(host name field) is incorrect.";
- break;
- case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
- if (clientTransportP->allowInvalidSSLCerts) {
- OutputDebugString(
- "Sync HttpSendRequest failed: "
- "The SSL certificate date that was received "
- "from the server is "
- "bad. The certificate is expired. ");
- reqFlags = INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
- InternetSetOption(winInetTransactionP->hHttpRequest,
- INTERNET_OPTION_SECURITY_FLAGS,
- &reqFlags, sizeof(reqFlags));
- goto Again;
- } else
- pMsg = "The SSL certificate date that was received "
- "from the server is invalid.";
- break;
- default:
- pMsg = (LPTSTR)pMsgMem = LocalAlloc(LPTR, MAX_PATH);
- sprintf(pMsg, "Sync HttpSendRequest failed: "
- "GetLastError (%d)", lastErr);
- break;
- }
- } else
- pMsg = (LPTSTR)pMsgMem;
- XMLRPC_FAIL(envP, XMLRPC_NETWORK_ERROR, pMsg);
- }
- queryLen = sizeof(unsigned long); /* initial value */
- succeeded = HttpQueryInfo(winInetTransactionP->hHttpRequest,
- HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE,
- &winInetTransactionP->http_status,
- &queryLen, NULL);
- if (!succeeded) {
- LPTSTR pMsg;
- lastErr = GetLastError();
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- lastErr,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &pMsgMem,
- 1024, NULL);
- pMsg = pMsgMem ? (LPTSTR)pMsgMem : "Sync HttpQueryInfo failed.";
- XMLRPC_FAIL(envP, XMLRPC_NETWORK_ERROR, pMsg);
- }
- /* Make sure we got a "200 OK" message from the remote server. */
- if (winInetTransactionP->http_status != 200) {
- unsigned long msgLen;
- char errMsg[1024];
- errMsg[0] = '\0';
- msgLen = 1024; /* initial value */
- HttpQueryInfo(winInetTransactionP->hHttpRequest,
- HTTP_QUERY_STATUS_TEXT, errMsg, &msgLen, NULL);
- xmlrpc_env_set_fault_formatted(
- envP, XMLRPC_NETWORK_ERROR,
- "HTTP error #%d occurred\n %s",
- winInetTransactionP->http_status, errMsg);
- goto cleanup;
- }
- /* Read the response. */
- get_wininet_response(envP, winInetTransactionP);
- XMLRPC_FAIL_IF_FAULT(envP);
- cleanup:
- /* Since the XMLRPC_FAIL calls goto cleanup, we must handle */
- /* the free'ing of the memory here. */
- if (pMsgMem)
- LocalFree(pMsgMem);
- }
- static void *
- doAsyncRpc(void * const arg) {
- rpc * const rpcP = arg;
- xmlrpc_env env;
- xmlrpc_env_init(&env);
- performWinInetTransaction(&env, rpcP->winInetTransactionP,
- rpcP->clientTransportP );
- rpcP->complete(rpcP->callInfoP, rpcP->responseXmlP, env);
- xmlrpc_env_clean(&env);
- return NULL;
- }
- 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_faultf(envP, "pthread_create() failed: "
- "System Resources exceeded.");
- break;
- case EINVAL:
- xmlrpc_faultf(envP, "pthread_create() failed: "
- "Param Error for attr.");
- break;
- case ENOMEM:
- xmlrpc_faultf(envP, "pthread_create() failed: "
- "No memory for new thread.");
- break;
- default:
- xmlrpc_faultf(envP, "pthread_create() failed: "
- "Unrecognized error code %d.", rc);
- break;
- }
- }
- static void
- rpcCreate(xmlrpc_env * const envP,
- struct xmlrpc_client_transport * const clientTransportP,
- const xmlrpc_server_info * const serverP,
- xmlrpc_mem_block * const callXmlP,
- xmlrpc_mem_block * const responseXmlP,
- xmlrpc_transport_asynch_complete complete,
- struct xmlrpc_call_info * const callInfoP,
- rpc ** const rpcPP) {
- rpc * rpcP;
- MALLOCVAR(rpcP);
- if (rpcP == NULL)
- xmlrpc_faultf(envP, "Couldn't allocate memory for rpc object");
- else {
- rpcP->callInfoP = callInfoP;
- rpcP->complete = complete;
- rpcP->responseXmlP = responseXmlP;
- rpcP->threadExists = FALSE;
- createWinInetTransaction(envP, serverP, callXmlP, responseXmlP,
- &rpcP->winInetTransactionP);
- if (!envP->fault_occurred) {
- if (complete) {
- createRpcThread(envP, rpcP, &rpcP->thread);
- if (!envP->fault_occurred)
- rpcP->threadExists = TRUE;
- }
- if (!envP->fault_occurred) {
- list_init_header(&rpcP->link, rpcP);
- pthread_mutex_lock(&clientTransportP->listLock);
- list_add_head(&clientTransportP->rpcList, &rpcP->link);
- pthread_mutex_unlock(&clientTransportP->listLock);
- }
- if (envP->fault_occurred)
- destroyWinInetTransaction(rpcP->winInetTransactionP);
- }
- if (envP->fault_occurred)
- free(rpcP);
- }
- *rpcPP = rpcP;
- }
- static void
- rpcDestroy(rpc * const rpcP) {
- XMLRPC_ASSERT_PTR_OK(rpcP);
- XMLRPC_ASSERT(!rpcP->threadExists);
- destroyWinInetTransaction(rpcP->winInetTransactionP);
- list_remove(&rpcP->link);
- free(rpcP);
- }
- static void *
- finishRpc(struct list_head * const headerP,
- void * const context ATTR_UNUSED) {
-
- rpc * const rpcP = headerP->itemP;
- if (rpcP->threadExists) {
- void * status;
- int result;
- result = pthread_join(rpcP->thread, &status);
-
- rpcP->threadExists = FALSE;
- }
- XMLRPC_MEMBLOCK_FREE(char, rpcP->responseXmlP);
- rpcDestroy(rpcP);
- return NULL;
- }
- /* Used for debugging purposes to track the status of
- your request.
- */
- void CALLBACK
- statusCallback (HINTERNET const hInternet,
- unsigned long const dwContext,
- unsigned long const dwInternetStatus,
- void * const lpvStatusInformation,
- unsigned long const dwStatusInformationLength) {
- switch (dwInternetStatus) {
- case INTERNET_STATUS_RESOLVING_NAME:
- OutputDebugString("INTERNET_STATUS_RESOLVING_NAME\r\n");
- break;
- case INTERNET_STATUS_NAME_RESOLVED:
- OutputDebugString("INTERNET_STATUS_NAME_RESOLVED\r\n");
- break;
- case INTERNET_STATUS_HANDLE_CREATED:
- OutputDebugString("INTERNET_STATUS_HANDLE_CREATED\r\n");
- break;
- case INTERNET_STATUS_CONNECTING_TO_SERVER:
- OutputDebugString("INTERNET_STATUS_CONNECTING_TO_SERVER\r\n");
- break;
- case INTERNET_STATUS_REQUEST_SENT:
- OutputDebugString("INTERNET_STATUS_REQUEST_SENT\r\n");
- break;
- case INTERNET_STATUS_SENDING_REQUEST:
- OutputDebugString("INTERNET_STATUS_SENDING_REQUEST\r\n");
- break;
- case INTERNET_STATUS_CONNECTED_TO_SERVER:
- OutputDebugString("INTERNET_STATUS_CONNECTED_TO_SERVER\r\n");
- break;
- case INTERNET_STATUS_RECEIVING_RESPONSE:
- OutputDebugString("INTERNET_STATUS_RECEIVING_RESPONSE\r\n");
- break;
- case INTERNET_STATUS_RESPONSE_RECEIVED:
- OutputDebugString("INTERNET_STATUS_RESPONSE_RECEIVED\r\n");
- break;
- case INTERNET_STATUS_CLOSING_CONNECTION:
- OutputDebugString("INTERNET_STATUS_CLOSING_CONNECTION\r\n");
- break;
- case INTERNET_STATUS_CONNECTION_CLOSED:
- OutputDebugString("INTERNET_STATUS_CONNECTION_CLOSED\r\n");
- break;
- case INTERNET_STATUS_HANDLE_CLOSING:
- OutputDebugString("INTERNET_STATUS_HANDLE_CLOSING\r\n");
- break;
- case INTERNET_STATUS_CTL_RESPONSE_RECEIVED:
- OutputDebugString("INTERNET_STATUS_CTL_RESPONSE_RECEIVED\r\n");
- break;
- case INTERNET_STATUS_REDIRECT:
- OutputDebugString("INTERNET_STATUS_REDIRECT\r\n");
- break;
- case INTERNET_STATUS_REQUEST_COMPLETE:
- /* This indicates the data is ready. */
- OutputDebugString("INTERNET_STATUS_REQUEST_COMPLETE\r\n");
- break;
- default:
- OutputDebugString("statusCallback, default case!\r\n");
- break;
- }
- }
- static void
- create(xmlrpc_env * const envP,
- int const flags ATTR_UNUSED,
- const char * const appname ATTR_UNUSED,
- const char * const appversion ATTR_UNUSED,
- const void * const transportparmsP,
- size_t const parm_size,
- struct xmlrpc_client_transport ** const handlePP) {
- /*----------------------------------------------------------------------------
- This does the 'create' operation for a WinInet client transport.
- -----------------------------------------------------------------------------*/
- const struct xmlrpc_wininet_xportparms * const wininetXportParmsP =
- transportparmsP;
- struct xmlrpc_client_transport * transportP;
- MALLOCVAR(transportP);
- if (transportP == NULL)
- xmlrpc_faultf(envP, "Unable to allocate transport descriptor.");
- else {
- pthread_mutex_init(&transportP->listLock, NULL);
-
- list_make_empty(&transportP->rpcList);
- if (hSyncInternetSession == NULL)
- hSyncInternetSession =
- InternetOpen("xmlrpc-c wininet transport",
- INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
- if (!wininetXportParmsP ||
- parm_size < XMLRPC_WXPSIZE(allowInvalidSSLCerts))
- transportP->allowInvalidSSLCerts = 0;
- else
- transportP->allowInvalidSSLCerts =
- wininetXportParmsP->allowInvalidSSLCerts;
- *handlePP = transportP;
- }
- }
- static void
- destroy(struct xmlrpc_client_transport * const clientTransportP) {
- /*----------------------------------------------------------------------------
- This does the 'destroy' operation for a WinInet client transport.
- -----------------------------------------------------------------------------*/
- XMLRPC_ASSERT(clientTransportP != NULL);
- XMLRPC_ASSERT(list_is_empty(&clientTransportP->rpcList));
- if (hSyncInternetSession)
- InternetCloseHandle(hSyncInternetSession);
- hSyncInternetSession = NULL;
- pthread_mutex_destroy(&clientTransportP->listLock);
- free(clientTransportP);
- }
- static void
- sendRequest(xmlrpc_env * const envP,
- struct xmlrpc_client_transport * const clientTransportP,
- const xmlrpc_server_info * const serverP,
- xmlrpc_mem_block * const callXmlP,
- xmlrpc_transport_asynch_complete complete,
- xmlrpc_transport_progress progress,
- struct xmlrpc_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 WinInet 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
- finishAsynch(struct xmlrpc_client_transport * const clientTransportP,
- xmlrpc_timeoutType const timeoutType ATTR_UNUSED,
- xmlrpc_timeout 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 WinInet client transport.
- -----------------------------------------------------------------------------*/
- /* We ignore any timeout request. Some day, we should figure out how
- to set an alarm and interrupt running threads.
- */
- pthread_mutex_lock(&clientTransportP->listLock);
- list_foreach(&clientTransportP->rpcList, finishRpc, NULL);
- pthread_mutex_unlock(&clientTransportP->listLock);
- }
- static void
- call(xmlrpc_env * const envP,
- struct xmlrpc_client_transport * const clientTransportP,
- const xmlrpc_server_info * const serverP,
- xmlrpc_mem_block * const callXmlP,
- 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(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) {
- performWinInetTransaction(envP, rpcP->winInetTransactionP,
- clientTransportP);
-
- *responsePP = responseXmlP;
-
- rpcDestroy(rpcP);
- }
- if (envP->fault_occurred)
- XMLRPC_MEMBLOCK_FREE(char, responseXmlP);
- }
- }
- struct xmlrpc_client_transport_ops xmlrpc_wininet_transport_ops = {
- NULL,
- NULL,
- &create,
- &destroy,
- &sendRequest,
- &call,
- &finishAsynch,
- NULL,
- };
- /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
- **
- ** Redistribution and use in source and binary forms, with or without
- ** modification, are permitted provided that the following conditions
- ** are met:
- ** 1. Redistributions of source code must retain the above copyright
- ** notice, this list of conditions and the following disclaimer.
- ** 2. Redistributions in binary form must reproduce the above copyright
- ** notice, this list of conditions and the following disclaimer in the
- ** documentation and/or other materials provided with the distribution.
- ** 3. The name of the author may not be used to endorse or promote products
- ** derived from this software without specific prior written permission.
- **
- ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- ** SUCH DAMAGE. */
|