SSL_accept takes 200ms (c / openssl) - c++

Is it normal that SSL_accept(ssl) takes 200 ms?
Running as a windows service, written in c++, using MFC and Boost. Running on an intel xeon e5620 2.4G, with 4GB memory, and Win 7 Pro.
Following is my code. I meanwhile suspected that maybe other methods before SSL_accept (SSL_CTX_* RAND_* etc) might consume long time , but I logged everthing and discovered that SSL_accept is eating all the time.
int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
return preverify_ok;
}
void somemethod() {
SSL *ssl = 0;
SSL_CTX *tlsctx = 0;
int ret_conn = -1;
tlsctx = SSL_CTX_new( SSLv23_method());
SSL_CTX_use_certificate_file(tlsctx, sCert , SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(tlsctx, sKey , SSL_FILETYPE_PEM);
RAND_write_file(sRandomPem);
int _rand_loaded = RAND_load_file(sRandomPem, -1 );
if(! SSL_CTX_load_verify_locations(tlsctx, sCACert, NULL))
{
// TODO // /* Handle error here */
}
SSL_CTX_set_verify( tlsctx, SSL_VERIFY_PEER, verify_callback );
ssl = SSL_new(tlsctx);
int _error = SSL_ERROR_WANT_READ;
int loopCount = 0;
// START MEASURING TIME FROM HERE
SSL_set_fd(ssl, _sck);
while(ret_conn != 1 )
{
loopCount++;
ret_conn = SSL_accept(ssl);
_error = SSL_get_error(ssl, ret_conn);
switch (_error)
{
case SSL_ERROR_NONE:
break;
case SSL_ERROR_WANT_WRITE:
break;
case SSL_ERROR_WANT_READ:
break;
case SSL_ERROR_WANT_X509_LOOKUP:
break;
case SSL_ERROR_SYSCALL:
break;
case SSL_ERROR_SSL:
break;
case SSL_ERROR_ZERO_RETURN:
break;
}
if( _error == SSL_ERROR_WANT_READ || _error == SSL_ERROR_WANT_WRITE)
{
Sleep(1);
} else
{
break;
}
}
if( ret_conn < 1)
{
Log("SSL_accept -1 ", ERR_error_string(_error, NULL));
return;
}
// MEASURING END HERE, takes ~200ms (on successfully accepting connection)
}

To my knowledge, SSL_accept is a blocking function, which waits for your client to connect. If your client connect 200 ms later than the beginning for the SSL_accept call, then you will measure that waiting time.

Related

How can i accept RakNet Connecting request in c++?

I want accept client's connecting request but i don't know how can i do this.
Serverside :
enum GameMessages
{
ID_GAME_MESSAGE_1 = ID_USER_PACKET_ENUM + 1
};
using namespace std;
int main(void)
{
RakNet::RakPeerInterface *peer = RakNet::RakPeerInterface::GetInstance();
bool isServer;
RakNet::Packet *packet;
RakNet::SocketDescriptor sd(SERVER_PORT, 0);
peer->Startup(MAX_CLIENTS, &sd, 1);
isServer = true;
if (isServer)
{
printf("Sunucu baslatiliyor.\n");
// We need to let the server accept incoming connections from the clients
peer->SetMaximumIncomingConnections(MAX_CLIENTS);
}
while (1)
{
for (packet = peer->Receive(); packet; peer->DeallocatePacket(packet), packet = peer->Receive())
{
switch (packet->data[0])
{
case ID_REMOTE_DISCONNECTION_NOTIFICATION:
printf("Another client has disconnected.\n");
break;
case ID_REMOTE_CONNECTION_LOST:
printf("Another client has lost the connection.\n");
break;
case ID_REMOTE_NEW_INCOMING_CONNECTION:
printf("Another client has connected.\n");
break;
case ID_CONNECTION_REQUEST_ACCEPTED:
{
printf("Our connection request has been accepted.\n");
// Use a BitStream to write a custom user message
// Bitstreams are easier to use than sending casted structures, and handle endian swapping automatically
RakNet::BitStream bsOut;
bsOut.Write((RakNet::MessageID)ID_GAME_MESSAGE_1);
bsOut.Write("Oyuna hosgeldin emmolu.");
peer->Send(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
}
break;
case ID_NEW_INCOMING_CONNECTION:
printf("Bir baglanti geliyor.\n");
break;
case ID_NO_FREE_INCOMING_CONNECTIONS:
printf("The server is full.\n");
break;
case ID_DISCONNECTION_NOTIFICATION:
if (isServer) {
printf("A client has disconnected.\n");
}
else {
printf("We have been disconnected.\n");
}
break;
case ID_CONNECTION_LOST:
if (isServer) {
printf("A client lost the connection.\n");
}
else {
printf("Connection lost.\n");
}
break;
case ID_GAME_MESSAGE_1:
{
RakNet::RakString rs;
RakNet::BitStream bsIn(packet->data, packet->length, false);
bsIn.IgnoreBytes(sizeof(RakNet::MessageID));
bsIn.Read(rs);
printf("%s\n", rs.C_String());
}
break;
default:
printf("Message with identifier %i has arrived.\n", packet->data[0]);
break;
}
}
}
RakNet::RakPeerInterface::DestroyInstance(peer);
return 0;
}
When i try my work it's giving me .
[LOG]
Server : Server started.
Client : Sent request to connect server.
Server : A request received from client to connect server.
Server : Accept client's request. ( What i'm trying to do )

I have used WaitForSingleObject in C++ and its return value is "WAIT_OBJECT_0" all the time

The function WaitForSingleObject returns timeout flag("WAIT_OBJECT_0") in all cases.
Only for testing I have commented this line
(while((WaitForSingleObject(ovread.hEvent,timeout)==WAIT_OBJECT_0)))
and the comport responds as expected.
I have tried various timeouts including INFINITE.
Can someone tell me where the error could be occurring.
int timeout=500;
OVERLAPPED ovread;
memset(&ovread, 0, sizeof(ovread));
ovread.hEvent = CreateEvent( 0,true,0,0);
while((WaitForSingleObject(ovread.hEvent,timeout)==WAIT_OBJECT_0))
{
//Execute the following code
ReadFile(h,buf,sizeof(buf),&read,&ovread);
}
The reading logic should more or less use the following code flow:
int timeout = 500;
OVERLAPPED ovread = {0}
ovread.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (ovread.hEvent == NULL) {
// Error creating overlapped event; abort.
return FALSE;
}
if (!ReadFile(h, buf, sizeof(buf), &read, &ovread)) {
if (GetLastError() != ERROR_IO_PENDING) {
// Handle error in communications
}
else {
DWORD ret = WaitForSingleObject(ovread.hEvent,timeout);
switch (ret) {
case WAIT_OBJECT_0:
HandleASuccessfulRead(buf, read);
break;
case WAIT_TIMEOUT:
// Handle timeout
break;
case WAIT_FAILED:
// Handle failure
break;
default:
// what else to handle?
break;
}
}
}
else {
// read completed immediately
HandleASuccessfulRead(buf, read);
}

opening serial port and reading a data string

I have a weighbridge application that used to read from a Klerkscale SASCALE before and now it also needs to read from a LS210 Opticon weighbridge. I have added code to set the baud rates etc fot it as OPTI but Im still getting an error of" no response from the comm port" this error comes from the ERR00009 (if you look at the default part of the swith statement. Can anyone help me rectify the code please.
AnsiString TfrmWeighDetails::GetMass()
{
LONG lLastError = ERROR_SUCCESS;
bool flag;AnsiString s;
AnsiString port;
bool vTrapErrors, vIgnoreRecvEvent;
DM->vErrLineNo="GCS-21052008-70";
if ( Scale == "INVALID PORT")
{
return "ERR0011";
}
// Attempt to open the serial port (COM1)
lLastError = serial.Open(_T(Scale.c_str()),0,0,true);
MessageBox(NULL,AnsiString(lLastError).c_str(),"Privesh Test",MB_OK);
if (lLastError != ERROR_SUCCESS)
{
return "ERR0001";
}
// Setup the serial port (9600,8N1, which is the default setting)
// lLastError = serial.Setup(CSerial::EBaud9600,CSerial::EData8,CSerial::EParNone,CSerial::EStop1);
lLastError = serial.Setup(CSerial::EBaud19200,CSerial::EData8,CSerial::EParNone,CSerial::EStop1);
if (BridgeSupplier == "OPTO")
MessageBox(NULL,AnsiString(lLastError).c_str(),"Privesh Test1",MB_OK);
lLastError = serial.Setup(CSerial::EBaud19200,CSerial::EData8,CSerial::EParNone,CSerial::EStop1);
if (BridgeSupplier == "KLERKSCALE")
lLastError = serial.Setup(CSerial::EBaud2400,CSerial::EData7,CSerial::EParOdd,CSerial::EStop1);
else
lLastError = serial.Setup(CSerial::EBaud1200,CSerial::EData7,CSerial::EParEven,CSerial::EStop1);
if (lLastError != ERROR_SUCCESS)
{
return "ERR0002";
}
// Setup handshaking (default is no handshaking)
lLastError = serial.SetupHandshaking(CSerial::EHandshakeHardware);
MessageBox(NULL,AnsiString(lLastError).c_str(),"Handshake",MB_OK);
if (lLastError != ERROR_SUCCESS)
{
return "ERR0003";
}
// Register only for the receive event
lLastError = serial.SetMask(CSerial::EEventBreak |
CSerial::EEventCTS |
CSerial::EEventDSR |
CSerial::EEventError |
CSerial::EEventRing |
CSerial::EEventRLSD |
CSerial::EEventRecv);
MessageBox(NULL,AnsiString(lLastError).c_str(),"Receive Event",MB_OK);
if (lLastError != ERROR_SUCCESS)
{
return "ERR0004";
}
// Use 'non-blocking' reads, because we don't know how many bytes
// will be received. This is normally the most convenient mode
// (and also the default mode for reading data).
lLastError = serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);
MessageBox(NULL,AnsiString(lLastError).c_str(),"Setup Read Timeouts",MB_OK);
if (lLastError != ERROR_SUCCESS)
{
return "ERR0005";
}
// Create a handle for the overlapped operations
HANDLE hevtOverlapped = ::CreateEvent(0,TRUE,FALSE,0);;
if (hevtOverlapped == 0)
{
return "ERR0006";
}
// Setup the overlapped structure
OVERLAPPED ov = {0};
ov.hEvent = hevtOverlapped;
// Open the "STOP" handle
HANDLE hevtStop = ::CreateEvent(0,TRUE,FALSE,_T("Overlapped_Stop_Event"));
if (hevtStop == 0)
{
return "ERR0007" ;
}
// Keep reading data, until an EOF (CTRL-Z) has been received
bool fContinue = true;
do
{
// Wait for an event
lLastError = serial.WaitEvent(&ov);
MessageBox(NULL,AnsiString(lLastError).c_str(),"Serial Wait Event",MB_OK);
if (lLastError != ERROR_SUCCESS)
{
return "ERR0010";
}
// Setup array of handles in which we are interested
HANDLE ahWait[2];
ahWait[0] = hevtOverlapped;
ahWait[1] = hevtStop;
// Wait until something happens
switch (::WaitForMultipleObjects(sizeof(ahWait)/sizeof(*ahWait),ahWait,FALSE,timeout.ToInt()))
{
case WAIT_OBJECT_0:
{
// Save event
const CSerial::EEvent eEvent = serial.GetEventType();
// Handle break event
if (eEvent & CSerial::EEventBreak)
{
MessageBox(NULL," BREAK received ","Comm Program",MB_OK);
}
// Handle CTS event
if (eEvent & CSerial::EEventCTS)
{
flag = serial.GetCTS();
if (flag)
s = "ON";
else
s = "OFF";
MessageBox(NULL,(AnsiString("Clear to send ") + s).c_str(),"Comm Prog",MB_OK);
}
// Handle DSR event
if (eEvent & CSerial::EEventDSR)
{
flag = serial.GetDSR();
if (flag)
s = "ON";
else
s = "OFF";
MessageBox(NULL,(AnsiString("Data set ready ") + s).c_str(),"Comm Prog",MB_OK);
}
// Handle error event
vTrapErrors=false;
if ((eEvent & CSerial::EEventError)&&
(vTrapErrors)) // Although errors encountered, mass still read on XP OS. Therefore, errors suppressed on XP i.e.vTrapErrors=false - MZI12112007
{
//MessageBox(NULL,"### ERROR: ");
switch (serial.GetError())
{
case CSerial::EErrorBreak: MessageBox(NULL,"Break condition","Com Prog",MB_OK); break;
case CSerial::EErrorFrame: MessageBox(NULL,"Framing error","Com Prog",MB_OK); break;
case CSerial::EErrorIOE: MessageBox(NULL,"IO device error","Com Prog",MB_OK); break;
case CSerial::EErrorMode: MessageBox(NULL,"Unsupported mode","Com Prog",MB_OK); break;
case CSerial::EErrorOverrun: MessageBox(NULL,"Buffer overrun","Com Prog",MB_OK); break;
case CSerial::EErrorRxOver: MessageBox(NULL,"Input buffer overflow","Com Prog",MB_OK); break;
case CSerial::EErrorParity: MessageBox(NULL,"Input parity error","Com Prog",MB_OK); break;
case CSerial::EErrorTxFull: MessageBox(NULL,"Output buffer full","Com Prog",MB_OK); break;
// default: MessageBox(NULL,"Unknown","Com Prog",MB_OK); break; // Error 0 is UNKNOWN but is a Success error therefore no need to handle -- MZI12112007
}
//printf(" ###\n");
}
// Handle ring event
if (eEvent & CSerial::EEventRing)
{
Sleep(2000);
}
// Handle RLSD/CD event
if (eEvent & CSerial::EEventRLSD)
{
flag = serial.GetRLSD();
if (flag)
s = "ON";
else
s = "OFF";
MessageBox(NULL,(AnsiString("RLSD/CD ") + s).c_str(),"Comm Prog",MB_OK);
}
Timer1->Enabled = false; //switch off the timeout
// Handle data receive event
Sleep (1000); // when no pause, no mass read on XP. Therefore, this ensures system gets in sync with Comm Device - MZI12112007
vIgnoreRecvEvent=true; // On XP, the Receive event does not seem to be triggered. Therefore this code was included to forcce WBR to work on Xp -- MZI12112007
if ((eEvent & CSerial::EEventRecv)||vIgnoreRecvEvent)
{
// Read data, until the reading from scale is stable
DWORD dwBytesRead = 0;
do
{
char szBuffer[101];
// Read data from the COM-port
lLastError = serial.Read(szBuffer,sizeof(szBuffer)-1,&dwBytesRead);
if (lLastError != ERROR_SUCCESS)
{
ShowError(serial.GetLastError(), _T("Unable to read from COM-port."));
return "ERR0008";
}
if (dwBytesRead > 0)
{
// Finalize the data, so it is a valid string
szBuffer[dwBytesRead] = '\0';
AnsiString result = GetStableReading(szBuffer,BridgeSupplier);
// Display the data
if ( result == "OVERCAPACITY" || result == "BELOWCAPACITY")
{
serial.Close();
return result;
}
else if ( result != "ERROR" && result != "")
{
serial.Close();
return result;
}
}
}
while ((dwBytesRead > 0 )&&(result == ""));
}
}
break;
case WAIT_OBJECT_0+1:
{
// Set the continue bit to false, so we'll exit
fContinue = false;
}
break;
default:
{
//No response from comm port
serial.Close();
return "ERR0009";
}
}
}
while (fContinue);
// Close the port again
serial.Close();
}
Please add more curly braces to the code to separate different choices, like this:
if (BridgeSupplier == "OPTO") {
MessageBox(NULL,AnsiString(lLastError).c_str(),"Privesh Test1",MB_OK);
lLastError = serial.Setup(CSerial::EBaud19200,CSerial::EData8,CSerial::EParNone,CSerial::EStop1);
} else if (BridgeSupplier == "KLERKSCALE") {
lLastError = serial.Setup(CSerial::EBaud2400,CSerial::EData7,CSerial::EParOdd,CSerial::EStop1);
} else {
lLastError = serial.Setup(CSerial::EBaud1200,CSerial::EData7,CSerial::EParEven,CSerial::EStop1);
}
because currently your code setups the port for OPTO and then sets the port again for the default "else" condition, overwriting the setup for OPTO.

how to find the MAC address of another computer (client server)?

i am trying to get the MAC address of another computer using a server and client program in c++ using UDP connections. The server is on one computer (it contains 2 listboxes, 1 for the IP addresses of connected clients, the other for the MAC address) the client is on another computer. my current code only gets the MAC address if i run the server and client and the same computer. When i debug the program i see that when trying to get the MAC address of another computer the program doesn't go into the if statement and run the line PrintMACaddress(pAdapterInfo->Address);
void CmfcServerDlg:: PrintMACFromIP(const CString &selected_ip_adr)
{
IP_ADAPTER_INFO AdapterInfo[16];
DWORD dwBufLen = sizeof(AdapterInfo);
DWORD dwStatus = GetAdaptersInfo(
AdapterInfo,
&dwBufLen);
assert(dwStatus == ERROR_SUCCESS);
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;// Contains pointer to current adapter info
bool found = false;
do {
const IP_ADDR_STRING *addr_str = &pAdapterInfo->IpAddressList;
if (addr_str != NULL)
{
if (selected_ip_adr == addr_str->IpAddress.String)
{
PrintMACaddress(pAdapterInfo->Address);
}
}
pAdapterInfo = pAdapterInfo->Next;
}
while(pAdapterInfo);
}
i found that using the ARP function may help with this or since the MAC address is data i may transmit it as a string or raw data but i have idea how to this
here is the PrintMAC function:
void CmfcServerDlg::PrintMACaddress(unsigned char MACData[])
{
CString strText;
strText.Format("%02X-%02X-%02X-%02X-%02X-%02X\n",MACData[0], MACData[1], MACData[2], MACData[3], MACData[4], MACData[5]);
m_ClientIdList.AddString(strText);
}
The GetAdaptersInfo function only returns the addresses of the adapters attached to the local computer. You should take a look to SendARP.
EDIT: Try this:
void CmfcServerDlg::PrintMACFromIP(const CString &selected_ip_adr)
{
DWORD dwRetVal;
IPAddr DestIp = 0;
IPAddr SrcIp = 0; /* default for src ip */
ULONG MacAddr[2]; /* for 6-byte hardware addresses */
ULONG PhysAddrLen = 6; /* default to length of six bytes */
char *SrcIpString = NULL;
BYTE *bPhysAddr;
DestIp = inet_addr(CT2A(selected_ip_adr));
memset(&MacAddr, 0xff, sizeof (MacAddr));
dwRetVal = SendARP(DestIp, SrcIp, &MacAddr, &PhysAddrLen);
if (dwRetVal == NO_ERROR) {
bPhysAddr = (BYTE *) & MacAddr;
if (PhysAddrLen) {
CString theMac;
theMac.Format(_T("%.2X-%.2X-%.2X-%.2X-%.2X-%.2X"), (int) bPhysAddr[0],
(int) bPhysAddr[1],(int) bPhysAddr[2],(int) bPhysAddr[3],(int) bPhysAddr[4],
(int) bPhysAddr[5]);
PrintMACaddress(theMac);
} else
printf
("Warning: SendArp completed successfully, but returned length=0\n");
} else {
printf("Error: SendArp failed with error: %d", dwRetVal);
switch (dwRetVal) {
case ERROR_GEN_FAILURE:
printf(" (ERROR_GEN_FAILURE)\n");
break;
case ERROR_INVALID_PARAMETER:
printf(" (ERROR_INVALID_PARAMETER)\n");
break;
case ERROR_INVALID_USER_BUFFER:
printf(" (ERROR_INVALID_USER_BUFFER)\n");
break;
case ERROR_BAD_NET_NAME:
printf(" (ERROR_GEN_FAILURE)\n");
break;
case ERROR_BUFFER_OVERFLOW:
printf(" (ERROR_BUFFER_OVERFLOW)\n");
break;
case ERROR_NOT_FOUND:
printf(" (ERROR_NOT_FOUND)\n");
break;
default:
printf("\n");
break;
}
}
}
void CmfcServerDlg::PrintMACaddress(CString& strText)
{
m_ClientIdList.AddString(strText);
}

My service won't stop

Whenever I try to stop my service through the services manager, I get the following error and the service stays in a started state. "Could not stop the service on Local Computer. The service did not return an error. This could be an internal Windows error or an internal service error."
I've had such trouble with this issue that I tried to follow the logic from Microsoft as best as I could.
http://msdn.microsoft.com/en-us/library/windows/desktop/bb540474(v=vs.85).aspx
There is a similar issue with this in .Net 1.1 that you'll find if you search; however, I'm not using the framweork at all.
void WINAPI serviceCtrlHandler(DWORD dwCtrl )
{
switch(dwCtrl)
{
case SERVICE_CONTROL_STOP:
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
SetEvent(stopEvent);
ReportSvcStatus(serviceStatus->dwCurrentState, NO_ERROR, 0);
return;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
}
void WINAPI startMain(DWORD argc, LPTSTR *argv)
{
serviceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, serviceCtrlHandler);
serviceStatus->dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus->dwServiceSpecificExitCode = NO_ERROR;
if (serviceStatusHandle == 0)
{
debug->DebugMessage(L"RegisterServiceCtrlHandler() failed, error: " + Error::GetErrorMessageW(GetLastError()));
return;
}
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
if (!SetServiceStatus(serviceStatusHandle, serviceStatus))
{
//debug->DebugMessage(L"SetserviceStatus() failed, error: " + Error::GetErrorMessageW(GetLastError()));
//return;
}
stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
boost::thread dust_main_thread(dust_main);
while(1)
{
WaitForSingleObject(stopEvent, INFINITE);
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
return;
}
}
VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
serviceStatus->dwCurrentState = dwCurrentState;
serviceStatus->dwWin32ExitCode = dwWin32ExitCode;
serviceStatus->dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
serviceStatus->dwControlsAccepted = 0;
else serviceStatus->dwControlsAccepted = SERVICE_ACCEPT_STOP;
if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED))
serviceStatus->dwCheckPoint = 0;
else
serviceStatus->dwCheckPoint = dwCheckPoint++;
SetServiceStatus(serviceStatusHandle, serviceStatus);
}
Run the service and then attach the debugger to the running process. Put a breakpoint at the serviceCtrlHandler and after the WaitForSingleObject(stopEvent, INFINITE) -- make sure what you think should happen does.