How to use win32 pipe on single application - c++

I'm trying to write to a pipe I created locally (in the same application)
At the moment I have this:
audioPipe = CreateNamedPipe(
L"\\\\.\\pipe\\audioPipe", // name of the pipe
PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
PIPE_TYPE_MESSAGE, // send data as a byte stream
1, // only allow 1 instance of this pipe
0, // no outbound buffer
0, // no inbound buffer
0, // use default wait time
NULL // use default security attributes
);
I don't know how to actually write data to it. I guess using WriteFile() but is there more to it? All examples I read seem to be using a client-server system and I don't need that. I just need to write data to the pipe (so ffmpeg picks it up, hopefully)

Based on comments, you are creating a named pipe that the command-line FFMPEG app will connect to. In order for that to work, you need to do three things:
change your call to CreateNamedPipe() to use PIPE_TYPE_BYTE instead of PIPE_TYPE_MESSAGE, as you will be streaming raw data live to FFMPEG, not messages. That will allow FFMPEG to read data from the pipe using whatever arbitrary buffers, etc it wants, as if it were reading from a real file directly.
audioPipe = CreateNamedPipe(
L"\\\\.\\pipe\\audioPipe", // name of the pipe
PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
PIPE_TYPE_BYTE, // send data as a byte stream
1, // only allow 1 instance of this pipe
0, // no outbound buffer
0, // no inbound buffer
0, // use default wait time
NULL // use default security attributes
);
you need to call ConnectNamedPipe() to accept a connection from FFMPEG before you can then write data to it.
ConnectNamedPipe(audioPipe, NULL);
when running FFMPEG, specify your pipe name as the input filename using the -i parameter, eg: ffmpeg -i \\.\pipe\audioPipe.

There's nothing more to this than calling WriteFile. You'll also need to call ConnectNamedPipe before calling WriteFile to wait for the client to connect.
The client reads from the pipe by opening a handle with CreateFile and then reading using ReadFile.
For a stream of bytes you need PIPE_TYPE_BYTE. Are you sure you want to specify 0 for the buffer sizes?

Related

Named pipe: ReadFile after ConnectNamedPipe return ERROR_BROKEN_PIPE

I reactivated code that I am sure used to work some months ago. It drives me crazy but it does not anymore. I could not find an answer in other questions.
On the server side, I create a pipe using
#define MAX_MESSAGE_LENGTH 1024
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, static_cast<PACL>(0), FALSE);
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
auto pipe_name = _T("\\\\.\\pipe\\") + _serviceName;
HANDLE pipe = CreateNamedPipe(
pipe_name.c_str(),
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1,
MAX_MESSAGE_LENGTH, MAX_MESSAGE_LENGTH, // buffer lengths (advisory)
0, // default timeout of 50ms when WaitNamedPipe uses NMPWAIT_USE_DEFAULT_WAIT
&sa));
Then a thread waits for incoming clients with ConnectNamedPipe. ConnectNamedPipe blocks until a client connects with
HANDLE pipe = CreateFile(
pipe_name.c_str(), // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
FILE_ATTRIBUTE_NORMAL, // default attributes
NULL); // no template file
ConnectNamedPipe on the server then returns with TRUE and GetLastError == 0. But when it tries to call ReadFile to read incoming data on the pipe, ReadFile immediately returns FALSE and GetLastError==ERROR_BROKEN_PIPE.
On client side, CreateFile has returned GetLastError==231, "All pipe instances are busy". Although it is the only client! A call to WaitNamedPipe(pipe, 2000)returns with error code 121, "The semaphore timeout period has expired".
Increasing the number of allowed clients in CreateNamedPipe does not change anything.
It seems the pipe got completely broken in the moment the client tries to connect. But why? Both client and server run on the same machine with same user and even same session.
Another call to ConnectNamedPipe then failed with GLE=232:"The pipe is being closed".
I also had other SECURITY_ATTRIBUTES for CreateNamedPipe, which shall allow for non-elevated users to connect, but that makes no difference.
Also I tried to use CallNamedPipe on the client with the same result.
PathFileExists is the pipe killer! After hours of trying I finally found what breaks the pipe: a simple call to PathFileExists on the pipe name! This was added recently on the client side to check whether the pipe is already created. I had a look at the code changes but I totally missed that. PathFileExists correctly returns true or false but seems to mess up the pipe (as I told it did not help to allow more than one client to connect). Argh!!!

Named-pipe reading timeout

