modem call in c++ - c++

I'm trying to make a modem call in one end, and in the other end the program answers the call. It doesn't seem to detect the carrier. Am I doing anything wrong? Am I missing something?
int main(int argc, char** argv)
{
ParseArgs(argc,argv);
SerialPort* port = SerialPort::New();
if(!port)
Error(ErrorNoMemory,"Can't create port");
int error = port->Open(PortNum, SendFlag);
if(error)
Error(error,"Can't open port");
error = port->Initialise(PortBaud);
if(error)
Error(error,"Can't initialise port");
if(ReceiveFlag)
{
port->Listen();
Receive(port); //after the call is stablished I send a file
}
else
{
port->Dial(PhoneNumber);
Send(port);
}
port->Close();
delete port;
return 0;
}
The part of opening the port:
int Open(unsigned port, bool SendFlag)
{
// make name for port...
char name[] = "\\\\.\\com???.???";
char* nameNumber = name+sizeof(name)-8;
char* nameEnd = nameNumber;
if(port>999){
return ErrorInvalidPort;
}
if(port>99)
{
*nameEnd++ = '0'+port/100;
port %= 100;
}
if(port>9)
{
*nameEnd++ = '0'+port/10;
port %= 10;
}
*nameEnd++ = '0'+port;
*nameEnd = 0;
// open port...
hSerial = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(hSerial==INVALID_HANDLE_VALUE)
{
switch(GetLastError())
{
case ERROR_FILE_NOT_FOUND:
return ErrorInvalidPort;
case ERROR_ACCESS_DENIED:
return ErrorPortInUse;
default:
return Error();
}
}
SetupComm( hSerial, 1024, 1024 );
if (!SendFlag)
{
if (!SetCommMask(hSerial, EV_RING |EV_RLSD))
// Error setting communications mask
printf("error mascara");
}
else
{
if (!SetCommMask(hSerial, EV_RLSD))
{
// Error setting communications mask
printf("error mascara");
}
}
return 0;
}
The initialise part:
int Initialise(unsigned baud)
{
// flush port...
if(!FlushFileBuffers(hSerial))
return Error();
if(!PurgeComm(hSerial, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR))
return Error();
// configure port...
DCB dcb ;
if(!GetCommState(hSerial, &dcb))
return Error();
dcb.BaudRate = CBR_115200;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
if(!SetCommState(hSerial, &dcb))
{
if(GetLastError()==ERROR_INVALID_PARAMETER)
return ErrorInvalidSettings;
return Error();
}
// set timeouts to zero so read/writes return immediately...
COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier= 0;
if(!SetCommTimeouts(hSerial, &timeouts))
return Error();
// flush port again...
if(!PurgeComm(hSerial, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR))
return Error();
return 0;
}
The dial part:
int Dial(char *telefono)
{
unsigned long int n = 0;
DWORD dwCommEvent;
DWORD bytes;
DWORD dwRead;
char cadena[15];
char chRead;
sprintf(cadena, "ATDT%s\r", telefono);
if (!WriteFile( hSerial, "ATH1\r", strlen("ATH1\r"), (&(n)), 0 ))
{
printf("error");
}
FlushFileBuffers( hSerial );
Sleep(1000);
if (!WriteFile( hSerial, cadena, strlen(cadena), (&(n)), 0))
{
printf("error");
}
FlushFileBuffers( hSerial );
Sleep(10000);
printf("Marcamos");
do
{
printf("Espero eventos");
if(WaitCommEvent(hSerial, &dwCommEvent, NULL))
{
if(dwCommEvent & EV_RLSD)
{
printf("rlsd");
break;
}
else
{
printf("otro");
}
}
printf("fin del bucle");
} while(true);
return 0;
}
The listening part:
int Listen()
{
DWORD dwCommEvent;
unsigned long int n = 0;
do
{
printf("ESpero eventos");
if(WaitCommEvent(hSerial, &dwCommEvent, NULL))
{
if(dwCommEvent & EV_RING)
{
printf("RING");
if (!WriteFile( hSerial, "ATA\r", strlen("ATA\r"), (&(n)), 0 ))
{
printf("error");
}
FlushFileBuffers( hSerial );
break;
}
else if (dwCommEvent & EV_RLSD )
{
break;
}
}
printf("fin del bucle");
} while(true);
return 0;
}

You might have an easier time of it using Microsoft's Telephony API (TAPI) rather than trying to talk to the modem directly.

You may want to try issuing an ATS0=1 on the receiving side and let the modem autoanswer (substitute the number of rings you want instead of 1 if you wish).
You may discover that smart modems don't always pass through the ring (EV_RING) signal.
EDIT: Don't forget to 'ATS0=0' when you don't want the modem to auto-answer any more.

Maybe you need to apply the A0 and / or S0=1 Hayes command on the answering side.

Related

Port COM Handling in C++ cause Watchdog Violation

