Converting (parsing) google protocol buffer streams from socket - c++

I am using the following code to parse a message that was SerializedwithCodedStream on to the socket:
if ( socket->read(databuffer, size) != -1)
{
google::protobuf::io::ArrayInputStream array_input(databuffer,size);
google::protobuf::io::CodedInputStream coded_input(&array_input);
data_model::terminal_data* tData = new data_model::terminal_data();
if (!tData->ParseFromCodedStream(&coded_input))
{
return;
}
else
std::cout << tData->symbol_name() << std::endl;
}
Here is how I serialized it:
data_model::terminal_data tData;
tData.set_type(1);
tData.set_client_id("C109");
tData.set_expiry("20140915");
tData.set_quantity(3500);
tData.set_strat_id("056");
tData.set_symbol_name("BANKNIFTY");
tData.set_time("145406340");
tData.set_trade_id(16109234);
int total_size = tData.ByteSize() + sizeof(int);
char *buffer = new char[total_size];
memset(buffer, '\0', total_size);
google::protobuf::io::ArrayOutputStream aos(buffer,total_size);
google::protobuf::io::CodedOutputStream *coded_output = new google::protobuf::io::CodedOutputStream(&aos);
google::protobuf::uint32 s = tData.ByteSize();
coded_output->WriteVarint32(s);
tData.SerializeToCodedStream(coded_output);
int sent_bytes = 0;
if ( (sent_bytes = send(liveConnections.at(i), buffer, total_size, MSG_NOSIGNAL)) == -1 )
liveConnections.erase(liveConnections.begin() + i);
else
std::cout << "sent " << sent_bytes << " bytes to " << i << std::endl;
delete coded_output;
delete buffer;
When I try to parse, it gives the following error at runtime:
[libprotobuf ERROR google/protobuf/message_lite.cc:123] Can't parse message of type "data_model.terminal_data" because it is missing required fields: type
But as you can see (in the second code snippet) I have set the type field. What is the problem ?

You're ignoring the count returned by read(), other than checking it for -1. You need to use it instead of size when constructing array_input.

Related

Unable to send the message again using C socket

I have created a ClientSocket and a ServerSocket class for simplifying functions. while sending a data, at first I am sending a 16 bytes header containing the message length followed by the message. But I am having trouble while sending data from client to server on the 2nd time. At first it is sending the header and the message properly but after that I am getting 0 bytes output from read() in ServerSocket::get_message while reading the header from the client. Please help me out here.
Sending and receiving part in Server.cpp
string ServerSocket::get_message(int client_socket_fd) {
//char *header = client_buffers[client_socket_fd].read_header;
char *read_buffer = client_buffers[client_socket_fd].read_buffer;
char header[16];
memset(header, 0, sizeof(header));
int read_result = -1;
read_result = read(client_socket_fd, header, 16);
cout << read_result << endl;
if (read_result > 0){
int read_size = stoi(string(header));
cout << read_size << endl;
memset(read_buffer, 0, sizeof(read_buffer));
read_result = read(client_socket_fd, read_buffer,read_size);
if (read_result > 0) return string(read_buffer);
}
cerr << "Unable to recieve message from client socket " << client_socket_fd << endl;
return "";
}
int ServerSocket::_send(int client_socket_fd, string message) {
//char *header = client_buffers[client_socket_fd].write_header;
char *write_buffer = client_buffers[client_socket_fd].write_buffer;
char header[16];
memset(header, 0, sizeof(header));
string write_size = to_string(message.length());
copy(write_size.begin(), write_size.end(), header);
int write_result = write(client_socket_fd, header, 16); // sending size of message
if (write_result > 0) {
write_result = write(client_socket_fd, message.c_str(), message.length());
}
if (write_result <= 0)
cerr << "Unable to send to client socket fd : " << client_socket_fd << endl;
return write_result;
}
Sending and receiving part in Client.cpp
string ClientSocket::_recieve(){
char read_header[16];
memset(read_header, 0, sizeof(read_header));
int read_result = read(socket_fd, read_header, 16);
if (read_result >0) {
int read_size = stoi(string(read_header));
memset(recieve_buffer, 0, sizeof(recieve_buffer));
read_result = read(socket_fd, recieve_buffer, read_size);
}
if ( read_result > 0) return string(recieve_buffer);
cerr << "Unable to read from server." << endl;
return "";
}
int ClientSocket::_send(string message) {
char write_header[16];
memset(write_header, 0, sizeof(write_header));
cout << message.length() << endl;
string s = to_string(message.length());
copy(s.begin(),s.end(), write_header);
int write_result = write(socket_fd, write_header, 16);
if (write_result > 0)
write_result = write(socket_fd, message.c_str(), message.length());
if (write_result <=0) cerr << "Unable to send message : "<< message << endl;
return write_result;
}
The code exhibits the two most frequent errors when using sockets:
Socket send/write and recv/read may not send/receive the number of bytes requested. The code must handle partial reads/writes in order to work correctly.
The received socket data is not zero-terminated. You need to zero-terminate the received data before passing it to functions that expect zero-terminated stings (std::string and stoi here). memset doesn't help when recv fills the entire buffer, you need to reserve one extra byte for the null terminator that recv doesn't overwrite.

