Basic Named Pipe to send data between c++ programs? - c++

I know this has been asked before but I just can't find the answer so I am posting for some help.
I have a DLL, which once injected into a process creates a named pipe. The pipe will wait until a client is connected and will send data to the client until the client disconnects.
The client side, it will just connect to the pipe and receive data and do things with such data.
My question is, I want to be able to send more than 1 type of data, for example, float, int, strings, etc. How do I reconstruct the data into correct data (float, int strings and such)?
Here is my code for the client :
HANDLE hPipe;
DWORD dwWritten;
char Buffer[1024];
hPipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hPipe != INVALID_HANDLE_VALUE)
{
WriteFile(hPipe,
Buffer, //How do I put all the data into a buffer to send over to the client?
sizeof(Buffer), // = length of string + terminating '\0' !!!
&dwWritten,
NULL);
CloseHandle(hPipe);
}
The Server :
wcout << "Creating Pipe..." << endl;
HANDLE hPipe;
char buffer[1024];
DWORD dwRead;
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
1,
1024 * 16,
1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
while (hPipe != INVALID_HANDLE_VALUE)
{
if (ConnectNamedPipe(hPipe, NULL) != FALSE) // wait for someone to connect to the pipe
{
while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
{
/* add terminating zero */
buffer[dwRead] = '\0';
/* do something with data in buffer */
printf("%s", buffer);
}
}
DisconnectNamedPipe(hPipe);
}
My problem is, I have a bunch of data I would like to send to the client in 1 go, which could contain things like float, int, double, etc. Once I gather all the data from the server, I would like to send it to the client and have the client parse it by splitting the data like so :
void split(const string& s, char c,
vector<string>& v) {
string::size_type i = 0;
string::size_type j = s.find(c);
while (j != string::npos) {
v.push_back(s.substr(i, j - i));
i = ++j;
j = s.find(c, j);
if (j == string::npos)
v.push_back(s.substr(i, s.length()));
}
}
I'm sort of lost on how I can send all my data over to the client and correctly get the original value?

You have to use a library that converts your data to something which can be send over a socket. This is called a serializer! You can use a serializer also for serializing into data stream or maybe also in a GUI or whatever. Receiving the data simply needs "deserialize".
You can find a lot of seriaizer libs like:
http://www.boost.org/doc/libs/1_66_0/libs/serialization/doc/index.html
https://uscilab.github.io/cereal/
many many more!
The custom code can look like ( pseudo code! ):
class Check
{
int i;
float f;
template<SERIALIZER_TYPE>
void Serialize( SERIALIZER_TYPE& ser )
{
ser & i & f;
}
};
int main()
{
Check c;
std::string s;
Socket socket( ip, port );
WriteSerializer ser(socket);
ser & c & s;
}
As you can see, you have nothing to write your self for "knowing" how data types are serialized. Classes/structs have to provide a serializer method, so that they also can be split into there native data types.
Edit:
Added question from comments:
Is it possible to send this data from my DLL to the EXE through named pipe instead of saving the file?
For cereal taken from the docs:
cereal comes with excellent standard library support as well as binary, XML, and JSON serializers. If you need something else, cereal was written to be easily extensible for adding custom serialization archives or types.
So one option is simply to write the new interface for your needs.
But take a look into the example code:
void x()
{
std::ofstream file( "out.xml" );
cereal::XMLOutputArchive archive( file ); // depending on the archive type, data may be
// output to the stream as it is serialized, or
// only on destruction
archive( some_data, more_data, data_galore );
}
As you can see there is used a std::ofstream as output. So you can simply use that ofstream which is opened for a socket.
How you can connect a std::ostream with a socket is answered e.g. here:
How can I create an 'ostream' from a socket?
But it is quite simply to this job also by hand. You simply have to write your own buffer class for the socket and connect it to a ofstream. Not more then 10 lines of code I believe!
As a result you can stream now your variables and objects as xml, json or whatever over a socket.
Edit: From the comments: Yes, using a pipe instead a socket will also be adaptable to iostream and the technique is exactly the same and based on implementing something around streambuf.
c++ connect output stream to input stream
I am in hope that on windows it will work the same way and istream is also as ostream adaptable.
To go more in details about a complete solution will not longer fit here in Q&A style I believe. So if there are further questions about connecting something to iostream, please start new question!

