We are porting our code from an old platform running on Windows CE 6.0 to Colibri T30 with SDK ,Toradex_CE600(ARMv4I), and are surprised how slowly T30 runs the wininet API calls to a secured HTTP server. I wrote the attached HTTP_Test project, in which the code first logs into HTTPS server with password. Then it does a POST every two seconds to server to get latest status by invoking update_status() function.
On the old platform, the execution time of update_status() runs about 100 msec ~ 150 msec. On T30, in most of my tests, it takes about 32 sec to 36 sec to return from HttpSendRequest() API call every other time update_status() is invoked. It runs about 100 msec ~ 200 msec the other time. There were also times that one call takes 20 some sec, and the next call takes 10 some sec. It looks like the execution time adds up to 32 sec ~ 36 sec for every two update_status() invocations.
I cannot figure out why this code runs so slowly on T30 while a lot of my other code runs faster on T30 as T30 has a faster CPUs than our old platform.
The HTTP server is running on Linux and is probably implemented using CURL. I notice two differences between T30 and our old platform, which I don’t think contribute to the differences in behavior. One being the old code is built on VS 2005 while T30 code is built on VS 2008. The other being the image of the old platform doesn’t have HKEY_LOCAL_MACHINE\COMM\HTTPD registry key.
link text
/* Below is a copy-paste of HTTP_Test.cpp, which include codes VS 2008 populates for a Win32 Smart Device Project */
// HTTP_Test.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "HTTP_Test.h"
#include
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE g_hInst; // current instance
HWND g_hWndCommandBar; // command bar handle
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE, LPTSTR);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
#define MAX_COMMAND_BYTES 64
HINTERNET hInternet = NULL;
HINTERNET hIConnect = NULL;
HINTERNET hIRequest = NULL;
static char URL_status[2][MAX_COMMAND_BYTES];
bool logInHTTPS( void );
bool update_status(int channel, char* status);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
char status[MAX_COMMAND_BYTES];
//main loop run
int Run = 1;
DWORD m_seconds, last_sec = 0; //system time in milliseconds
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable;
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_HTTP_TEST));
last_sec = GetTickCount();
if (logInHTTPS())
{
printf("Logged in Successful and took %d ms! \n", GetTickCount()- last_sec );
}
else
{
printf("Log in Failed! \n");
}
int channel = 0;
for (int j = 0; j < 2; j++ )
{
sprintf(URL_status[j],"channel=%d&request=status\0",j+1);
}
//------------------------------Main Loop------------------------
while (Run){
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){ //use to stop program - console
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Sleep(5); // to reduce heat
m_seconds = GetTickCount();
if((m_seconds - last_sec) > 2000.0){
//----------------- Get status every 2 seconds ---------------------------
last_sec = m_seconds;
channel = (channel) ? 0 :1 ;
update_status(channel, status);
}
}
return (int) msg.wParam;
}
bool logInHTTPS( void )
{
TCHAR *EventName = NULL;
DWORD NumBytes = 0;
HANDLE UserEvent = INVALID_HANDLE_VALUE;
if(!hInternet) {
hInternet = InternetOpen(TEXT("Connection to Device"),
INTERNET_OPEN_TYPE_DIRECT,
NULL,
NULL,
0);
if (!hInternet)
{
return false;
}
}
// Next, connect to the Internet via InternetConnect
hIConnect = InternetConnect(hInternet,
TEXT("10.10.10.234"), // Server name/Ip address
INTERNET_DEFAULT_HTTPS_PORT, // sever port, default to HPPS port-443
TEXT("DEVICE"), // User name
TEXT("pseudo"), // User password
INTERNET_SERVICE_HTTP, // Service
0, // Flags
0); // Context
if(!hIConnect) {
InternetCloseHandle(hInternet);
return false;
}
hIRequest = HttpOpenRequest( hIConnect,
TEXT("GET"), // Method
TEXT("/device/m2m"), // Object name
NULL, // Version
NULL, // Referrer
NULL, // Extra headers
INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID |
INTERNET_FLAG_IGNORE_CERT_DATE_INVALID |
INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | INTERNET_FLAG_NO_UI |
INTERNET_FLAG_KEEP_CONNECTION, // Flag to keep login
0); // Context
if(!hIRequest) {
InternetCloseHandle(hIConnect);
return false;
}
DWORD dwFlags;
DWORD dwBuffLen = sizeof (dwFlags);
// Send the request
InternetQueryOption (hIRequest, INTERNET_OPTION_SECURITY_FLAGS,
(LPVOID) &dwFlags,
&dwBuffLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption (hIRequest,
INTERNET_OPTION_SECURITY_FLAGS,
&dwFlags,
sizeof(dwFlags));
DWORD start_t = GetTickCount();
BOOL fSuccess = HttpSendRequest(hIRequest,
NULL,
0,
NULL,
0);
DWORD errorCode = 0;
if (!fSuccess)
{
errorCode = GetLastError();
printf("Failed in HttpSendRequest() with errro code = %u \n", errorCode);
return false;
}
printf("Login SendRequest() takes %d ms \n", GetTickCount() - start_t);
// Download the file
char* lpBuffer = NULL;
LPVOID lpTotal = NULL;
DWORD dwRead = 0;
BOOL bActive = TRUE;
lpTotal = (LPVOID)LocalAlloc(LPTR, 40960);
lpBuffer = (char *)LocalAlloc(LPTR, 4096);
if(!lpBuffer || !lpTotal) {
printf(" CANNOT_ALLOCATE_MEMEORY_FOR_HTTP_DOWNLOAD \n");
return false;
}
int k = 0;
DWORD dwAvail;
memset(lpBuffer, 0, 4096);
do{
InternetQueryDataAvailable(hIRequest,
&dwAvail,
0, 0);
if (dwAvail == 0 ) {
bActive = FALSE;
break;
}
fSuccess = InternetReadFile(hIRequest, (LPVOID)lpBuffer, dwAvail,
&dwRead);
if(!fSuccess || dwRead == 0) {
bActive = FALSE;
break;
}
if (k == 0)
{
strncpy((char*)lpTotal, (char*)lpBuffer, 4096);
} else {
strncat((char*)lpTotal, (char*)lpBuffer, 4096);
}
k++;
dwRead = 0;
} while(bActive);
LocalFree(lpBuffer);
LocalFree(lpTotal);
return true;
}
bool update_status(int channel, char* status)
{
DWORD dwFlags, errorCode, dwStatus, dwAvail;
DWORD dwStatusSize = sizeof(dwStatus);
DWORD start_time = GetTickCount();
InternetCloseHandle(hIRequest);
hIRequest = HttpOpenRequest( hIConnect,
TEXT("POST"), // Method
TEXT("/device/m2m"),
NULL, // Version
NULL, // Referrer
NULL, // Extra headers
INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID |
INTERNET_FLAG_IGNORE_CERT_DATE_INVALID |
INTERNET_FLAG_KEEP_CONNECTION, // Flag to keep login
0); // Context
if(!hIRequest) {
printf("CANNOT_OPEN_HTTP_REQUEST_HTTP in update status \n");
return false;
}
DWORD postSize = strlen(URL_status[channel]);
// InternetQueryOption (hIRequest, INTERNET_OPTION_SECURITY_FLAGS,
// (LPVOID) &dwFlags,
// &dwBuffLen);
dwFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption (hIRequest,
INTERNET_OPTION_SECURITY_FLAGS,
&dwFlags,
sizeof(dwFlags));
DWORD start_time2 = GetTickCount();
BOOL fSuccess = HttpSendRequest(hIRequest,
NULL,
0,
URL_status[channel],
postSize);
if (!fSuccess)
{
errorCode = GetLastError();
printf("CANNOT_REQUEST_HTTP_SERVER with error code, %d \n", errorCode);
return false;
}
DWORD HttpSendRequest_time = GetTickCount();
if ( (HttpSendRequest_time - start_time) > 800 ) {
printf( "Warning: took %d msec to HttpSendRequest() \n",
HttpSendRequest_time - start_time2);
}
char pOutBuf[1024];
memset(pOutBuf, 0, 1024);
dwAvail = 0;
char* pTempOut = pOutBuf;
DWORD dwRead;
while (InternetQueryDataAvailable(hIRequest,
&dwAvail,
0, 0) && dwAvail != 0 )
{
InternetReadFile(hIRequest,pTempOut, dwAvail, &dwRead);
pTempOut += dwRead;
}
printf("channel %d, time = %d, message = %s, \n \n \n", channel+1,
HttpSendRequest_time-start_time, pOutBuf);
return true;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HTTP_TEST));
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
return RegisterClass(&wc);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
TCHAR szTitle[MAX_LOADSTRING]; // title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // main window class name
g_hInst = hInstance; // Store instance handle in our global variable
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_HTTP_TEST, szWindowClass, MAX_LOADSTRING);
if (!MyRegisterClass(hInstance, szWindowClass))
{
return FALSE;
}
hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
if (g_hWndCommandBar)
{
CommandBar_Show(g_hWndCommandBar, TRUE);
}
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_HELP_ABOUT:
DialogBox(g_hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, About);
break;
case IDM_FILE_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_CREATE:
g_hWndCommandBar = CommandBar_Create(g_hInst, hWnd, 1);
CommandBar_InsertMenubar(g_hWndCommandBar, g_hInst, IDR_MENU, 0);
CommandBar_AddAdornments(g_hWndCommandBar, 0, 0);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
CommandBar_Destroy(g_hWndCommandBar);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
RECT rectChild, rectParent;
int DlgWidth, DlgHeight; // dialog width and height in pixel units
int NewPosX, NewPosY;
// trying to center the About dialog
if (GetWindowRect(hDlg, &rectChild))
{
GetClientRect(GetParent(hDlg), &rectParent);
DlgWidth = rectChild.right - rectChild.left;
DlgHeight = rectChild.bottom - rectChild.top ;
NewPosX = (rectParent.right - rectParent.left - DlgWidth) / 2;
NewPosY = (rectParent.bottom - rectParent.top - DlgHeight) / 2;
// if the About box is larger than the physical screen
if (NewPosX < 0) NewPosX = 0;
if (NewPosY < 0) NewPosY = 0;
SetWindowPos(hDlg, 0, NewPosX, NewPosY,
0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
return (INT_PTR)TRUE;
case WM_COMMAND:
if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL))
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hDlg, message);
return TRUE;
}
return (INT_PTR)FALSE;
}
Dear @Mike_Fang
Thank you for the source code. It’s still an issue to reproduce the problem, as we don’t have a similar server to connect to (I assume 10.10.10.234 is your own HTTPS server).
Can you reproduce the problem with a publicly accessible server, so we would be able to reproduce the issue here?
Kind Regards, Andy
Can you please share Http_Test.h or compiled curl.h for winCE ?