I'm writing an application for handling communication with the device by COM port.
For it I use ReadFile() from <windows.h>, as I had some problems with synchronous use, I tried overlapped implementation from http://www.egmont.com.pl/addi-data/instrukcje/standard_driver.pdf
And from what I understand for constant reading (to not lose any data sent by device), I need to call that reading func in a separate thread in infinite while() - I created some class for handling that and it's working perfectly, but after some random amount of time it's causing bluescreen DPC WATCHDOG VIOLATION unfortunately, I can't tell any specific event that may cause this :(
#edit1
I should add that's if I use some other program for COM communication, like Termite or TerraTerm it's working with no problems.
PortHandling.cpp (basically copy of that's overlapped implementation) :
#define OVERLAPPED_READ_TIMEOUT 1
PortHandling::PortHandling()
{
this->portHandle = INVALID_HANDLE_VALUE;
this->done = false;
this->portSelected = "";
this->baudRate = 0;
}
void PortHandling::ClearPort()
{
if (this->done)
{
this->done = false;
PurgeComm(this->portHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
CloseHandle(this->portHandle);
std::cout << "[E] Disconnected from port " << this->portSelected << std::endl;
}
}
bool PortHandling::SetPortProp(std::string portName, int baudRate, int maxReadSize, int maxWriteSize)
{
this->portSelected = portName;
this->portHandle = CreateFileA(("\\\\.\\" + this->portSelected).c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (this->portHandle == INVALID_HANDLE_VALUE)
{
std::cout << "[E] Connecting to port failed - Port occupied" << std::endl;
this->portSelected = "";
return false;
}
SetupComm(this->portHandle, maxReadSize, maxWriteSize); // The size of input buffer and output buffer
COMMTIMEOUTS timeOuts;
timeOuts.ReadIntervalTimeout = 3; //Set read timeout
timeOuts.ReadTotalTimeoutMultiplier = 1;
timeOuts.ReadTotalTimeoutConstant = 3;
timeOuts.WriteTotalTimeoutMultiplier = 0; // Set write timeout
timeOuts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(this->portHandle, &timeOuts); // Set timeout
DCB dcb;
GetCommState(this->portHandle, &dcb);
dcb.BaudRate = baudRate; /* Baudrate at which running */
dcb.fBinary = 1; /* Binary Mode (skip EOF check) */
dcb.fParity = 0; /* Enable parity checking */
dcb.fOutxCtsFlow = 0; /* CTS handshaking on output */
dcb.fOutxDsrFlow = 0; /* DSR handshaking on output */
dcb.fDtrControl = DTR_CONTROL_ENABLE; /* DTR Flow control */
dcb.fDsrSensitivity = 0; /* DSR Sensitivity */
dcb.fTXContinueOnXoff = 1; /* Continue TX when Xoff sent */
dcb.fOutX = 0; /* Enable output X-ON/X-OFF */
dcb.fInX = 0; /* Enable input X-ON/X-OFF */
dcb.fErrorChar = 1; /* Enable Err Replacement */
dcb.fNull = 1; /* Enable Null stripping */
dcb.fRtsControl = RTS_CONTROL_DISABLE; /* Rts Flow control */
dcb.ByteSize = 8; /* Number of bits/byte, 4-8 */
dcb.Parity = NOPARITY; /* 0-4 = None,Odd,Even,Mark,Space */
dcb.StopBits = ONESTOPBIT; /* 0,1,2 = 1, 1.5, 2 */
dcb.XonChar; /* Tx and Rx X-ON character */
dcb.XoffChar; /* Tx and Rx X-OFF character */
dcb.ErrorChar; /* Error replacement char */
dcb.EofChar; /* End of Input character */
dcb.EvtChar; /* Received Event character */
SetCommState(this->portHandle, &dcb);
PurgeComm(this->portHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
this->done = true;
std::cout << "[I] Connecting to port " << this->portSelected << " succeeded" << std::endl;
return true;
}
//#brief
//param size - Maximal read size, may be shorter if read is waiting for longer than set timeout (10ms)
//param buffer - Buffer into witch read data is saved
//param onRead - Function that is called on succesfull read
DWORD PortHandling::ReadFromPort(int size, char *buffer, std::function<void()> onRead)
{
DWORD dwRead = 0;
DWORD dwRes = 0;
BOOL fWaitingOnRead = FALSE;
OVERLAPPED osReader = {0};
// Create the overlapped event. Must be closed before exiting to avoid a handle leak.
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL)
{
std::cout << "[E] Error in communication, overlapped construction failed" << std::endl;
return dwRead;
}
if (!fWaitingOnRead)
{
// Issue read operation.
if (!ReadFile(this->portHandle, buffer, size, &dwRead, &osReader))
{
if (GetLastError() != ERROR_IO_PENDING) // read not delayed?
{
std::cout << "[E] Error in communication (read:1)" << std::endl;
} else
{
fWaitingOnRead = TRUE;
}
} else
{
// read completed immediately
}
}
if (fWaitingOnRead)
{
dwRes = WaitForSingleObject(osReader.hEvent, OVERLAPPED_READ_TIMEOUT);
switch (dwRes)
{
// Read completed.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(this->portHandle, &osReader, &dwRead, FALSE))
{
std::cout << "[E] Error in communication (read:2)" << std::endl;
} else
{
// Read completed successfully.
}
// Reset flag so that another opertion can be issued.
fWaitingOnRead = FALSE;
break;
case WAIT_TIMEOUT:
// Operation isn't complete yet. fWaitingOnRead flag isn't
// changed since I'll loop back around, and I don't want
// to issue another read until the first one finishes.
// This is a good time to do some background work.
break;
default:
// Error in the WaitForSingleObject; abort.
// This indicates a problem with the OVERLAPPED
// structure's event handle
std::cout << "[E] Error in communication, overlapped construction failed" << std::endl;
return dwRead;
}
}
if (strlen(buffer) > 0)
{
onRead();
}
return dwRead;
}
//#brief
//param size - Size of written message
//param buffer - Buffer from witch data is send
//param onWrite - Function that is called on succesfull write
bool PortHandling::WriteToPort(int size, const char *buffer, std::function<void()> onWrite)
{
OVERLAPPED osWrite = {0};
DWORD dwWritten = 0;
DWORD dwRes = 0;
BOOL fRes = FALSE;
// Create this writes OVERLAPPED structure hEvent.
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL)
{
std::cout << "[E] Error in communication, overlapped construction failed" << std::endl;
return FALSE;
}
// Issue write.
if (!WriteFile(this->portHandle, buffer, size, &dwWritten, &osWrite))
{
if (GetLastError() != ERROR_IO_PENDING)
{
// WriteFile failed, but it isn't delayed. Report error and abort.
std::cout << "[E] Error in communication (write:1)" << std::endl;
fRes = FALSE;
} else
{
// Write is pending.
dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
switch (dwRes)
{
// OVERLAPPED structure's event has been signaled.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(this->portHandle, &osWrite, &dwWritten, FALSE))
{
std::cout << "[E] Error in communication (write:2)" << std::endl;
fRes = FALSE;
} else
{
// Write operation completed successfully.
fRes = TRUE;
onWrite();
}
break;
default:
// An error has occurred in WaitForSingleObject.
// This usually indicates a problem with the
// OVERLAPPED structure's event handle.
std::cout << "[E] Error in communication (write:3)" << std::endl;
fRes = FALSE;
break;
}
}
} else
{
// WriteFile completed immediately.
fRes = TRUE;
onWrite();
}
CloseHandle(osWrite.hEvent);
return fRes;
}
My class for handling that,
PortOperator.cpp
bool PortOperator::Construct(std::string portName, int baudRate, int maxReadSize, int maxWriteSize)
{
this->portName = portName;
this->baudRate = baudRate;
this->maxReadSize = maxReadSize;
this->maxWriteSize = maxWriteSize;
this->cRead = new char[maxReadSize];
memset(cRead, 0, this->maxReadSize);
this->cWrite = new char[maxWriteSize];
memset(cWrite, 0, this->maxWriteSize);
if (this->PortHandler.SetPortProp(portName, baudRate, maxReadSize, maxWriteSize))
{
// if connection succesfull, start Reading in the background
this->Reading = std::thread(&PortOperator::ReadingThread, this);
} else
{
static ftor_DeltaTime reconnect_timeout = ftor_DeltaTime();
int n = 0;
while (true)
{
// try reconnecting to port each second, max 5 tries
if (reconnect_timeout(TimeUnits::SECONDS) >= 1)
{
n++;
if (this->PortHandler.SetPortProp(portName, baudRate, maxReadSize, maxWriteSize))
{
// if connection succesfull, start Reading in the background
this->Reading = std::thread(&PortOperator::ReadingThread, this);
break;
}
if (n > 5)
{
return false;
}
reconnect_timeout.Reset();
}
}
}
return true;
}
void PortOperator::ReadingThread()
{
this->notReciving = ftor_DeltaTime();
char *buffer = new char[this->maxReadSize];
while (true)
{
memset(buffer, 0, this->maxReadSize);
//make sure the thread is stopped when port disconnect
if (!this->PortHandler.done)
{
break;
}
this->PortHandler.ReadFromPort(this->maxReadSize, buffer,
[&]() {
//block executed only when there's some data read (not empty)
if (ConsolePreview)
{
std::cout << buffer;
}
mtx_cRead.lock();
strcpy(this->cRead, buffer);
mtx_cRead.unlock();
readFlag = 1;
cv.notify_all();
notReciving.Reset();
});
}
}
std::string PortOperator::Write(std::string command)
{
std::mutex mtx_cv;
std::unique_lock<std::mutex> write_lck(mtx_cv);
std::string response = "";
this->PortHandler.WriteToPort(command.length(), command.c_str(), []() {});
if (cv.wait_for(write_lck, std::chrono::milliseconds(45)) == std::cv_status::no_timeout)
{
response = cRead;
}
return response;
}
bool PortOperator::Reconnect()
{
this->Disconnect();
return this->Construct(this->portName, this->baudRate, this->maxReadSize, this->maxWriteSize);
}
bool PortOperator::Disconnect()
{
//first clear port connection to stop thread, and then join
this->PortHandler.ClearPort();
if (Reading.joinable())
{
Reading.join();
}
return true;
}
long long int PortOperator::SilenceTime(TimeUnits t)
{
return this->notReciving(t);
}
std::vector<std::string> PortOperator::GetPorts()
{
std::vector<std::string> portsCOM;
//try connecting with each port to check which are avaiable
for (int i = 0; i <= 256; i++)
{
std::string portName = "COM" + std::to_string(i);
if (this->CheckPort(portName))
{
portsCOM.push_back(portName.c_str());
}
}
//if there's no avaiable port add "-" to vector
if (portsCOM.size() == 0)
{
portsCOM.push_back(" - ");
}
return portsCOM;
}
bool PortOperator::CheckPort(std::string portName)
{
//try connecting with given port
HANDLE serialHandle;
serialHandle = CreateFileA(("\\\\.\\" + portName).c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (serialHandle == INVALID_HANDLE_VALUE)
{
return false;
}
CloseHandle(serialHandle);
return true;
}
I'm not the best programmer, if something hurt your eyes please tell me...
Thanks for your time :D

multi-serial port communication on windows

I am working on a project which need to operate two serial port as the same time on windows, but whatever I try I can only open one serial port. Unless repeat open and close, I can operate the two ports but it is too slow. I need to write and read first port and formalize it by protocol and sent it to another port, but I can not initial two port. I was using open and close two ports repeatly to do that before but it was toooooooo slow. Anybody know how to open two port in the same time; Thx!!!
here are my code here:
#include <iostream>
#include <iomanip>
#include "udp.h"
#include "Serial.h"
#include "Formalized.h"
using namespace std;
bool sthread = false;
unsigned char status[6] = {};
HANDLE hMutex = NULL;
DWORD WINAPI ULTRAread(LPVOID lpParamter)
{
Cserial ultra;
unsigned char input0[7] = { 0x00,0x01,0x00,0x01,0x01,0xE5,0xAC };
unsigned char input1[7] = { 0x00,0x02,0x00,0x01,0x01,0xE5,0xE8 };
unsigned char input2[7] = { 0x00,0x03,0x00,0x01,0x01,0xE4,0x14 };
unsigned char input3[7] = { 0x00,0x04,0x00,0x01,0x01,0xE5,0x60 };
unsigned char input4[7] = { 0x00,0x05,0x00,0x01,0x01,0xE4,0x9C };
unsigned char input5[7] = { 0x00,0x06,0x00,0x01,0x01,0xE4,0xD8 };
unsigned char* input[6] = { input0,input1,input2,input3,input4,input5 };
unsigned char pool[8] = {};
if (!ultra.Initcom("COM10")) //ultrasonic COM interface
{
cout << "Init ultrasonic failure \n";
getchar();
sthread = false;
}
else
{
sthread = true;
for (;;)
{
WaitForSingleObject(hMutex, INFINITE);
for (int i = 0; i < 6; i++)
{
if (ultra.Write(input[i], 7))
{
ultra.Read(pool, 8);
}
switch (pool[5])
{
case 0x01:
status[i] = 0x01;
break;
case 0x00:
status[i] = 0x00;
break;
}
}
Sleep(5000);
ReleaseMutex(hMutex);
}
}
}
int main()
{
HANDLE uThread = CreateThread(NULL, 0, ULTRAread, NULL, 0, NULL);
hMutex = CreateMutex(NULL, FALSE, "ultrasonics status");
Cserial zigbee;
cUDP UWB;
char buff[300];
char data[256];
if (!UWB.Initial(6685)) //latitude and longitude port
{
cout << "UWB Port connecting failure \n";
getchar();
}
else
{
cout << "UWB Com connecting success \n";
}
if (!zigbee.Initcom("COM7")) //zigbee access port
{
cout << "Zigbee Initial Failure! \n";
getchar();
}
else
{
cout << "Zigbee Initial Success! \n";
}
for (;;)
{
WaitForSingleObject(hMutex, INFINITE);
switch (sthread)
{
case TRUE: //ultrasonics trustful
WaitForSingleObject(hMutex, INFINITE);
cout << "1";
ReleaseMutex(hMutex);
break;
case FALSE:
cout << "2";
break;
}
Sleep(5000);
}
CloseHandle(uThread);
getchar();
return 0;
}
#include"Serial.h"
Cserial::Cserial()
{
hcom = INVALID_HANDLE_VALUE;
}
Cserial::~Cserial()
{
}
bool Cserial::Initcom(LPCSTR Port)
{
hcom = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL, 0);
if (hcom == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "fail serial1\n");
return false;
}
SetupComm(hcom, 1024, 1024);
DCB dcb;
GetCommState(hcom, &dcb);
dcb.BaudRate = 9600;
dcb.ByteSize = 8;
dcb.Parity = 0;
dcb.StopBits = 1;
SetCommState(hcom, &dcb);
COMMTIMEOUTS CommTimeouts;
GetCommTimeouts(hcom, &CommTimeouts);
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 10;
CommTimeouts.ReadTotalTimeoutConstant = 100;
CommTimeouts.WriteTotalTimeoutMultiplier = 1;
CommTimeouts.WriteTotalTimeoutConstant = 10;
if (!SetCommTimeouts(hcom, &CommTimeouts))
{
fprintf(stderr, "fail serial2\n");
return FALSE;
}
return true;
}
void Cserial::Uninitcom()
{
CloseHandle(hcom);
hcom = INVALID_HANDLE_VALUE;
}
bool Cserial::Clearcom()
{
PurgeComm(hcom, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT);
return TRUE;
}
bool Cserial::Write(unsigned char* buf, int len)
{
if (hcom == INVALID_HANDLE_VALUE)
{
return FALSE;
}
DWORD dwWrittenLen = 0;
if (!WriteFile(hcom, buf, len, &dwWrittenLen, NULL))
{
return FALSE;
}
else
{
return TRUE;
}
}
bool Cserial::Read(unsigned char* buf, int len)
{
DWORD dwReadLen = 0;
if (hcom == INVALID_HANDLE_VALUE)
{
return FALSE;
}
if (!ReadFile(hcom, buf, len, &dwReadLen, NULL))
{
return FALSE;
}
else
{
return TRUE;
}
}

Com Port C++ read 0xFF

I'm trying to read/write from a com port.
When I open the Com Port I make it Non overlapped.
Everything works fine, but when I read a 0xFF byte it sees it like an EOF and finishes the read.
Can I make a Non overlapped read 0xFF?
Here is my code:
//Opening the com port:
hComm = CreateFile( s.c_str(), // COM PORT
GENERIC_READ | GENERIC_WRITE, //
0, // exclusive access
NULL, // no security
OPEN_EXISTING, // must be a port
0 , // async i/o
NULL); //
//Port init:
void initPort(int baud)
{
uart_baud = baud;
DCB dcb;
dcb.DCBlength = sizeof(DCB);
GetCommState(hComm, &dcb); // read current config
dcb.BaudRate = baud;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
dcb.fParity = FALSE;
SetCommState(hComm, &dcb);
}
//Reading:(PS: private: char rx_packet[1024]; int rx_size;)
int readByte(int timeout)
{
COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = 1;
CommTimeOuts.ReadTotalTimeoutMultiplier = timeout;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hComm, &CommTimeOuts);
char byte;
DWORD bytes = 0;
if (ReadFile(hComm, &byte, 1, &bytes, NULL))
{
return bytes == 1 ? byte : -1;
}
return -1;
}
void readPacket(void)
{
int data_read;
bool first_read = true;
rx_size = 0;
DWORD dwEventMask;
DWORD ERR = 0;
if (!SetCommMask(hComm, EV_RXCHAR)) return;
if (!WaitCommEvent(hComm, &dwEventMask, NULL)) return;
while (rx_size < MAX_PACKET_SIZE)
{
data_read = readByte(first_read ? 200 : 50);
first_read = false;
if (data_read == -1)return;
rx_packet[rx_size] = (char)data_read;
rx_size++;
}
}
//Writing port:
bool writeByte(char byte)
{
DWORD bytes = 0;
WriteFile(hComm, &byte, 1, &bytes, NULL);
return bytes == 1 ? true : false;
}
void RvcCommUART::writePacket(BYTE *data , UINT16 size)
{
int tx_index = 0;
while (tx_index < size)
{
if (writeByte(data[tx_index]) == false) return;
tx_index++;
}
}
It seems that your char is signed (its signedness is implementation-dependent), so 0xFF is -1.
Use unsigned char to represent "bytes".