If you use WriteFile API to write to pipe, then you can send Buffer of bytes. I like #Klaus idea about serialization to pack all your data and if I need to send objects over pipe from client to server it would be my implementation of choice.
However I consider it overkill if you need to send just some pair of data (like "abc 1.12345"). I would simply put them in the buffer with known delimiter and send from server to client, and then just parse the string on the client.
Answering on your question "//How do I put all the data into a buffer to send over to the client?"
Here's some code snippets:
std::string strToSend;
// ... some initialization
std::wstring wstr = std::wstring(strToSend.begin(), strToSend.end());
LPTSTR pchStr = wstr.c_str();
LPCTSTR pchSend;
StringCchCopy( pchSend, 1024, pchStr );
Use pchSend in WriteFile(hPipe, pchSend, ... call.
Please also check the following example for some code ideas: Named Pipe Client

First of all we need to understand what is a pipe here. Pipe and Queue are medium for communication between multiple process. Every message you submit/drop in a queue or pipe are unique as one set of message and while you are reading it, will read only one message at a time. If you put 10, 20.45 and “Hellow” into a pipe and read them from a client it will read 10 as first message 20.45 as second message and “Hellow” as third message. Normally they will be coming a string value which you need to convert into appropriate type. You should have your own logic to check whether a value is int or float or a normal string. First just read the data and print them all and think how to cope up with them.

Related

Sending/Receiving serial port (COM) data with C++ Handle

I need some help with understanding how to use ReadFile and WriteFile in C++ while using method shown in this guide:
https://www.delftstack.com/howto/cpp/cpp-serial-communication/
My question is, how to use these two functions to send or receive anything? I don't know how to call them properly
I start with Handle:
// Open serial port
HANDLE serialHandle;
serialHandle = CreateFile(L"COM3", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
Next I did some basic settings like setting baud, bytesize etc. I will skip that. And here we come to my problem.
I tried to send some data and receive it (my cable output and input pins are connected). Problem is I don't know how to call ReadFile and WriteFile properly. Here's how I tried to do it:
char sBuff[n + 1] = { 0 };
DWORD send = 0;
cout << "Sent: " << WriteFile(serialHandle, sBuff, n, &send, NULL) << endl;
DWORD dwRead = 0;
cout << "Received: " << ReadFile(serialHandle, sBuff, n, &dwRead, NULL) << endl;
CloseHandle(serialHandle);
}
}
It's just some attempt to guess the correct method. Any example with short explanation will be much appreciated.
Edit: removed useless chunk of code, hope my question is more understandable now
It's all about the handle "serialHandle" being set to the com3 port instead of the file.
The first question, in the layer where you write code, you should not worry about the synchronization or interference of sending and receiving. The serial port handler coordinates it.
Second question, your data is sent as a string of characters that are ASCII. You have to write a function called extract(reciedData) in receiving and place your variables in integer or double or string. In fact, you need a protocol, for example, NMEA .
please search aboat NMEA protocol in google

Epoll reverse proxy stuck while writing client

