I'll start with the code:
typedef std::vector<unsigned char> CharBuf;
static const int RCV_BUF_SIZE = 1024;
SOCKET m_socket = a connected and working socket;
// ...
CharBuf buf; // Declare buffer
buf.resize(RCV_BUF_SIZE); // resize buffer to 1024
char* p_buf = reinterpret_cast<char*>(&buf[0]); // change from unsigned char to char
//char p_buf[RCV_BUF_SIZE];
int ret = recv(m_socket, p_buf, RCV_BUF_SIZE, 0); // Does not work
for (int i=0; i<RCV_BUF_SIZE; ++i) // Works (does not crash, so the buffer is ok)
char c = p_buf[i];
//...
Now when I run this code ret becomes -1 and WSAGetLastError() returns 10014 which means the pointer is bad.
However I can't see why this shouldn't work? If I comment out the reinterpret_cast line and use the line below it works!
It could be argued that reinterpret_cast is risky, but I think it should be ok as both unsigned char and signed char has the exact same size.
std::vectors should be safe to address directly in memory as far as I know as well.
The funny part is that when I do the same thing with the same vector-type in send() it works! Send function:
void SendData(const CharBuf& buf)
{
buf.resize(RCV_BUF_SIZE); // resize buffer to 1024
const char* p_buf = reinterpret_cast<const char*>(&buf[0]); // change from unsigned char to char
int ret = send(m_socket, p_buf, (int)buf.size(), 0); // Works
}
As we see, no difference except CharBuf being const in this case, can that change anything?
Why is recv() more sensitive than send()? How can recv() even know the pointer is invalid (which it obviously isn't)?? all it should see is a char array!
As per request my whole receive function (bear in mind that I can't spell out every function in it, but I think they should be fairly self-explanatory.
bool TcpSocket::ReceiveData(CharBuf* pData)
{
if (!CheckInitialized("ReceiveData"))
return false;
if (m_status != CONNECTED_STAT)
{
AddToErrLog("Socket not connected", 1, "ReceiveData");
return false;
}
int ret;
pData->resize(RCV_BUF_SIZE);
char* p_buf = reinterpret_cast<char*>(&pData[0]);
ret = recv(m_socket, p_buf, RCV_BUF_SIZE, 0);
switch (ret)
{
case 0: // Gracefully closed
AddToLog("Connection gracefully closed", 2);
Shutdown(); // The connection is closed, no idea to keep running
return true;
case SOCKET_ERROR: // Error
ret = WSAGetLastError();
if (ret == 10004) // This indicates the socket was closed while we were waiting
AddToLog("Socket was shut down while waiting for data", 1, "ReceiveData(1)");
else
AddToErrLog("Receive data failed with code: " + CStr(ret));
AddToLog("Connection ended with error", 2);
Shutdown();
return false;
default: // Normal operation
pData->resize(ret); // Remove unused space
return true;
}
}
Never mind. I found it while I was pasting the function. Like always, you find your error when you try to explain it for someone else :)
I leave it up to the reader to figure out what was wrong, but I'll give &pData[0] as a hint.
Thanks for your help :D
Found the answer myself while pasting the whole function, &pData[0] is a hint.
Related
I am successfully receiving data over RF on a second Arduino. However I am trying to compare the incoming string so that I can call a method when there is a match. The "if" block is never executed. I am just trying to compare the strings that are incoming. It's printing the correct values to the serial monitor but the block is never executed. Maybe because this is using a pointer to a string (don't shoot me)? I am not that familiar with C or C++. I have tried several of the string comparison methods in the Arduino docs but no joy? Any reccomendations?
void loop()
{
// Set buffer to size of expected message
uint8_t buf[7];
uint8_t buflen = sizeof(buf);
// Check if received packet is correct size
if (rf_driver.recv(buf, &buflen))
{
// Message received with valid checksum
Serial.print("Message Received: ");
String str_out = String((char*)buf);
Serial.println(str_out); /
if (str_out == "plasma1") { // this is never executed wtf!!!
plasmaSequenceOne();
} else if (str_out == "plasma2") {
plasmaSequenceTwo();
} else if (str_out == "plasma3") {
plasmaSequenceThree();
} else if (str_out == "plasma4") {
plasmaSequenceFour();
}
}
}
Making Alex' self-response easier readable, and avoiding unnecessary String objects:
uint8_t buf[8];
uint8_t buflen = sizeof(buf)-1; // leave space for terminating 0
if (rf_driver.recv(buf, &buflen)) {
buf[buflen] = 0;
char* str_out = (char*)buf;
Serial.println (str_out);
if (strcmp(str_out, "plasma1")==0) plasmaSequenceOne();
...
}
This worked, thanks to #Remy Lebeau.
I hooked some socket function of a game. Then can get the receive and sent data from sockets inside that game. The problem is: There are more then 1 socket.
How could I get the handle of the FIRST socket created? I hooked the function SOCKET, like this:
SOCKET GameMainSocket;
SOCKET _stdcall WSAAPI nSocket(int af,int type,int protocol)
{
UnHookFunction("ws2_32.dll", "socket", KSocketHook);
GameMainSocket = socket(af, type, protocol);
HookFunction("ws2_32.dll", "socket", (LPVOID*) nSocket, KSocketHook);
return GameMainSocket;
}
But then, later, when I try to compare it within hooked send and recv function, like this:
int __stdcall nSend(SOCKET s, const char *buf, int len,int flags)
{
if (s = GameMainSocket)
{
// Allow send
}
}
The code is just skipped and all the checks are true.
** My real quetion is: How could I identifie each socket created by an application?
Thanks in advance!
PROBLEM FULLY SOLVED.
My code now is:
if (s == GameMainSocket)
{
// The magic goes here, encrypt packet with XOR (server does the same)
char* buf2 = (char*) malloc (len);
memcpy(buf2, buf, len);
//buf2[0] = buf2[0];
buf2[0] = buf2[0] ^ int("x") % 255;
}
if (s = GameMainSocket)
is doing assignment which will return the assigned value, which will be true if it is not 0.
Did you mean to do the following?
if (s == GameMainSocket)
Currently I try to write a serial port communication in VC++ to transfer data from PC and robot via XBee transmitter. But after I wrote some commands to poll data from robot, I didn't receive anything from the robot (the output of filesize is 0 in the code.). Because my MATLAB interface works, so the problem should happen in the code not the hardware or communication. Would you please give me help?
01/03/2014 Updated: I have updated my codes. It still can not receive any data from my robot (the output of read is 0). When I use "cout<<&read" in the while loop, I obtain "0041F01C1". I also don't know how to define the size of buffer, because I don't know the size of data I will receive. In the codes, I just give it a random size like 103. Please help me.
// This is the main DLL file.
#include "StdAfx.h"
#include <iostream>
#define WIN32_LEAN_AND_MEAN //for GetCommState command
#include "Windows.h"
#include <WinBase.h>
using namespace std;
int main(){
char init[]="";
HANDLE serialHandle;
// Open serial port
serialHandle = CreateFile("\\\\.\\COM8", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
// Do some basic settings
DCB serialParams;
DWORD read, written;
serialParams.DCBlength = sizeof(serialParams);
if((GetCommState(serialHandle, &serialParams)==0))
{
printf("Get configuration port has a problem.");
return FALSE;
}
GetCommState(serialHandle, &serialParams);
serialParams.BaudRate = CBR_57600;
serialParams.ByteSize = 8;
serialParams.StopBits = ONESTOPBIT;
serialParams.Parity = NOPARITY;
//set flow control="hardware"
serialParams.fOutX=false;
serialParams.fInX=false;
serialParams.fOutxCtsFlow=true;
serialParams.fOutxDsrFlow=true;
serialParams.fDsrSensitivity=true;
serialParams.fRtsControl=RTS_CONTROL_HANDSHAKE;
serialParams.fDtrControl=DTR_CONTROL_HANDSHAKE;
if (!SetCommState(serialHandle, &serialParams))
{
printf("Set configuration port has a problem.");
return FALSE;
}
GetCommState(serialHandle, &serialParams);
// Set timeouts
COMMTIMEOUTS timeout = { 0 };
timeout.ReadIntervalTimeout = 30;
timeout.ReadTotalTimeoutConstant = 30;
timeout.ReadTotalTimeoutMultiplier = 30;
timeout.WriteTotalTimeoutConstant = 30;
timeout.WriteTotalTimeoutMultiplier = 30;
SetCommTimeouts(serialHandle, &timeout);
if (!SetCommTimeouts(serialHandle, &timeout))
{
printf("Set configuration port has a problem.");
return FALSE;
}
//write packet to poll data from robot
WriteFile(serialHandle,">*>p4",strlen(">*>p4"),&written,NULL);
//check whether the data can be received
char buffer[103];
do {
ReadFile (serialHandle,buffer,sizeof(buffer),&read,NULL);
cout << read;
} while (read!=0);
//buffer[read]="\0";
CloseHandle(serialHandle);
return 0;
}
GetFileSize is documented not to be valid when used with a serial port handle. Use the ReadFile function to receive serial port data.
You should use strlen instead of sizeof here:
WriteFile(serialHandle,init,strlen(init),&written,NULL)
You would be even better off creating a function like this:
function write_to_robot (const char * msg)
{
DWORD written;
BOOL ok = WriteFile(serialHandle, msg, strlen(msg), &written, NULL)
&& (written == strlen(msg));
if (!ok) printf ("Could not send message '%s' to robot\n", msg);
}
But that's only the appetizer. The main trouble is, as MDN says:
You cannot use the GetFileSize function with a handle of a nonseeking device such as a pipe or a communications device.
If you want to read from the port, you can simply use ReadFile until it returns zero bytes.
If you already know the max size of your robot's response, try reading that many characters.
Continue reading until the read reports an actual number of bytes read inferior to the size of the buffer. For instance:
#define MAX_ROBOT_ANSWER_LENGTH 1000 /* bytes */
const char * read_robot_response ()
{
static char buffer[MAX_ROBOT_ANSWER_LENGTH];
DWORD read;
if (!ReadFile (serialHandle, buffer, sizeof(buffer), &read, NULL))
{
printf ("something wrong with the com port handle");
exit (-1);
}
if (read == sizeof(buffer))
{
// the robot response is bigger than it should
printf ("this robot is overly talkative. Flushing input\n");
// read the rest of the input so that the next answer will not be
// polluted by leftovers of the previous one.
do {
ReadFile (serialHandle, buffer, sizeof(buffer), &read, NULL);
} while (read != 0);
// report error
return "error: robot response exceeds maximal length";
}
else
{
// add a terminator to string in case Mr Robot forgot to provide one
buffer[read] = '\0';
printf ("Mr Robot said '%s'\n", buffer);
return buffer;
}
}
This simplistic function returns a static variable, which will be overwritten each time you call read_robot_response.
Of course the proper way of doing things would be to use blocking I/Os instead of waiting one second and praying for the robot to answer in time, but that would require a lot more effort.
If you feel adventurous, you can use overlapped I/O, as this lenghty MDN article thoroughly explores.
EDIT: after looking at your code
// this reads at most 103 bytes of the answer, and does not display them
if (!ReadFile(serialHandle,buffer,sizeof(buffer),&read,NULL))
{
printf("Reading data to port has a problem.");
return FALSE;
}
// this could display the length of the remaining of the answer,
// provided it is more than 103 bytes long
do {
ReadFile (serialHandle,buffer,sizeof(buffer),&read,NULL);
cout << read;
}
while (read!=0);
You are displaying nothing but the length of the response beyond the first 103 characters received.
This should do the trick:
#define BUFFER_LEN 1000
DWORD read;
char buffer [BUFFER_LEN];
do {
if (!ReadFile(
serialHandle, // handle
buffer, // where to put your characters
sizeof(buffer) // max nr of chars to read
-1, // leave space for terminator character
&read, // get the number of bytes actually read
NULL)) // Yet another blody stupid Microsoft parameter
{
// die if something went wrong
printf("Reading data to port has a problem.");
return FALSE;
}
// add a terminator after last character read,
// so as to have a null terminated C string to display
buffer[read] = '\0';
// display what you actually read
cout << buffer;
}
while (read!=0);
I advised you to wrap the actual calls to serial port accesses inside simpler functions for a reason.
As I said before, Microsoft interfaces are a disaster. They are verbose, cumbersome and only moderately consistent. Using them directly leads to awkward and obfuscated code.
Here, for instance, you seem to have gotten confused between read and buffer
read holds the number of bytes actually read from the serial port
buffer holds the actual data.
buffer is what you will want to display to see what the robot answered you
Also, you should have a documentation for your robot stating which kind of answers you are supposed to expect. It would help to know how they are formatted, for instance whether they are null-terminated strings or not. That could dispense to add the string terminator.
While debugging, when WSARecv is called, I supply the function with the address of the PerIoData->WSABUF structure. This should assign the sent data to the WSABUF.buf char* array, which it seems to. When The worker thread loops back to the waiting GetQueuedCompletionStatus, it seems to somehow (magically) send that data to PerIoData.Buffer (char* array). So essentially, the PerIoData.Buffer and PerIoData.WSABUF.buf both equal the same char* array. When I remove the PerIoData.Buffer from the PER_IO_DATA Struct (and all references to it), the GetQueuedCompletionStaus never returns when the client sends data though i know the WSABUF.buf should be populated with data.
The pertinent information:
I'm implementing the Completion Port Model found in "Network Programming for Microsoft Windows" (p.157). Though the examples in that book left much to be independently discovered, my code works fine now.
In the while loop of the ServerWorkerThread: GetQueuedCompletionStatus , called first, receives per_handle_data, and per_io_data
per_io_data struct is as such:
struct _PER_IO_DATA{ //in the interests of an efficient question, i'm omitting the
//constructor/destructor code
public:
OVERLAPPED Overlapped;
WSABUF DataBuf;
char myBuffer[BUFFER_LENGTH];
int BufferLen;
int OperationType;
};
typedef _PER_IO_DATA PER_IO_DATA;
typedef _PER_IO_DATA *PPER_IO_DATA;
My GetQueuedCompletionStatus function is called like so:
ret = GetQueuedCompletionStatus(CompletionPort,
&BytesTransferred,
(LPDWORD)&PerHandleData,
(LPOVERLAPPED *)&PerIoData,
INFINITE);
My WSARecv Function is called like so:
WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, NULL, &Flags, ((LPWSAOVERLAPPED)&PerIoData->Overlapped), NULL);
//i know casting the Overlapped structure as LPWSAOVERLAPPED is unnecessary, but I was tweaking the
//code when I didn't fully understand the problems I was having.
My problem is that I never explicitly assign anything to the PerIoData->Buffer yet it seems to always get populated with the sent data. I'm lead to believe GetQueuedCompletionStatus "knows" to send this data to that PerIoData->Buffer though it's expecting a pointer to a LPOVERLAPPED structure (to which i pass my PerIoData struct instance containing the Buffer char array in question). It's really bugging me... Maybe it's not behaving like I'm thinking it is, but the only place I can see the PerIoData->Buffer being populated is from within the GetQueuedCompletionStatus method. If that's not the case, then PerIoData->Buffer seems to be populated from nowhere? I've scoured MSDN and google for days. I'll continue looking and if I find the answer I'll post an update. Please Help? Thanks in advance!
*Note: I would've created the tags WSABUF and GetQueuedCompletionStatus, but this is my first post.
--EDIT: I'm posting the structs and worker thread, leaving out all other unrelated code.--
You'll notice that _PER_IO_DATA::DataBuf.buf is allocated memory, then zeroed out. Not pointing to the myBuffer array....
#include "stdafx.h"
#define SEND_POSTED 1
#define RECV_POSTED 2
#define BUFFER_LENGTH 1024
HANDLE CompletionPort;
SOCKADDR_IN serverAddress, *clientAddress;
SOCKET listener, client;
unsigned short port = 5000;
SYSTEM_INFO SystemInfo;
int i;
struct _PER_HANDLE_DATA{//Per handle data structure
SOCKET Socket;
SOCKADDR_STORAGE Address;
_PER_HANDLE_DATA(){
Socket = 0;
ZeroMemory(&Address, sizeof(SOCKADDR_STORAGE));
}
~_PER_HANDLE_DATA(){
Socket = NULL;
ZeroMemory(&Address, sizeof(SOCKADDR_STORAGE));
}
};typedef _PER_HANDLE_DATA PER_HANDLE_DATA;typedef _PER_HANDLE_DATA *PPER_HANDLE_DATA;
struct _PER_IO_DATA{
public:
OVERLAPPED Overlapped;
WSABUF DataBuf;
char myBuffer[BUFFER_LENGTH];
int BufferLen;
int OperationType;
_PER_IO_DATA(){
OperationType = 0;
DataBuf.len = BUFFER_LENGTH;
DataBuf.buf = (char*)malloc(BUFFER_LENGTH+1);
BufferLen = BUFFER_LENGTH;
ZeroMemory(DataBuf.buf, (sizeof(BUFFER_LENGTH+1)));
ZeroMemory(&myBuffer, (sizeof(char)*BUFFER_LENGTH));
SecureZeroMemory((PVOID)&Overlapped, sizeof(Overlapped));
}
~_PER_IO_DATA(){
free(&DataBuf.buf);
}
};
typedef _PER_IO_DATA PER_IO_DATA;
typedef _PER_IO_DATA *PPER_IO_DATA;
unsigned _stdcall ServerWorkerThread(LPVOID CompletionPortID);
int _tmain(int argc, _TCHAR* argv[])
{
/*
INITIALIZE WINSOCK AND COMPLETION PORT, AND ACCEPT CONNECTIONS
*/
}
unsigned _stdcall ServerWorkerThread(LPVOID CompletionPortID){
printf("ServerWorkerThread(%d) Working\n", GetCurrentThreadId());
HANDLE CompletionPort = (HANDLE) CompletionPortID;
DWORD BytesTransferred;
PPER_HANDLE_DATA PerHandleData = new PER_HANDLE_DATA;
PPER_IO_DATA PerIoData = new PER_IO_DATA;
DWORD SendBytes = 0, RecvBytes = 0;
DWORD Flags;
BOOL ret;
Sleep(2000);
while(TRUE){
ret = GetQueuedCompletionStatus(CompletionPort,
&BytesTransferred,
(LPDWORD)&PerHandleData,
(LPOVERLAPPED *)&PerIoData,
INFINITE);
//printf("\n\nBytesTransferred: %d\n\n", BytesTransferred);
if(BytesTransferred == 0 && (PerIoData->OperationType == RECV_POSTED || PerIoData->OperationType == SEND_POSTED)){
closesocket(PerHandleData->Socket);
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}
if(PerIoData->OperationType == RECV_POSTED){
//output received data
if(!strcmp(PerIoData->DataBuf.buf, "Disconnect") || !strcmp(PerIoData->DataBuf.buf, "disconnect")){
printf("Disconnecting...\n");
if(!shutdown(PerHandleData->Socket, SD_BOTH)){
closesocket(PerHandleData->Socket);
delete(PerHandleData);
}
}else{
printf("RECV_POSTED: %s\n", PerIoData->DataBuf.buf);
}
}
Flags = 0;
SecureZeroMemory((PVOID)&PerIoData->Overlapped, sizeof(WSAOVERLAPPED));
PerIoData->DataBuf.len = BUFFER_LENGTH;
//***************************************************************************
//Even though the following is commented out, PerIoData->DataBuf.buf
//is still being populated and so is PerIoData-myBuffer
//So why is myBuffer being populated with data when DataBuf.buf is not pointing to it??
//PerIoData->DataBuf.buf = PerIoData->myBuffer;
//Also, if you comment out all references of myBuffer, GetQueuedCompletionStatus(),
//will never return if myBuffer doesn't exist...how does it seem to be 'aware' of myBuffer?
//***************************************************************************
PerIoData->OperationType = RECV_POSTED;
WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, NULL, &Flags, ((LPWSAOVERLAPPED)&PerIoData->Overlapped), NULL);
}
return 0;
}
So I am trying to implement timed http connection Keep-Alive. And I need to be capable of killing it on some time-out. So currently I have (or at least I would like to have):
void http_request::timed_receive_base(boost::asio::ip::tcp::socket& socket, int buffer_size, int seconds_to_wait, int seconds_to_parse)
{
this->clear();
http_request_parser_state parser_state = METHOD;
char* buffer = new char[buffer_size];
std::string key = "";
std::string value = "";
boost::asio::ip::tcp::iostream stream;
stream.rdbuf()->assign( boost::asio::ip::tcp::v4(), socket.native() );
try
{
do
{
stream.expires_from_now(boost::posix_time::seconds(seconds_to_wait));
int bytes_read = stream.read_some(boost::asio::buffer(buffer, buffer_size));
stream.expires_from_now(boost::posix_time::seconds(seconds_to_parse));
if (stream) // false if read timed out or other error
{
parse_buffer(buffer, parser_state, key, value, bytes_read);
}
else
{
throw std::runtime_error("Waiting for 2 long...");
}
} while (parser_state != OK);
}
catch (...)
{
delete buffer;
throw;
}
delete buffer;
}
But there is no read_some in tcp::iostream, so compiler gives me an error:
Error 1 error C2039: 'read_some' : is not a member of 'boost::asio::basic_socket_iostream<Protocol>'
That is why I wonder - how to read 1 byte via stream.read (like stream.read(buffer, 1);) and than read_some to that very buffer via socket API ( it would look like int bytes_read = socket.read_some(boost::asio::buffer(buffer, buffer_size)); and than call my parse_buffer function with real bytes_read value)
BTW it seems like there will be a really sad problem of 1 last byte..(
Sorry to be a bit rough, but did you read the documentation? The socket iostream is supposed to work like the normal iostream, like cin and cout. Just do stream >> var. Maybe you want basic_stream_socket::read_some instead?