winhttp client and openssl server communication error

I have encounted a strange communication problem when using winhttp to program http client and using openssl to program http server.
I use wireshark to analyze the communication. Everything seems ok when handshake between the two, and the handshake procedure is really quick. But after the handshake, winhttp client taken a really long time send a http request, then server received the request (the received packet is right) then server attempted to send response with ssl_write, but client cannot receive this packet.
please see notes in my code for advanced info.
Below is client's main communication code.
BOOL CHttpClient :: _Synchronize(BYTE* pbRequest, DWORD dwRequestCb,
BYTE** pbResponse, DWORD* dwResponseCb)
{
DWORD dwErrorCode = 0;
DWORD dwStatusCode = 0;
DWORD dwSize = sizeof(DWORD);
DWORD dwLastStatusCode = 0;
BOOL bDone = FALSE;
if (FALSE == DoConnectAndOpenRequest(dwRequestCb == 0))
{
return FALSE;
}
while (!bDone)
{
if (!WinHttpSendRequest(m_hRequest, NULL, 0, pbRequest, dwRequestCb, dwRequestCb, NULL))
{
dwErrorCode = GetLastError();
switch (dwErrorCode)
{
case ERROR_WINHTTP_CANNOT_CONNECT:
case ERROR_WINHTTP_TIMEOUT:
m_dwDefaultAddrIndex = (m_dwDefaultAddrIndex + 1) % m_lpConfig->dwHttpAddrNum;
case ERROR_WINHTTP_CONNECTION_ERROR:
if (FALSE == DoConnectAndOpenRequest(dwRequestCb == 0))
{
return FALSE;
}
continue;
case 12175:
continue;
case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
continue;
default:
return FALSE;
}
}
// client always wait here for server's response and get a error code as 12002--ERROR_INTERNET_TIMEOUT
if (!WinHttpReceiveResponse(m_hRequest, NULL))
{
dwErrorCode = GetLastError(); // get error code 12002--ERROR_INTERNET_TIMEOUT
switch (dwErrorCode)
{
case ERROR_WINHTTP_RESEND_REQUEST:
continue;
case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
continue;
default:
if (FALSE == DoConnectAndOpenRequest(dwRequestCb == 0))
{
return FALSE;
}
continue;
}
}
if (!DoServerAuth())
{
m_dwDefaultAddrIndex = (m_dwDefaultAddrIndex + 1) % m_lpConfig->dwHttpAddrNum;
if (FALSE == DoConnectAndOpenRequest(dwRequestCb == 0))
{
return FALSE;
}
continue;
}
if (!WinHttpQueryHeaders(m_hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
NULL, &dwStatusCode, &dwSize, NULL))
{
return FALSE;
}
switch (dwStatusCode)
{
// success
case 200:
bDone = TRUE;
break;
// proxy need authentication
case 407:
if (dwLastStatusCode == 407)
{
bDone = TRUE;
}
else if (!DoProxyAuth())
return FALSE;
break;
default:
return FALSE;
}
dwLastStatusCode = dwStatusCode;
}
DWORD dwBytesAvailable = 0;
DWORD dwBytesTransfered = 0;
BYTE* pbTmpBuf = new BYTE [GetMaxTransferCb()];
// read http server reply
*dwResponseCb = 0;
do
{
if (!WinHttpQueryDataAvailable(m_hRequest, &dwBytesAvailable))
{
return FALSE;
}
if (!WinHttpReadData(m_hRequest, pbTmpBuf + *dwResponseCb, dwBytesAvailable,
&dwBytesTransfered))
{
return FALSE;
}
*dwResponseCb += dwBytesTransfered;
} while (dwBytesAvailable > 0);
*pbResponse = new BYTE [*dwResponseCb];
memcpy(*pbResponse, pbTmpBuf, *dwResponseCb);
RELEASE_ARRAY(pbTmpBuf);
// all done
return TRUE;
}
BOOL CHttpClient :: DoConnectAndOpenRequest(BOOL bGetVerb)
{
BOOL bOK = FALSE;
DWORD dwReqObjNameCch = (DWORD)rand() % (20 - 5) + 5;
BYTE* lpReqObjName = new BYTE [(dwReqObjNameCch + 6) * sizeof(TCHAR)];
DWORD dwOptionCode = 0;
__try
{
// release old handles
RELEASE_HINTERNET(m_hConnect);
RELEASE_HINTERNET(m_hRequest);
// connect to default address, change of default address is not my duty
if (NULL == (m_hConnect = WinHttpConnect(m_hSession,
m_lpConfig->lpHttpAddrs[m_dwDefaultAddrIndex].tszAddr,
m_lpConfig->lpHttpAddrs[m_dwDefaultAddrIndex].wPort, 0)))
__leave;
// random generate request object name
// now this method is slow and bad, we can improve later
if (!CryptGenRandom(m_hCryptProv, dwReqObjNameCch * sizeof(TCHAR), lpReqObjName))
return FALSE;
for (DWORD i = 0; i < dwReqObjNameCch * sizeof(TCHAR); i += sizeof(TCHAR))
{
lpReqObjName[i] = (lpReqObjName[i] % 26) + 97;
lpReqObjName[i + 1] = 0;
}
((LPTSTR)lpReqObjName)[dwReqObjNameCch] = _T('.');
((LPTSTR)lpReqObjName)[dwReqObjNameCch + 1] = _T('h');
((LPTSTR)lpReqObjName)[dwReqObjNameCch + 2] = _T('t');
((LPTSTR)lpReqObjName)[dwReqObjNameCch + 3] = _T('m');
((LPTSTR)lpReqObjName)[dwReqObjNameCch + 4] = _T('l');
((LPTSTR)lpReqObjName)[dwReqObjNameCch + 5] = 0;
// open request
if (NULL == (m_hRequest = WinHttpOpenRequest(m_hConnect, bGetVerb ? L"GET" : L"POST",
(LPTSTR)lpReqObjName, L"HTTP/1.1", WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE)))
__leave;
// set cert options
if (m_lpConfig->bSsl)
{
dwOptionCode = SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
SECURITY_FLAG_IGNORE_UNKNOWN_CA;
if (!WinHttpSetOption(m_hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &dwOptionCode,
sizeof(DWORD)))
__leave;
}
// all done
bOK = TRUE;
}
__finally
{
if (!bOK)
{
RELEASE_HINTERNET(m_hConnect);
RELEASE_HINTERNET(m_hRequest);
}
RELEASE_ARRAY(lpReqObjName);
}
return bOK;
}
Below is server's main communication code
#include <strsafe.h>
BOOL CSslServer :: StartService(SSL_CONFIG* lpSslServerConfig)
{
WSADATA lpWSAData;
WSAStartup(MAKEWORD(2, 2), &lpWSAData);
CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
SSL_library_init(); // Initialize OpenSSL's SSL libraries
SSL_load_error_strings(); // Load SSL error strings
OpenSSL_add_all_algorithms(); // Load all available encryption algorithms
m_lpConfig = lpSslServerConfig;
m_SslCtx = SSL_CTX_new(SSLv3_server_method());
SSL_CTX_set_default_passwd_cb_userdata(m_SslCtx, (void*)"123456");
if (1 > SSL_CTX_use_certificate_file(m_SslCtx, m_lpConfig->szCertFileDir, SSL_FILETYPE_PEM))
{
return FALSE;
}
if (1 > SSL_CTX_use_PrivateKey_file(m_SslCtx, m_lpConfig->szSkeyFileDir, SSL_FILETYPE_PEM))
{
return FALSE;
}
SSL_CTX_set_cipher_list(m_SslCtx, "ALL");
SSL_CTX_set_verify(m_SslCtx, SSL_VERIFY_NONE, NULL);
if (NULL == (m_hServerQuitEvt = CreateEvent(NULL, FALSE, FALSE, NULL)))
return FALSE;
if (NULL == (m_hWorkThread = CreateThread(NULL, 0, SslServerWorkThread, this, 0, NULL)))
{
StopService();
return FALSE;
}
return TRUE;
}
BOOL CSslServer :: StopService()
{
DWORD dwExitCode = 0;
if (m_hWorkThread != NULL)
{
SetEvent(m_hServerQuitEvt);
WaitForSingleObject(m_hWorkThread, 30000);
if(GetExitCodeThread(m_hWorkThread, &dwExitCode))
{
if(dwExitCode == STILL_ACTIVE)
TerminateThread(m_hWorkThread, 0);
}
}
SSL_CTX_free(m_SslCtx);
RELEASE_HANDLE(m_hServerQuitEvt);
RELEASE_HANDLE(m_hWorkThread);
m_WorkThreadList.empty();
return TRUE;
}
DWORD WINAPI SslServerWorkThread(LPVOID lpParam)
{
CSslServer* lpServer = (CSslServer*)lpParam;
SOCKET hListenSocket = INVALID_SOCKET;
TIMEVAL* lpWaitTime = new TIMEVAL;
fd_set ListenFds;
DWORD dwWaitForQuit = 0;
int nSelectRel = 0;
int nSize = 0;
SESSION_CONTEXT* lpSessionCtx = NULL;
WORK_THREAD_CONTEXT* lpWorkThreadCtx = NULL;
hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(hListenSocket, (sockaddr*)&lpServer->m_lpConfig->SslServerAddr,
sizeof(sockaddr_in));
if (SOCKET_ERROR == listen(hListenSocket, SOMAXCONN))
{
RELEASE_SOCKET(hListenSocket);
RELEASE(lpWaitTime);
return 0;
}
FD_ZERO(&ListenFds);
FD_SET(hListenSocket, &ListenFds);
lpWaitTime->tv_sec = 30;
lpWaitTime->tv_usec = 0;
do
{
nSelectRel = select(0, &ListenFds, NULL, NULL, lpWaitTime);
switch (nSelectRel)
{
case SOCKET_ERROR:
goto END;
case 1:
lpSessionCtx = new SESSION_CONTEXT;
nSize = sizeof(sockaddr_in);
if (INVALID_SOCKET == (lpSessionCtx->hClientSocket = accept(hListenSocket,
(struct sockaddr *)&lpSessionCtx->ClientAddress, &nSize)))
{
RELEASE(lpSessionCtx);
goto END;
}
lpSessionCtx->lpServer = lpServer;
lpSessionCtx->lpWorkConfig = lpServer->m_lpConfig->lpWorkConfig;
lpSessionCtx->SslSession = SSL_new(lpServer->m_SslCtx);
SSL_set_fd(lpSessionCtx->SslSession, lpSessionCtx->hClientSocket);
SSL_accept(lpSessionCtx->SslSession);
lpWorkThreadCtx = new WORK_THREAD_CONTEXT;
lpWorkThreadCtx->hWorkThreadQuitEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
lpWorkThreadCtx->hWorkThread = CreateThread(NULL, 0, WorkMain, lpSessionCtx,
0, NULL);
// WorkMain is not provided here, the function just analyze the received packet and
// invoke SendPacket to send response.
lpSessionCtx->lpWorkThreadCtx = lpWorkThreadCtx;
lpServer->m_WorkThreadList.push_back(lpWorkThreadCtx);
break;
default:
FD_SET(hListenSocket, &ListenFds);
}
dwWaitForQuit = WaitForSingleObject(lpServer->m_hServerQuitEvt, 0);
if (dwWaitForQuit == WAIT_FAILED || dwWaitForQuit == WAIT_ABANDONED)
{
goto END;
}
} while (dwWaitForQuit != WAIT_OBJECT_0);
END:
RELEASE_SOCKET(hListenSocket);
RELEASE(lpWaitTime);
return 0;
}
// I have examined the received packet. This function is ok
BOOL CSslServer :: ParseClientPacket(SSL* ssl, BYTE** lpBuf, DWORD* dwTransCb)
{
char* lpHeader = NULL;
BOOL bOk = FALSE;
int nRet = 0;
int nHeaderBufCb = 1024;
int nIndex = 0;
DWORD dwPackBufCb = 0;
__try
{
*dwTransCb = 0;
lpHeader = new char [nHeaderBufCb];
memset(lpHeader, 0, nHeaderBufCb);
if (0 >= (nRet = SSL_read(ssl, lpHeader, nHeaderBufCb)))
__leave;
nHeaderBufCb = lstrlenA(lpHeader);
for (nIndex = 20; nIndex < nHeaderBufCb - 15; nIndex++)
{
if (0 == memcmp(lpHeader + nIndex, "Content-Length: ", 16))
{
sscanf_s(lpHeader + nIndex + 16, "%d", &dwPackBufCb);
break;
}
}
if (nIndex == nHeaderBufCb - 15)
__leave;
for (nIndex += 16; nIndex < nHeaderBufCb - 4; nIndex++)
{
if (0 == memcmp(lpHeader + nIndex, "\r\n\r\n", 4))
break;
}
if (nIndex == nHeaderBufCb - 4)
__leave;
*lpBuf = new BYTE [dwPackBufCb];
if (nRet - nIndex - 4 > 0)
{
memcpy(*lpBuf, lpHeader + nIndex + 4, nRet - nIndex - 4);
*dwTransCb = nRet - nIndex - 4;
}
while (*dwTransCb < dwPackBufCb)
{
if (0 >= SSL_read(ssl, *lpBuf + *dwTransCb, dwPackBufCb - *dwTransCb))
{
bOk = TRUE;
__leave;
}
*dwTransCb += nRet;
}
bOk = TRUE;
}
__finally
{
RELEASE_ARRAY(lpHeader);
}
return bOk;
}
BOOL CSslServer :: SendPacket(SSL* ssl, BYTE* lpBuf, DWORD cb)
{
LPSTR lpHttpPacket = NULL;
DWORD dwHeaderLen = 0;
BOOL bOk = FALSE;
char szTime[50] = {0};
time_t lTime;
struct tm GmtTime;
__try
{
lpHttpPacket = new char [200 + cb];
memset(lpHttpPacket, 0, 200 + cb);
time(&lTime);
_gmtime64_s(&GmtTime, &lTime);
strftime(szTime, 50, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", &GmtTime);
StringCchPrintfA(lpHttpPacket, 200,
"HTTP/1.1 200 OK\r\nServer: Microsoft-IIS/8.0\r\nConnection: Keep-Alive\r\n%sContent-Type: text/html\r\nContent-Length: %d\r\n\r\n",
szTime, cb);
dwHeaderLen = lstrlenA(lpHttpPacket);
memcpy(lpHttpPacket + dwHeaderLen, lpBuf, cb);
if (0 >= SSL_write(ssl, lpHttpPacket, cb)) // the packet send by this sentence cannot be received by client
__leave; // observe by wireshark, this sentence send a ssl reassembled pdu
bOk = TRUE;
}
__finally
{
RELEASE_ARRAY(lpHttpPacket);
}
return bOk;
}
And below is wireshark snap.
NO. Time Source Destination Protocol Length Info
15951 3691.1 .23 .98 SSL 126 client hello
15952 3691.1 .98 .23 SSLv3 1109 server hello
15953 3691.1 .23 .98 SSLv3 386 client key exchange, change cipher spec, finished
15954 3691.1 .98 .23 SSLv3 121 change cipher spec, finished
16029 3706.6 .23 .98 http 301 POST ...... HTTP/1.1
16060 3711.9 .98 .23 SSLv3 83 [SSL segment of a ressembled PDU]
It takes me really a long time to solve this problem. I really hope someone and handle this.
best wishes

Why do I get a Timeout in PortRead() in visual c++?

I am trying jni interfacing for serial port programming, using Microsoft Visual Studio 11 with .NET 4.0.
I get he following error when I try to read from the comm port:
time out happened in PortRead()
The read time out value is set to 5sec.
The following is a part of the code:
Also, since my laptop is 64 bit I'm using a bafo ie a 64 to 32 bit converter, and then attach the rs232 wire.
JNIEXPORT jint JNICALL Java_JavaSerial_Read(JNIEnv *env, jobject obj)
{
jint idata = 0;
char cdata[8];
ERR_CODE rc = OK;
CommPortClass* commClass;
commClass = new CommPortClass;
commClass->iMaxChars = 1;
rc = PortRead(commClass);
if (rc != OK)
Msg("ERROR in PortRead()! ");
sprintf_s(cdata, "%d", commClass->pcBuffer[0]);
idata = atoi(cdata);
delete commClass;
return idata;
}
//Port read function
ERR_CODE PortRead(CommPortClass *hCommPort)
{
HANDLE hThread; // handler for port read thread
DWORD IDThread;
DWORD Ret, ExitCode;
DWORD dTimeout = 5000; // define time out value: 5 sec.
ERR_CODE ecStatus = OK;
if (!(hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadFunc, (LPVOID)hCommPort, CREATE_SUSPENDED, &IDThread) ) )
// no security attributes, use default stack size, parameter to thread function, creation flag - suspended, returns thread ID
{
Msg("Create Read Thread failed");
return EC_CREATE_THREAD;
}
ResumeThread(hThread); // start thread now
Ret = WaitForSingleObject(hThread, dTimeout);
if (Ret == WAIT_OBJECT_0)
{
// Data received & process it... need to do nothing because the data is stored in the
// hCommPort in the Thread Function. The only thing is to close thread handle
CloseHandle(hThread);
}
else if (Ret == WAIT_TIMEOUT) // Time out happened
{
// Warning & kill thread
Ret = GetExitCodeThread(hThread, &ExitCode);
Msg("Time out happened in PortRead() ");
if (ExitCode == STILL_ACTIVE)
{
TerminateThread(hThread, ExitCode);
CloseHandle(hThread);
return EC_RECV_TIMEOUT;
}
else
{
CloseHandle(hThread);
Msg("ERROR in GetExitCodeThread: != STILL_ACTIVE ");
ecStatus = EC_EXIT_CODE;
}
}
else
{
Msg("ERROR in WaitFor SingleObject ");
ecStatus = EC_WAIT_SINGLEOBJ;
}
return ecStatus;
}
//Thread() function
void WINAPI ThreadFunc(void* hCommPorts)
{
char Byte;
BOOL bResult, fDone;
int nTotRead = 0;
DWORD dwCommModemStatus, dwBytesTransferred;
CommPortClass* CommPorts;
ERR_CODE ecStatus = OK;
CommPorts = (CommPortClass* )hCommPorts;
// Specify a set of events to be monitored for the port.
SetCommMask(hPort, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_RING);
fDone = FALSE;
while (!fDone)
{
// Wait for an event to occur for the port.
WaitCommEvent(hPort, &dwCommModemStatus, 0);
// Re-specify the set of events to be monitored for the port.
SetCommMask(hPort, EV_RXCHAR | EV_CTS | EV_DSR |EV_RLSD| EV_RING);
if (dwCommModemStatus & EV_RXCHAR||dwCommModemStatus & EV_RLSD)
{
// received the char_event & loop to wait for the data.
do
{
// Read the data from the serial port.
bResult = ReadFile(hPort, &Byte, 1, &dwBytesTransferred, 0);
if (!bResult)
{
Msg("ERROR in ReadFile !");
fDone = TRUE;
break;
}
else
{
// Display the data read.
if (dwBytesTransferred == 1)
{
CommPorts->pcBuffer[nTotRead] = Byte;
nTotRead++;
if (nTotRead == CommPorts->iMaxChars)
{
fDone = TRUE;
break;
}
}
else
{
if (Byte == 0x0D ||Byte == 0x0A) // null char or CR
{
Msg("Received null character ");
fDone = TRUE;
break;
}
}
}
} while (dwBytesTransferred == 1); //while (nTotRead < pRecv->iMaxChars);
} // if
} // while
return;
}