I am trying to write reverse proxy with nonblocking socket and epoll. That seems ok at first, but when I tried to open a big jpg file, I got stuck.
When I try to write into client sometimes It may not writable and how can I handle proper way.
Additional Notes:
this->getFd() = ProxyFd
this->clientHandler->getFd = clientFd
I am using EPOLLET flag both proxy and client
if( (flag & EPOLLIN) ){
char buffer[1025] = {'\0'};
int readSize;
while( (readSize = read(this->getFd(),buffer,1024)) > 0){
this->headerParse(buffer);
this->readSize += readSize;
int check = 0;
do{
check = write(this->clientHandler->getFd(),buffer,readSize);
}while(check < 0);
}
if(this->headerEnd == 1 && this->readSize >= this->headerLenght ){
close(this->clientHandler->getFd());
close(this->getFd());
delete this->clientHandler;
delete this;
}
}
Thanks for taking time to read.
Assuming your headerParse() method doesn't change buffer in a size-extending way (you'd need to update readsize, at least, not to mention the buffer full scenario), it seems like your write() path is broken.
if the socket you're writing to is also in nonblocking mode, it's perfectly legal for write() to return -1 (and set errno to EGAIN or EWOULDBLOCK or whatever your platform has) before you wrote all data.
In that case, you must store the remaining data (the remainder of buffer minus what was written if one or more calls to write() succeeded), program epoll to notify the clientHandler->getFd() descriptor for writeability, if not already, and when you get subsequent "write ready" event, you write the data you stored. On this case, the write() can again be unable to flush all your data, so you must cycle until all data is sent.

How to send image data over linux socket

I have a relatively simple web server I have written in C++. It works fine for serving text/html pages, but the way it is written it seems unable to send binary data and I really need to be able to send images.
I have been searching and searching but can't find an answer specific to this question which is written in real C++ (fstream as opposed to using file pointers etc.) and whilst this kind of thing is necessarily low level and may well require handling bytes in a C style array I would like the the code to be as C++ as possible.
I have tried a few methods, this is what I currently have:
int sendFile(const Server* serv, const ssocks::Response& response, int fd)
{
// some other stuff to do with headers etc. ........ then:
// open file
std::ifstream fileHandle;
fileHandle.open(serv->mBase + WWW_D + resource.c_str(), std::ios::binary);
if(!fileHandle.is_open())
{
// error handling code
return -1;
}
// send file
ssize_t buffer_size = 2048;
char buffer[buffer_size];
while(!fileHandle.eof())
{
fileHandle.read(buffer, buffer_size);
status = serv->mSock.doSend(buffer, fd);
if (status == -1)
{
std::cerr << "Error: socket error, sending file\n";
return -1;
}
}
return 0
}
And then elsewhere:
int TcpSocket::doSend(const char* message, int fd) const
{
if (fd == 0)
{
fd = mFiledes;
}
ssize_t bytesSent = send(fd, message, strlen(message), 0);
if (bytesSent < 1)
{
return -1;
}
return 0;
}
As I say, the problem is that when the client requests an image it won't work. I get in std::cerr "Error: socket error sending file"
EDIT : I got it working using the advice in the answer I accepted. For completeness and to help those finding this post I am also posting the final working code.
For sending I decided to use a std::vector rather than a char array. Primarily because I feel it is a more C++ approach and it makes it clear that the data is not a string. This is probably not necessary but a matter of taste. I then counted the bytes read for the stream and passed that over to the send function like this:
// send file
std::vector<char> buffer(SEND_BUFFER);
while(!fileHandle.eof())
{
fileHandle.read(&buffer[0], SEND_BUFFER);
status = serv->mSock.doSend(&buffer[0], fd, fileHandle.gcount());
if (status == -1)
{
std::cerr << "Error: socket error, sending file\n";
return -1;
}
}
Then the actual send function was adapted like this:
int TcpSocket::doSend(const char* message, int fd, size_t size) const
{
if (fd == 0)
{
fd = mFiledes;
}
ssize_t bytesSent = send(fd, message, size, 0);
if (bytesSent < 1)
{
return -1;
}
return 0;
}
The first thing you should change is the while (!fileHandle.eof()) loop, because that will not work as you expect it to, in fact it will iterate once too many because the eof flag isn't set until after you try to read from beyond the end of the file. Instead do e.g. while (fileHandle.read(...)).
The second thing you should do is to check how many bytes was actually read from the file, and only send that amount of bytes.
Lastly, you read binary data, not text, so you can't use strlen on the data you read from the file.
A little explanations of the binary file problem: As you should hopefully know, C-style strings (the ones you use strlen to get the length of) are terminated by a zero character '\0' (in short, a zero byte). Random binary data can contain lots of zero bytes anywhere inside it, and it's a valid byte and doesn't have any special meaning.
When you use strlen to get the length of binary data there are two possible problems:
There's a zero byte in the middle of the data. This will cause strlen to terminate early and return the wrong length.
There's no zero byte in the data. That will cause strlen to go beyond the end of the buffer to look for the zero byte, leading to undefined behavior.