Sending files over TCP using C++, recving wrong size

I am very new to socket programming, and i am trying to send over TCP connection but getting few errors.
here is my code
FILE* File;
char* Buffer;
unsigned long Size;
File = fopen("C:\\test.zip", "rb");
if (!File)
{
printf("Error while readaing the file\n");
return;
}
// file size 1
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
Buffer = new char[Size];
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%i", Size);
cout << "MAX PATH " << MAX_PATH<<endl;
cout << "cSize: " << cSize << endl;
fclose(File);
`
So this to find the size of my file. most of the code i am trying it out from other questions in here but it didnt solve my problem.
'
my send and recv:
unsigned long filechunk = 1025;
unsigned long byteSent = 0;
unsigned long bytesToSend = 0;
send(Sub, cSize, MAX_PATH, 0); // File size to client
while (byteSent < Size) {
if ((Size - byteSent) >= filechunk) {
bytesToSend = filechunk;
}
else {
bytesToSend = Size - byteSent;
}
if (send(Sub, Buffer + byteSent, bytesToSend, 0)) {
std::cout << "Sent: ";
}
byteSent += bytesToSend;
std::cout << "Size : "<<Size<<" BytesSent : "<<byteSent<<" Bytes to send: " << bytesToSend << std::endl;
system("pause");
on the client side:
int Size;
char* Filesize = new char[5000000]; // is there a better way? my sfiles size are unknown but at least 50mb
if (recv(Socket, Filesize, 5000000, 0)) // File size
{
Size = atoi((const char*)Filesize);
printf("File size: %d\n", Size);
}
char* Buffer = new char[Size];
FILE* File;
File = fopen("test.zip", "wb"); //start copying from the server, creating the file first.
std::string convert;
long conv;
std::cout << "Size: " << Size << std::endl;
int total=Size;
int byteRecv = 0;
int recvCheck;
int bytes = 1025;
//getting the file
while (byteRecv < Size ) {
recvCheck = recv(Socket, Buffer, bytes, 0);
if (recvCheck >0) // File
{
fwrite(Buffer, 1, byteRecv, File);
std::cout << "Recieved:" << byteRecv << std::endl;
Size -= byteRecv;
byteRecv += byteRecv;
std::cout << "Error: " << WSAGetLastError();
}
else {
std::cout << "Error: " << WSAGetLastError();
total += 1; // the loop often get into infinit loop so i force it in case of this error.
if (total > 3) {
break;
}
}
}
fclose(File);
So, i know it is not very efficient and i am not sure if there are similar questions as i have been digging in here for a few weeks now.
-is there a better way i can make a char*[]? as i dont know the size of the files i want to send yet.
- does ftell() and sifeof() work the same way?
-when i check for the size i recved from the server it is alays wrong. Ex: server file: 32633513, recv size: 3263
-most of the code i have taken from other problems and combined it. if you see anything that is not needed do tell me so i take notes of that.
There is a lot of wrong things but that may correct your problem at first:
On the client side replace (your are both decrementing the total count of bytes and the received ones with the wrong value):
Size -= byteRecv;
byteRecv += byteRecv;
with:
byteRecv += recvCheck; // actualizes the count of received bytes
The other problem is your buffer size. Never try to get an entire file in memory, this is nonsense in general; files are usually managed chunks by chunks. As you are reading at most 1025 bytes in each loop, then only use a buffer of size 1025, you don't need more. Same for reading and writing...

C++ WinSock sending files

Recently, i've been assigned a client/server project, which is basically a chat room, where files can be sent and recieved, and we can use webcams.
I'm currently working on the file transfer part, and after looking at some online tutorials, i've noticed most of them use offsets to write into their buffers, then they write the whole buffer into their new file.
To replicate that kind of code, i've set up 2 buffers, one on the client side, the other on the server side. On the server side, i read 8192 bytes from my file, into the buffer, then i send it into the client side, which recieves it, and adds it to my buffer. Problem is, after the second file transfer, every single transfer it does, it's a SOCKET_ERROR, which probably means something's not quite right.
server:
std::ifstream readFile;
readFile.open(FileName, std::ios::binary | std::ios::ate);
if (!readFile)
{
std::cout << "unable to open file" << std::endl;
}
int FileSize = readFile.tellg();
readFile.seekg(0);
int remainingBytes = 0;
uint32_t FileSize32t = (uint32_t)FileSize;
FileSize32t = htonl(FileSize32t);
send(connections[ID], (char*)&FileSize32t, sizeof(uint32_t), 0);
int sent_bytes = 0;
int offset = 0;
char data[8192];
remainingBytes = FileSize;
int i = 0;
while (i<6)
{
readFile.read(data, 8192);
if (remainingBytes < 8192)
{
sent_bytes = send(connections[ID], data+offset, remainingBytes, 0);
remainingBytes -= sent_bytes;
offset += sent_bytes;
}
else
{
sent_bytes = send(connections[ID], data+offset, 8192, 0);
if (sent_bytes == SOCKET_ERROR)
{
std::cout << "erro" << std::endl;
}
remainingBytes -= sent_bytes;
offset += sent_bytes;
std::cout <<"offset: "<< offset << std::endl;
std::cout << "Sent bytes: " << sent_bytes << std::endl;
std::cout << "remaining bytes: " << remainingBytes << std::endl;
}
i++;
}
Client:
char data[8192];
std::ofstream writeFile;
writeFile.open("Putin.jpg", std::ios::binary);
int bytesReceieved = 0;
int totalBytesReceieved = 0;
int i = 0;
while (i<6)
{
if (recvFileSize - totalBytesReceieved < 8192)
{
bytesReceieved = recv(connection, data+totalBytesReceieved, recvFileSize - totalBytesReceieved, 0);
totalBytesReceieved += bytesReceieved;
}
else
{
bytesReceieved = recv(connection, data + totalBytesReceieved, 8192, 0);
totalBytesReceieved += bytesReceieved;
std::cout << totalBytesReceieved << std::endl;
}
i++;
}
writeFile.write(data, totalBytesReceieved);
std::cout << "transferĂȘncia terminada, bytes recebidos: " << totalBytesReceieved << std::endl;
writeFile.close();
Do note that this is just a test program, and it's preety much one of my first interactions with C++. I've been told this probably isn't the best way to start off with C++, but i need this assignment done until the 15th of september, so i need to finish it regardless. If you find any errors or problems besides my original issue do feel free to point them out and if you can, explain me why it's wrong.
Thank you very much for your help.

Win32 Can't get data from shared memory

I am able to create a shared memory object, as well as open it using the guide from MSDN.
The first process creates it and keeps it open.
The second process inputs a string.
Then the first process will attempt to recover that string and display it, however I can't seem to get anything. It's always empty although it seems like the writing part is set up correctly.
I write a string to memory like this:
int MemoryMapper::Write(const std::string& data) {
m_pBuffer = (LPCTSTR)MapViewOfFile(m_OpenHandle, FILE_MAP_ALL_ACCESS, 0, 0, m_BufferSize);
if (m_pBuffer == NULL)
{
std::cerr << m_DebugErrorTitle << "Write(): " << MM_ERROR_MAPPING_FAILED << " {" << GetLastError() << "}" << std::endl;
Close();
return 0;
}
const char* cdata = _CharFromString(data);
int size = (lstrlen(cdata) * sizeof(const char*));
CopyMemory((PVOID)m_pBuffer, cdata, size);
m_WrittenSize += size;
if (m_Debug > 1) { std::cout << m_DebugTitle << "Wrote " << size << " bytes." << std::endl; }
return size;
}
Then I read it like so:
int MemoryMapper::Read(std::string& data) {
m_pBuffer = (LPCTSTR) MapViewOfFile(m_OpenHandle, FILE_MAP_ALL_ACCESS, 0, 0, m_BufferSize);
if (m_pBuffer == NULL)
{
std::cerr << m_DebugErrorTitle << "Read(" << m_MemoryName << "): " << MM_ERROR_MAPPING_FAILED << " {" << GetLastError() << "}" << std::endl;
Close();
return 0;
}
MessageBox(NULL, m_pBuffer, TEXT("TEST MESSAGE"), MB_OK);
int size = (lstrlen(m_pBuffer) * sizeof(const char*));
UnmapViewOfFile(m_pBuffer);
return size;
}
m_pBuffer is a LPCTSTR and m_BufferSize is 1024.
The name speficied for the object is the same on both ends. I've already made sure the creation and opening/closing part works.
The second process writes '8312.000000,8312.000000', a total of 92 bytes according to the code.
The reader's buffer is empty.
What am I doing wrong?
I've tried various data types, char, const char, string, tchar - same result.
8312.000000,8312.000000 is 23 characters in length.
std::string::c_str() returns a null-terminated char* pointer. lstrlen() returns the number of characters up to but not including the null terminator.
Write() is multiplying the string length by sizeof(const char*), which is 4 in a 32-bit process (8 in a 64-bit process). Write() is exceeding the bounds of data and attempting to copy 23 * 4 = 92 bytes into m_pBuffer. cdata is guaranteed to point at a buffer containing 24 bytes max (23 characters + 1 null terminator), so Write() is reaching into surrounding memory. That is undefined behavior, and anything could happen. In your case, you probably just ended up copying extra garbage into m_pBuffer. Write() could have easily crashed instead.
In fact, if data has more than 256 characters, Write() WOULD crash, because it would be trying to copy 257+ * 4 > 1024 bytes into m_pBuffer - more than MapViewOfFile() mapped access for.
You should be multiplying the string length by sizeof(std::string::value_type) instead, which is sizeof(char), which is always 1 (so you could just omit the multiplication).
Read() has the same sizeof() mistake, but it is also making the assumption that m_pBuffer is always null-terminated when calling lstrlen() and MessageBox(), but Write() does not guarantee that a null terminator is always present.
With that said, try something more like this instead:
int MemoryMapper::Write(const std::string& data)
{
// include the null terminator if there is room...
DWORD size = std::min(data.size() + 1, m_BufferSize);
char *pBuffer = (char*) MapViewOfFile(m_OpenHandle, FILE_MAP_WRITE, 0, 0, size);
if (!pBuffer)
{
DWORD errCode = GetLastError();
std::cerr << m_DebugErrorTitle << "Write(): " << MM_ERROR_MAPPING_FAILED << " {" << errCode << "}" << std::endl;
Close();
return 0;
}
CopyMemory(pBuffer, data.c_str(), size);
UnmapViewOfFile(pBuffer);
m_WrittenSize += size;
if (m_Debug > 1) {
std::cout << m_DebugTitle << "Wrote " << size << " bytes." << std::endl;
}
return size;
}
int MemoryMapper::Read(std::string& data)
{
char *pBuffer = (char*) MapViewOfFile(m_OpenHandle, FILE_MAP_READ, 0, 0, m_BufferSize);
if (!pBuffer)
{
DWORD errCode = GetLastError();
std::cerr << m_DebugErrorTitle << "Read(" << m_MemoryName << "): " << MM_ERROR_MAPPING_FAILED << " {" << errCode << "}" << std::endl;
Close();
return 0;
}
// check for a null terminator, but don't exceed the buffer...
char *terminator = std::find(pBuffer, pBuffer + m_BufferSize, '\0');
std::size_t len = std::distance(pBuffer, terminator);
data.assign(pBuffer, len);
UnmapViewOfFile(pBuffer);
MessageBoxA(NULL, data.c_str(), "TEST MESSAGE", MB_OK);
// include the null terminator if it was read...
return std::min(len + 1, m_BufferSize);
}

Access violation reading location when using ReadFile

I`m struggling for the past many hours with the following problem: I try to read a file using CreateFile and ReadFile methods.
Here is the code:
char* Utils::ReadFromFile(wchar_t* path) {
HANDLE hFile = CreateFile(
path, // long pointer word string file path (16 bit UNICODE char pointer)
GENERIC_READ, // access to file
0, // share mode ( 0 - prevents others from opening/readin/etc)
NULL, // security attributes
OPEN_EXISTING, // action to take on file -- returns ERROR_FILE_NOT_FOUND
FILE_ATTRIBUTE_READONLY, // readonly and offset possibility
NULL // when opening an existing file, this parameter is ignored
);
if (hFile == INVALID_HANDLE_VALUE) {
std::cout << "File opening failed" << endl;
std::cout << "Details: \n" << Utils::GetLastErrorMessage() << endl;
CloseHandle(hFile);
hFile = NULL;
return nullptr;
}
LARGE_INTEGER largeInteger;
GetFileSizeEx(hFile, &largeInteger);
LONGLONG fileSize = largeInteger.QuadPart;
if (fileSize == 0) {
std::cout << "Error when reading file size" << endl;
std::cout << "Details: \n" << Utils::GetLastErrorMessage() << endl;
CloseHandle(hFile);
hFile = NULL;
return nullptr;
}
cout << "File size: " << fileSize << endl;
char* bytesRead;
bytesRead = new char(fileSize);
int currentOffset = 0;
int attempts = 0;
int nBytesToBeRead = BYTES_TO_READ;
//DWORD nBytesRead = 0;
OVERLAPPED overlap{};
errno_t status;
while (currentOffset < fileSize) {
overlap.Offset = currentOffset;
if (fileSize - currentOffset < nBytesToBeRead)
nBytesToBeRead = fileSize - currentOffset;
status = ReadFile(
hFile, // file handler
bytesRead + currentOffset, // byted read from file
nBytesToBeRead, // number of bytes to read
NULL, // number of bytes read
&overlap // overlap parameter
);
if (status == 0) {
std::cout << "Error when reading file at offset: " << currentOffset << endl;
std::cout << "Details: \n" << Utils::GetLastErrorMessage() << endl;
attempts++;
std::cout << "Attempt: " << attempts << endl;
if (attempts == 3) {
cout << "The operation could not be performed. Closing..." << endl;
CloseHandle(hFile);
hFile = NULL;
return nullptr;
}
continue;
}
else {
cout << "Read from offset: " << currentOffset;// << " -- " << overlap.InternalHigh << endl;
currentOffset += nBytesToBeRead;
if (currentOffset == fileSize) {
cout << "File reading completed" << endl;
break;
}
}
}
CloseHandle(hFile);
return bytesRead;
}
When running this method I get some weird results:
One time it worked perfectly
Very often I get Access violation reading location for currentOffset variable and overlap.InternalHigh ( I commented last one), with last method from CallStack being
msvcp140d.dll!std::locale::locale(const std::locale & _Right) Line 326 C++
Sometimes the function runs perfectly, but I get access violation reading location when trying to exit main function with last method from CallStack being
ucrtbased.dll!_CrtIsValidHeapPointer(const void * block) Line 1385 C++
I read the windows documentation thoroughly regarding the methods I use and checked the Internet for any solution I could find, but without any result. I don't understand this behaviour, getting different errors when running cod multiple times, and therefore I can`t get to a solution for this problem.
Note: The reason I am reading the file in repeated calls is not relevant. I tried reading with a single call and the result is the same.
Thank you in advance
You are allocating a single char for bytesRead, not an array of fileSize chars:
char* bytesRead;
bytesRead = new char(fileSize); // allocate a char and initialize it with fileSize value
bytesRead = new char[fileSize]; // allocate an array of fileSize chars