I'm trying to set a timeout to the reading operation of my named pipe.
In order to read from the named pipe, I'm using the ReadFile function.
I read that a timeout can be set for this function with the SetCommTimeouts function but when I try to use it, I get system error 1: "Incorrect function".
Here is my code (this is the client side):
m_pipe = CreateFileA(pipeName, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
if (m_pipe != INVALID_HANDLE_VALUE)
{
DWORD mode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
ok = SetNamedPipeHandleState(m_pipe, &mode, NULL, NULL);
COMMTIMEOUTS cto;
cto.ReadTotalTimeoutConstant = 1000;
BOOL time = SetCommTimeouts(m_pipe, &cto);
}
Am I doing something wrong or the SetCommTimeouts method is not supposed to be used with pipes? Is there any other way to get a reading timeout?
If the purpose of the timeout is to not get stuck forever you may consider a call to PeekNamedPipe(...) in a timed loop. This way you can check whether there is anything to read from time to time.
Alternatively PeekNamedPipe may be used to decide whether a read on the pipe is actually going to get anything before the read is performed. This way a "waiting" read can be avoided.
You cannot use SetCommTimeouts with named pipes. If you want timeouts, you will have to use Async I/O and implement the timeout yourself using CancelIo or CancelIoEx
ReadFile blocks until it read requested amount of bytes or error/abort happen. Overlapped works same, i.e. it completes on same conditions. Tried to implement timeouts using CancelIoEx and figured out that it loses data. Until now see no way to implement timeouts and read only part of requested amount of bytes, or read cached data.

Sending and receiving OOB data through a TCP connection using POCO C++

I need to develop a TCP server capable of receiving periodic urgent out-of-bounds data. I am using the POCO C++ libraries to achieve this. In the (scarce) documentation of the StreamSocket class, I see that this should be a very easy task to achieve: it should be done by setting the SO_OOBINLINE flag when using the receiveBytes() method like so:
n = ss.receiveBytes( buffer, sizeof(buffer), SO_OOBINLINE );
To test this, I made a very simple TCP client (also using the POCO libraries) which uses the "sendUrgent()" method to send the OOB data (a single byte):
ss1.sendUrgent( 0xFF );
When I send the OOB data, nothing happens. The server doesn't seem to notice it.
On the other hand, when I send "normal" data, using the sendBytes() method, if the SO_OOBINLINE flag is set on the StreamSocket, I receive an infinite amount of the same sent data (it keeps reading the same data although nobody is resending it).
What am I missing?
Edit: After #JimR's suggestion and reading this, I have tried:
n = ss.receiveBytes( buffer, sizeof(buffer), MSG_OOB );
And even this:
n = ss.receiveBytes( buffer, sizeof(buffer), SO_OOBINLINE | MSG_OOB );
Both raise the same exception: Invalid argument.
I think (it's been a long time) you should change
n = ss.receiveBytes( buffer, sizeof(buffer), SO_OOBINLINE ); to
n = ss.receiveBytes( buffer, sizeof(buffer), MSG_OOB );
Edit: Along with the above changes, you will need to call setsockopt with the SO_OOBINLINE flag and the appropriate arguments so OOB data will be seen in the normal stream and not in a separate channel. In your case, as stated in the comments, call ss.setOOBInline(true);.
SO_OOBINLINE is a socket option used with setsockopt.
MSG_OOB is a flag for recv and send and company.

Deadlock with WriteFile/ReadFile

I'm using pipes and I got a kind of deadlock on WriteFile/ReadFile. Here is my code :
hProbePipeRet = CreateNamedPipe(
"\\\\.\\pipe\\probePipeRet", // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
5, // client time-out
NULL); // default security attribute
First I create my pipe, then I use it like this in another application:
WriteFile(
hProbePipeRet, // handle to pipe
msg.c_str(), // buffer to write from
msg.size(), // number of bytes to write
&dwBytesWritten, // number of bytes written
NULL); // not overlapped I/O
And I receive it back with :
fSuccess = ReadFile(
myInst->hProbePipeRet, // handle to pipe
buf, // buffer to receive data
BUFSIZE, // size of buffer
&dwBytesRead, // number of bytes read
NULL); // not overlapped I/O
This is very basic and I have two more pipes that do EXACLY the same thing, the only difference is that they are in a different thread, but I need this one only for basic transactions of message.
On the first try, the informations on the pipes are read successfully, but on the second try, if I don't send at least BUFSIZE of data, both WriteFile and ReadFile will block. As I said, I have two more pipes that do the same thing, with the same functions and I don't need to send BUFSIZE of data to have a successful communication.
EDIT : Additionnal infos
The execution goes as follow : A message is sent to the server by pipe1, the message is received then it returns data with hProbePipeRet in my problematic code. The data is read by the client, printed to the screen.
Another message is dispatched using pipe1, received and the result goes again in hProbePipeRet, the client is waiting for at least BUFSIZE of information and I don't know what the server is doing but it's blocked at WriteFile.
This scenario is the same as my others pipes but I don't put hProbePipeRet in a seperate thread to read from it. I'm doing this because I need an answer right after I dispatched the message.
Perhaps you have the problem that you use blocking IO. The call to ReadFile blocks until there is something to read. If you have a loop that calls write and then read it may block in the second call.
Perhaps you should consider using async io. You call the readFile with a event. The event gets set when there is something to read. So there is no need to create multiple threads.
use PIPE_TYPE_BYTE and PIPE_READMODE_BYTE instead of the MESSAGE counter parts. Also the server must not perform any blocking read operations before any client has connected.
See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx
Edit: For the 'must not perform any blocking read operations': This can, according the the documentation lead to a race condition which actually might be your case, however it is hard to tell without seeing more of your code.

About pipe behavior in windows

hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0,
I have two questions about this:
what if the above code is run twice,how many pipes will get created,1 or 2?
if 2,suppose one of the pipe get connected by A,then B tries to connect lpszPipename, is it guaranteed that B will connect to the one that no one has connected?
The second call to CreateNamedPipe with the same name fails, if FILE_FLAG_FIRST_PIPE_INSTANCE flag is used, or connects to the same pipe, if this flag is not used. In the case the second CreateNamedPipe call succeeds, it returns another handle to the same kernel object.
In the fourth parameter of CreateNamedPipe function you can limit how many named pipe instances can be created. If you set it to PIPE_UNLIMITED_INSTANCE as in your example and call the CreateNamedPipe function twice with the same parameters, two instances will be created (they'll share the same pipe name) and two clients will be able to connect to your named pipe server (each of them to one named pipe instance).
For more information look at http://msdn.microsoft.com/en-us/library/aa365594%28v=VS.85%29.aspx