How can i tell the client to wait until it received all the data?

this is my first post. i am currently taking a networking class and i am required to write a client program that can download all emails from imap.gmail.com:993 to text files. i am required to write this program using winsock and openssl. I was able to connect to the server and fetch the emails. For emails with small data, i had no problem receiving it. But for emails with large data such as an images that is base64-decoded, i was able to download only a part of it.
so my question is How can i tell the client to wait until it received all the data from the server?
Here is what i have done so far:
void fetchMail(SSL *sslConnection,int lowerLimit, int UpperLimit)
{
SYSTEMTIME lt;
ofstream outfile;
GetLocalTime(&lt);
char szFile[MAX_PATH + 1];
char szPath[MAX_PATH+1];
char message[BUFSIZE];
char result[BUFSIZE];
::GetModuleFileName( NULL, szPath, MAX_PATH );
// Change file name to current full path
LPCTSTR psz = strchr( szPath, '\\');
if( psz != NULL )
{
szPath[psz-szPath] = '\0';
}
char szMailBox[MAX_PATH+1];
memset( szMailBox, 0, sizeof(szMailBox));
wsprintf( szMailBox, "%s\\inbox", szPath );
// Create a folder to store emails
::CreateDirectory( szMailBox, NULL );
for(int i = lowerLimit; i < UpperLimit; ++i)
{
// Create a folder to store emails
memset( szFile, 0, sizeof(szFile));
memset( result, 0, sizeof(result));
memset( message, 0, sizeof(message));
::sprintf(szFile,"%s\\%d%d%d%d%d%d.txt", szMailBox, lt.wHour, lt.wMinute,lt.wMinute,lt.wSecond, lt.wMilliseconds,i);
string Result;//string which will contain the result
stringstream convert; // stringstream used for the conversion
const char * num;
convert << i;//add the value of Number to the characters in the stream
Result = convert.str();//set Result to the content of the stream
num = Result.c_str();
strcpy(result, "tag FETCH ");
strcat(result, num);
strcat(result, " (BODY[TEXT])\r\n");
int n = 0;
cout << "\nFETCHING : \n";
SSL_write(sslConnection, result, strlen(result));
outfile.open(szFile );
SSL_read(sslConnection, message, sizeof(message)-1);
outfile <<message ;
outfile.close();
}
}
First of all some points on your code:
You use strcpy, strcat and all those unchecked, unsafe C functions. You might easily get buffer overflows and other kinds of errors. Consider to use C++ strings, vectors, arrays.
You do a lot of different things in that function, on different levels of abstraction. AFAICS only the two SSL_* function calls are really about fetching that mail. Consider to break out some functions to improve readability.
Now to your problem: Googling a bit about SSL_read, you will see that it returns an int, denoting how many bytes were actually read. You should use that return value - not only for this issue but also for error handling. If the mail data is longer than your buffer, the function will read until the buffer is filled and return its size. You should continue to call the function until all bytes have been read.

Named Pipes, How to know the exact number of bytes to read on Reading side. C++, Windows

