From 89c5b2369413025e1fe7dfe5c5d0bf3bedd8558d Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Mon, 23 Jul 2012 13:52:57 +0000 Subject: git-svn-id: http://svn.miranda-ng.org/main/trunk@1123 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- !NotAdopted/IMO2sProxy/src/imolib/io_layer_win32.c | 440 +++++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 !NotAdopted/IMO2sProxy/src/imolib/io_layer_win32.c (limited to '!NotAdopted/IMO2sProxy/src/imolib/io_layer_win32.c') diff --git a/!NotAdopted/IMO2sProxy/src/imolib/io_layer_win32.c b/!NotAdopted/IMO2sProxy/src/imolib/io_layer_win32.c new file mode 100644 index 0000000000..1fd425ced7 --- /dev/null +++ b/!NotAdopted/IMO2sProxy/src/imolib/io_layer_win32.c @@ -0,0 +1,440 @@ +/* Module: io_layer_win32.c + Purpose: IO Layer for Internet communication using WININET (Win32) + Author: leecher + Date: 30.08.2009 +*/ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include "fifo.h" +#include "io_layer.h" + +#ifndef LongToPtr +#define DWORD_PTR DWORD +#endif + +/* Set this to use asynchronous I/O + This is needed as synchronous WININET functions tend to block forever on connection + loss or other occasions leading to a deadlock of the whole application + */ +#define ASYNC +#define ASYNC_CONN_TIMEOUT 5000 // Connection timeout in ms +#define ASYNC_REQ_TIMEOUT 40000 // HttpSendRequest timeout in ms in async mode (Should be at least 30 sec!) + +#pragma comment(lib,"wininet.lib") + +#define INET_FLAGS INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID | \ + INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_UI | \ + INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_SECURE + +typedef struct +{ + IOLAYER vtbl; + HINTERNET hInet; + HINTERNET hRequest; +#ifdef ASYNC + INTERNET_ASYNC_RESULT stAsyncRes; + HANDLE hConnectedEvent; + HANDLE hRequestCompleteEvent; +#endif + TYP_FIFO *hResult; + LPVOID lpErrorBuf; +} IOLAYER_INST; + +static void IoLayer_Exit (IOLAYER *hPIO); +static char *IoLayer_Post(IOLAYER *hPIO, char *pszURL, char *pszPostFields, unsigned int cbPostFields, unsigned int *pdwLength); +static char *IoLayer_Get(IOLAYER *hIO, char *pszURL, unsigned int *pdwLength); +static void IoLayer_Cancel(IOLAYER *hIO); +static char *IoLayer_GetLastError(IOLAYER *hIO); +static char *IoLayer_EscapeString(IOLAYER *hPIO, char *pszData); +static void IoLayer_FreeEscapeString(char *pszData); +static void FetchLastError (IOLAYER_INST *hIO); +#ifdef ASYNC +static void __stdcall Callback(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus, + LPVOID lpStatusInfo, DWORD dwStatusInfoLen); +#endif + +// ----------------------------------------------------------------------------- +// Interface +// ----------------------------------------------------------------------------- + +IOLAYER *IoLayerW32_Init(void) +{ + IOLAYER_INST *hIO; + + if (!(hIO = calloc(1, sizeof(IOLAYER_INST)))) + return NULL; + + // Init Inet + if (!(hIO->hInet = InternetOpen ("Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13", + INTERNET_OPEN_TYPE_PRECONFIG, NULL, "", +#ifdef ASYNC + INTERNET_FLAG_ASYNC +#else + 0 +#endif + ))) + { + free (hIO); + return NULL; + } + + if (!(hIO->hResult = Fifo_Init(1024))) + { + IoLayer_Exit((IOLAYER*)hIO); + return NULL; + } + +#ifdef ASYNC + if (InternetSetStatusCallback(hIO->hInet, (INTERNET_STATUS_CALLBACK)&Callback) == INTERNET_INVALID_STATUS_CALLBACK) + { + IoLayer_Exit((IOLAYER*)hIO); + return NULL; + } + + hIO->hConnectedEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + hIO->hRequestCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL); +#endif + + //InternetSetCookie ("https://o.imo.im/", "proto", "prpl-skype"); + + // Init Vtbl + hIO->vtbl.Exit = IoLayer_Exit; + hIO->vtbl.Post = IoLayer_Post; + hIO->vtbl.Get = IoLayer_Get; + hIO->vtbl.Cancel = IoLayer_Cancel; + hIO->vtbl.GetLastError = IoLayer_GetLastError; + hIO->vtbl.EscapeString = IoLayer_EscapeString; + hIO->vtbl.FreeEscapeString = IoLayer_FreeEscapeString; + + return (IOLAYER*)hIO; +} +// ----------------------------------------------------------------------------- + +static void IoLayer_Exit (IOLAYER *hPIO) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + + if (hIO->hInet) InternetCloseHandle (hIO->hInet); + if (hIO->lpErrorBuf) LocalFree(hIO->lpErrorBuf); + if (hIO->hResult) Fifo_Exit(hIO->hResult); + +#ifdef ASYNC + if (hIO->hConnectedEvent) CloseHandle (hIO->hConnectedEvent); + if (hIO->hRequestCompleteEvent) CloseHandle (hIO->hRequestCompleteEvent); +#endif + free (hIO); +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_Post(IOLAYER *hPIO, char *pszURL, char *pszPostFields, unsigned int cbPostFields, unsigned int *pdwLength) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + URL_COMPONENTS urlInfo = {0}; + HINTERNET hUrl; + DWORD dwFlags = 0, cbFlags = sizeof(dwFlags), dwRemaining = 0; + char szHostName[INTERNET_MAX_HOST_NAME_LENGTH], + szURLPath[INTERNET_MAX_URL_LENGTH], *p; +#ifdef ASYNC + INTERNET_BUFFERS InetBuff={0}; + InetBuff.dwStructSize = sizeof(InetBuff); + + ResetEvent (hIO->hConnectedEvent); + ResetEvent (hIO->hRequestCompleteEvent); +#endif + +//OutputDebugString(pszPostFields); + urlInfo.dwStructSize = sizeof (URL_COMPONENTS); + urlInfo.lpszHostName = szHostName; + urlInfo.dwHostNameLength = sizeof(szHostName); + urlInfo.lpszUrlPath = szURLPath; + urlInfo.dwUrlPathLength = sizeof(szURLPath); + if (!InternetCrackUrl(pszURL, strlen(pszURL), 0, &urlInfo)) return NULL; + /* + if (!pszPostFields) + { + if (pszPostFields=strchr (pszURL, '?')) + cbPostFields = strlen(pszPostFields); + } + */ + if (!(hUrl = InternetConnect (hIO->hInet, szHostName, + INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)hIO))) + { +#ifdef ASYNC + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(hIO->hConnectedEvent, ASYNC_CONN_TIMEOUT) == WAIT_OBJECT_0) + { + hUrl = (HINTERNET)hIO->stAsyncRes.dwResult; + hIO->stAsyncRes.dwResult = 0; + SetLastError(hIO->stAsyncRes.dwError); + } + } + if (!hUrl) +#endif + { + FetchLastError (hIO); + return NULL; + } + } + + hIO->hRequest = HttpOpenRequest (hUrl, pszPostFields?"POST":"GET", szURLPath, NULL, "https://imo.im/", NULL, + INET_FLAGS, (DWORD_PTR)hIO); + if (!hIO->hRequest) + { +#ifdef ASYNC + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(hIO->hConnectedEvent, ASYNC_CONN_TIMEOUT) == WAIT_OBJECT_0) + { + hIO->hRequest = (HINTERNET)hIO->stAsyncRes.dwResult; + hIO->stAsyncRes.dwResult = 0; + SetLastError(hIO->stAsyncRes.dwError); + } + } + if (!hUrl) +#endif + { + FetchLastError (hIO); + InternetCloseHandle (hUrl); + return NULL; + } + } + + InternetQueryOption (hIO->hRequest, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &cbFlags); + dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; + InternetSetOption (hIO->hRequest, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags)); + + /* + { + char szCookies[4096]; + DWORD cbCookies, dwIndex=0; + + OutputDebugString ("Sending headers:\n"); + do + { + cbCookies=sizeof(szCookies); + if (!HttpQueryInfo (hIO->hRequest, HTTP_QUERY_FLAG_REQUEST_HEADERS|HTTP_QUERY_RAW_HEADERS_CRLF, szCookies, &cbCookies, &dwIndex) || + GetLastError() != ERROR_SUCCESS) + break; + OutputDebugString (szCookies); + } while (1); + } + */ + +// ASYNC: This needs to block for at least 30 seconds on poll! + if (!(HttpSendRequest (hIO->hRequest, "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n" + "X-Requested-With: XMLHttpRequest", -1, + pszPostFields, cbPostFields))) + { +#ifdef ASYNC + BOOL bRes = FALSE; + + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(hIO->hRequestCompleteEvent, ASYNC_REQ_TIMEOUT) == WAIT_OBJECT_0) + { + bRes = hIO->stAsyncRes.dwResult; + hIO->stAsyncRes.dwResult = 0; + SetLastError(hIO->stAsyncRes.dwError); + } + } + if (!bRes) +#endif + { + FetchLastError (hIO); + InternetCloseHandle (hIO->hRequest); + hIO->hRequest = NULL; + InternetCloseHandle (hUrl); + return NULL; + } + } +#ifdef ASYNC + else WaitForSingleObject(hIO->hRequestCompleteEvent, ASYNC_REQ_TIMEOUT); +#endif + + /* + { + char szCookies[4096]; + DWORD cbCookies, dwIndex=0; + + OutputDebugString ("Received headers:\n"); + do + { + cbCookies=sizeof(szCookies); + if (!HttpQueryInfo (hIO->hRequest, HTTP_QUERY_FLAG_REQUEST_HEADERS|HTTP_QUERY_RAW_HEADERS_CRLF, szCookies, &cbCookies, &dwIndex) || + GetLastError() != ERROR_SUCCESS) + break; + OutputDebugString (szCookies); + } while (1); + } + */ + +#ifdef ASYNC + do + { + if (!InternetQueryDataAvailable (hIO->hRequest, &InetBuff.dwBufferLength, 0, 0)) + { + BOOL bRes = FALSE; + + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(hIO->hRequestCompleteEvent, ASYNC_REQ_TIMEOUT) == WAIT_OBJECT_0) + { + bRes = hIO->stAsyncRes.dwResult; + hIO->stAsyncRes.dwResult = 0; + SetLastError(hIO->stAsyncRes.dwError); + } + } + if (!bRes) break; + } + if (InetBuff.dwBufferLength == 0) break; + if (InetBuff.lpvBuffer = Fifo_AllocBuffer (hIO->hResult, InetBuff.dwBufferLength)) + { + if (!InternetReadFileEx (hIO->hRequest, &InetBuff, 0, (DWORD_PTR)hIO)) + { + BOOL bRes=FALSE; + + if (GetLastError() == ERROR_IO_PENDING) + { + if (WaitForSingleObject(hIO->hRequestCompleteEvent, ASYNC_REQ_TIMEOUT) == WAIT_OBJECT_0) + { + bRes = hIO->stAsyncRes.dwResult; + hIO->stAsyncRes.dwResult = 0; + SetLastError(hIO->stAsyncRes.dwError); + } + } + if (!bRes) break; + } + } + } + while(InetBuff.dwBufferLength); +#else + while (InternetQueryDataAvailable (hIO->hRequest, &dwRemaining, 0, 0) && dwRemaining > 0) + { + if (p = Fifo_AllocBuffer (hIO->hResult, dwRemaining)) + InternetReadFile (hIO->hRequest, p, dwRemaining, &dwRemaining); + } +#endif + + if (!pdwLength) + { + // Get string + Fifo_Add (hIO->hResult, "", 1); + p = Fifo_Get (hIO->hResult, NULL); + } + else + { + // Get binary, return size of buffer + *pdwLength = (unsigned int)-1; + p = Fifo_Get (hIO->hResult, pdwLength); + } + InternetCloseHandle (hIO->hRequest); + hIO->hRequest = NULL; + InternetCloseHandle (hUrl); +OutputDebugString(p); +OutputDebugString("\n"); + return p; +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_Get(IOLAYER *hIO, char *pszURL, unsigned int *pdwLength) +{ + return IoLayer_Post (hIO, pszURL, NULL, 0, pdwLength); +} + +// ----------------------------------------------------------------------------- + +static void IoLayer_Cancel(IOLAYER *hPIO) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + +#ifdef ASYNC + if (hIO->hRequest) + { + hIO->stAsyncRes.dwResult = 0; + hIO->stAsyncRes.dwError = ERROR_CANCELLED; + SetEvent(hIO->hRequestCompleteEvent); + } +#else + if (hIO->hRequest && InternetCloseHandle(hIO->hRequest)) + hIO->hRequest = NULL; +#endif +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_GetLastError(IOLAYER *hIO) +{ + return (char*)((IOLAYER_INST*)hIO)->lpErrorBuf; +} + +// ----------------------------------------------------------------------------- + +static char *IoLayer_EscapeString(IOLAYER *hPIO, char *pszData) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)hPIO; + TYP_FIFO *hFifo; + char szBuf[8], *pszRet; + unsigned char *p; + + if (!(hFifo = Fifo_Init(strlen(pszData)))) return NULL; + for (p=pszData; *p; p++) + { + if (isalnum(*p)) Fifo_Add (hFifo, p, 1); + else { + wsprintf (szBuf, "%%%02X", *p); + Fifo_Add (hFifo, szBuf, 3); + } + } + Fifo_Add (hFifo, "", 1); + if (pszRet = Fifo_Get(hFifo, NULL)) + pszRet = strdup(pszRet); + Fifo_Exit(hFifo); + return pszRet; +} + +// ----------------------------------------------------------------------------- + +static void IoLayer_FreeEscapeString(char *pszData) +{ + free (pszData); +} + +// ----------------------------------------------------------------------------- +// Static +// ----------------------------------------------------------------------------- + +static void FetchLastError (IOLAYER_INST *hIO) +{ + if (hIO->lpErrorBuf) LocalFree(hIO->lpErrorBuf); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, + GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), + (LPTSTR)&hIO->lpErrorBuf, 0, NULL); +} + +#ifdef ASYNC +static void __stdcall Callback(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus, + LPVOID lpStatusInfo, DWORD dwStatusInfoLen) +{ + IOLAYER_INST *hIO = (IOLAYER_INST*)dwContext; + + + switch(dwInternetStatus) + { + case INTERNET_STATUS_HANDLE_CREATED: + SetEvent (hIO->hConnectedEvent); + break; + case INTERNET_STATUS_REQUEST_COMPLETE: + hIO->stAsyncRes = *((INTERNET_ASYNC_RESULT *)lpStatusInfo); + SetEvent(hIO->hRequestCompleteEvent); + break; + } +} +#endif \ No newline at end of file -- cgit v1.2.3