I am using Named Pipes configured to send data as a single byte stream to send serialized data structures between two applications. The serialized data changes in size quite dramatically. On the sending side, this is not a problem, I can adjust the number of bytes to send exactly.
How can I set the buffer on the receiveing (Reading) end to the exact number of bytes to read? Is there a way to know how big the data is on the sending (Writing) side is?
I have looked at PeekNamedPipe, but the function appears useless for byte typed named pipes?
lpBytesLeftThisMessage [out, optional]
A pointer to a variable that receives the number of bytes remaining in this message. This parameter will be zero for byte-type named pipes or for anonymous pipes. This parameter can be NULL if no data is to be read.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365779(v=vs.85).aspx
How does one handle such a situation best if you cannot determine the exact required buffer size?
Sending Code
string strData;
strData = "ShortLittleString";
DWORD numBytesWritten = 0;
result = WriteFile(
pipe, // handle to our outbound pipe
strData.c_str(), // data to send
strData.length(), // length of data to send (bytes)
&numBytesWritten, // will store actual amount of data sent
NULL // not using overlapped IO
);
Reading Code:
DWORD numBytesToRead0 = 0;
DWORD numBytesToRead1 = 0;
DWORD numBytesToRead2 = 0;
BOOL result = PeekNamedPipe(
pipe,
NULL,
42,
&numBytesToRead0,
&numBytesToRead1,
&numBytesToRead2
);
char * buffer ;
buffer = new char[numBytesToRead2];
char data[1024]; //1024 is way too big and numBytesToRead2 is always 0
DWORD _numBytesRead = 0;
BOOL result = ReadFile(
pipe,
data, // the data from the pipe will be put here
1024, // number of bytes allocated
&_numBytesRead, // this will store number of bytes actually read
NULL // not using overlapped IO
);
In the code above buffer is always of size 0 as the PeakNamedPipe function returns 0 for all numBytesToRead variables. Is there a way to set this buffer size exactly? If not, what is the best way to handle such a situation? Thanks for any help!
Why do you think you could not use lpTotalBytesAvail to get sent data size? It always works for me in bytes mode. If it's always zero possibly you did something wrong. Also suggest to use std::vector as data buffer, it's quite more safe than messing with raw pointers and new statement.
lpTotalBytesAvail [out, optional] A pointer to a variable that receives the total number of bytes available to be read from the pipe. This parameter can be NULL if no data is to be read.
Sample code:
// Get data size available from pipe
DWORD bytesAvail = 0;
BOOL isOK = PeekNamedPipe(hPipe, NULL, 0, NULL, &bytesAvail, NULL);
if(!isOK)
{
// Check GetLastError() code
}
// Allocate buffer and peek data from pipe
DWORD bytesRead = 0;
std::vector<char> buffer(bytesAvail);
isOK = PeekNamedPipe(hPipe, &buffer[0], bytesAvail, &bytesRead, NULL, NULL);
if(!isOK)
{
// Check GetLastError() code
}
Well, you are using ReadFile(). The documentation says, among other things:
If a named pipe is being read in message mode and the next message is longer
than the nNumberOfBytesToRead parameter specifies, ReadFile returns FALSE and
GetLastError returns ERROR_MORE_DATA. The remainder of the message can be read
by a subsequent call to the ReadFile or PeekNamedPipefunction.
Did you try that? I've never used a pipe like this :-), only used them to get to the stdin/out handles of a child process.
I'm assuming that the above can be repeated as often as necessary, making the "remainder of the message" a somewhat inaccurate description: I think if the "remainder" doesn't fit into your buffer you'll just get another ERROR_MORE_DATA so you know to get the remainder of the remainder.
Or, if I'm completely misunderstanding you and you're not actually using this "message mode" thing: maybe you are just reading things the wrong way. You could just use a fixed size buffer to read data into and append it to your final block, until you've reached the end of the data. Or optimize this a bit by increasing the size of the "fixed" size buffer as you go along.