Ok, I have asked a few questions about different facets of trying to accomplish what I want to do. This time I'm having big issues just reading from a named pipe. I think I have harvested enough information to possibly complete the project I am working on if I can set this up properly. I will include all relevant code below, but my mission is this: read the output (continuously) from a program I did not write and post it to the WinAPI. So my problem is that I have just switched from anonymous pipes to named pipes and I am having issues trying to properly set them up so I can retrieve information. I have a framework setup based off of an example from the MSDN.
#define WAIT_TIME 2 // 2s
#define INSTANCES 4 // Number of threads
#define CONNECT_STATE 0
#define READ_STATE 1
#define WRITE_STATE 2
#define WORLDRD 0
#define WORLDWR 1
#define WORLDINRD 2
#define WORLDINWR 3
#define BUFSIZE 0x1000 // Buffer size 4096 (in bytes)
#define PIPE_TIMEOUT 0x1388 // Timeout 5000 (in ms)
void Arc_Redirect::createProcesses()
{
TCHAR programName[]=TEXT("EXEC_PROGRAM.exe");
PROCESS_INFORMATION pi;
STARTUPINFO si;
BOOL bSuccess = FALSE;
ZeroMemory(hEvents,(sizeof(hEvents)*INSTANCES));
ZeroMemory(outStd,(sizeof(PIPE_HANDLES)*INSTANCES));
// Prep pipes
for(int i=0;i<INSTANCES;i++)
{
hEvents[i] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
if(hEvents[i] == NULL)
throw "Could not init program!";
outStd[i].o1.hEvent = hEvents[i];
outStd[i].hPipeInst = ::CreateNamedPipe(
TEXT("\\\\.\\pipe\\arcworld"), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, BUFSIZE*sizeof(TCHAR), BUFSIZE*sizeof(TCHAR), PIPE_TIMEOUT, NULL);
if(outStd[i].hPipeInst == INVALID_HANDLE_VALUE)
throw "Could not init program!";
outStd[i].pendingIO = getState(outStd[i].hPipeInst,&outStd[i].o1);
outStd[i].dwState = outStd[i].pendingIO ?
CONNECT_STATE : READ_STATE;
}
// Set stuff up
ZeroMemory( &pi, sizeof(PROCESS_INFORMATION));
ZeroMemory( &si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.hStdError = outStd[WORLDRD].hPipeInst;
si.hStdOutput = outStd[WORLDRD].hPipeInst;
si.hStdInput = outStd[WORLDINWR].hPipeInst;
si.dwFlags |= STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES|FILE_FLAG_OVERLAPPED;
// Start our process with the si info
CreateProcess(programName,NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
}
BOOL Arc_Redirect::getState(HANDLE hPipe, LPOVERLAPPED lpo)
{
BOOL connected, pendingIO = FALSE;
// Overlap connection for this pipe
connected = ::ConnectNamedPipe(hPipe,lpo);
if(connected)
throw "ConnectNamedPipe(); failed!";
switch(GetLastError())
{
case ERROR_IO_PENDING:
pendingIO = TRUE;
break;
case ERROR_PIPE_CONNECTED:
if(SetEvent(lpo->hEvent))
break;
default:
throw "ConnectNamedPipe(); failed!";
break;
}
return pendingIO;
}
outStd[INSTANCES] is defined as PIPE_HANDLES (a custom struct) which is below
typedef struct
{
HANDLE hPipeInst;
OVERLAPPED o1;
TCHAR chReq[BUFSIZE];
TCHAR chReply[BUFSIZE];
DWORD dwRead;
DWORD dwWritten;
DWORD dwState;
DWORD cbRet;
BOOL pendingIO;
} PIPE_HANDLES, *LPSTDPIPE;
Now from here is where I am getting a bit lost. I'm not sure where to go. I tried using the loop in the MSDN example, but it didn't work properly for what I am looking to do. I need to take the read end of the pipe and retrieve the information (again, continuously) while having a write end opened as well for whenever I may need to write to it. Does anyone have any ideas? I have been trying to do a ReadFile() as I would do with an anonymous pipe, but it does not appear to be working in the same fashion.
Also, please note: The code is a bit sloppy because I have been working with it, so I apologize. I will definitely be cleaning it up after I get this to function properly.
You should have two OVERLAPPED structures, one for reading and one for writing. Also you need one event handle per pipe for when you want to close the pipe, and one more event when you want to abort all (and close application). You can have one WaitForMultipleObjects for every operation that all pipes are currently involved with, or separate reading from writing in two threads with one WFMO in each. I would go with only one thread, because closing the pipe is then simpler (otherwise you need to have some reference counting on the pipe handle and close it only when reference count drops to zero).
When you get one event then process it, and try WFMO with 0 seconds on all handles that were in the array after the one you just processed. This way no pipe will get starved. When 0 second WFMO elapses repeat normal WFMO from beginning.
If you need high concurrency then process events in separate threads, and omit the currently processing handles from WFMO. However, tracking all the handles then gets a little complicated.
Have you tried passing PIPE_NOWAIT instead of PIPE_WAIT in the CreateNamedPipe call? This will allow ReadFile and WriteFile to be non-blocking.
Alternatively, have you tried using async IO? You're passing the FILE_FLAG_OVERLAPPED flag, so this should work. If you've tried it, what problems did you encounter?
In the linux world, one program can write to a named pipe through write/fwrite calls and another program can read it through read/fread().
The FULL path of the named pipe must be used in read/write operations.
Related
My application runs particular number of processes(different executables) using createprocess(windows api) in parallel(using threads). User can refresh / close my application at any time. As of now, I am pushing the process handles into vector and whenever close request received, I am iterating the vector and terminating(using GetExitCodeProcess and TerminateProcess APIs) and closing(using CloseHandle API) the process handles. Also I am closing the handle of the process when it is completed. The problem with current model is, whenever process completed handle will be closed and when close request received again I will try to close it using vector(handle is not updated). To solve this, I have to update/remove the handle in/from the vector. To do this, need to maintain index.
Since I know the number of process, I want to create a static vector and update it rather than pushing a local object to a vector. Can someone suggest a best approach.
Below is the sample code.
//member object
std::vector<PROCESS_INFORMATION> mProcessHandles;
//this is a thread and will be called multiple times with different executable names in the application
void method(std::string executable)
{
STARTUPINFO startInfo{};
PROCESS_INFORMATION procInfo{};
bool ret = CreateProcess(NULL, executable, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &startInfo, &procInfo);
mProcessInfo.push_back(procInfo);
if(ret)
{
WaitForSingleObject(procInfo.hProcess, INFINITE);
CloseHandle(procInfo.hProcess);
procInfo.hProcess = NULL;
CloseHandle(procInfo.hThread);
procInfo.hThread = NULL;
}
return;
}
//this will be called when application close requested
void forceKill()
{
for (auto &processHandlesIt : mProcessHandles)
{
DWORD errorcode = 0;
GetExitCodeProcess(processHandlesIt.hProcess, &errorcode);
if (errorcode == STILL_ACTIVE)
{
TerminateProcess(processHandlesIt.hProcess, errorcode);
}
CloseHandle(processHandlesIt.hProcess);
processHandlesIt.hProcess = NULL;
CloseHandle(processHandlesIt.hThread);
processHandlesIt.hThread = NULL;
}
}
You should not use handles (in GetExitCodeProcess for example) after they are closed.
I would simply not close those process handles in the threads, and just leave them for the forceKill or other clean-up function to close.
Also, since you are not using procInfo.hThread, you could close it right after CreateProcess returns.
I guess you are not using any other members of the procInfo, so you could only store the process' handles in your vector.
As per subject I'm trying to develop a simple piped parent/child program.
Main purpose of this program is to keep the child process alive and use std::cin and std::cout to communicate between parent/child processes.
On Linux all of this works quite well.
On Windows I've been following the example here and there's one peculiar difference with Linux: one has to invoke
CloseHandle(g_hChildStd_IN_Wr)
To write to the child pipe and flush it. This has the side effect to close the pipe, thus terminating my in-connection to the child process.
I've also tried to use FlushFileBuffers but it doesn't work.
Any idea how can I flush the buffer without having to close the anonymous pipe?
Below sources of both Parent and Child processes.
If the code of the parent process is basically the one in the example above:
// IN_Wr_ is initialized as below with bInheritHandle=TRUE
::CreatePipe(&IN_Rd_, &IN_Wr_, &saAttr, 0);
// and
::SetHandleInformation(IN_Wr_, HANDLE_FLAG_INHERIT, 0)
// When I spawn the child process I do
STARTUPINFO siStartInfo = {0};
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = INVALID_HANDLE_VALUE;
siStartInfo.hStdOutput = OUT_Wr_;
siStartInfo.hStdInput = IN_Rd_;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
...
// then in order to write to std::cin
const DWORD reqSz = static_cast<DWORD>(std::strlen(request));
DWORD written = 0;
while(true) {
DWORD curWritten = 0;
if(!WriteFile(IN_Wr_, request + written, reqSz-written, &curWritten, NULL))
throw std::runtime_error("Error on WriteFile");
written += curWritten;
if(written == reqSz) {
// all written, done
break;
}
}
::FlushFileBuffers(IN_Wr_);
// only when I do this CloseHandle then the child process
// is able to read data
::CloseHandle(IN_Wr_);
this child code is a simple echo server, along the lines of:
buif[2048+1];
while(std::cin) {
std::cin.read(buf, 2048);
const auto rb = std::cin.gcount();
buf[rb] = '\0';
std::cout << buf << std::endl; // this does flush
}
Here's your problem:
std::cin.read(buf, 2048);
It's doing exactly what you've asked it to: waiting until it has read 2048 characters or reaches the end of file. You're not sending 2048 characters, so nothing happens until the server closes the pipe, which counts as the end of file in this context.
Instead, you should be using something like getline(s, 2048, '\0') which will stop reading when it sees a null character. (And, of course, you will need to modify the sender so that it writes that null character at the end of the string.)
Alternatively, you could use the native API: ReadFile has the semantics you seem to be wanting. Ideally you would use a message-mode pipe, which is designed precisely for this sort of use.
The article here might be helpful: https://support.microsoft.com/en-us/kb/190351. It has a section on flushing problems when printf is used to send data to the redirected pipe, which seems to be done in your case. The suggested solution is to use fflush(NULL) to flush the C run-time IO buffers.
It looks like the issue is a MSFT implementation of std::cin::read (and even fread(..., ..., ..., stdin)).
If instead of relying on:
// C++ API
while(std::cin) {
std::cin.read(buf, 2048);
...
// or also "C" API
int rb = 0;
while(0 < (rb = fread(buf, 2048, 1, stdin))) {
...
I do
// Low level Win32 "C" API
while(::ReadFile(hStdin, buf, 2048, &rb, 0)) {
...
// or also low level unix-like "C" API
int rb = 0;
while(0 < (rb = _read(0, buf, 2048))) {
...
The above example just works fine (funnily enough, the call to FlushFileBuffers is not even needed).
I'm trying to read from stderr of a child process. The data is lines of text created with sprintf(stderr, "some debug info\n"). I'm using ReadFileEx with a completion routine. I don't know how many lines of text or how long each line will be. So, what do I put as the nNumberOfBytesToRead parameter?
My guess is I put the max size of my buffer, which I will make 4k; although I don't know if that's an optimal size. I'm guessing that if the line written to stderr is shorter than 4k, the completion routine won't fire. I'm guessing that when the 4k is reached but more data remains, I have to fire off another ReadFileEx within the completion routine. I'll know this is the case because GetLastError will return ERROR_MORE_DATA. I'm hoping that I get a call when the buffer isn't full, but the child process has exited. I'm not sure I get a completion callback when the child process exits, because I passed the stderr write handle to the child when I created it; maybe I get the callback when I close that handle. Are there any race conditions when the child closes wrt to my reading stderr?
Here is the psuedo code of how the process and handles are created:
Attr.bInheritHandle = true
CreatePipe(&hr, &hw, &Attr, 0) and SetHandleInformation(hX, HANDLE_FLAG_INHERIT) on hX the child uses.
Si.hStdXXX = handles from CreatePipe that child uses
CreateProcess(inherit=true, &Si)
Details (Tx extension is a wrapper that throws errors):
HANDLE Create() {
STARTUPINFO SI, *pSI = NULL;
bool fInherit = m_fInherit;
if (m_fStdOut || m_fStdIn || m_fStdErr) {
fInherit = true;
SECURITY_ATTRIBUTES Attr;
Attr.nLength = sizeof(SECURITY_ATTRIBUTES);
Attr.bInheritHandle = TRUE;
Attr.lpSecurityDescriptor = NULL;
if (m_fStdOut) // Create a pipe for the child process's STDOUT. The child will use the write.
CHandle::CreatePipe(m_hStdOutR, m_hStdOutW, &Attr, CP_INHERIT_WRITE);
if (m_fStdErr) // Create a pipe for the child process's STDERR. The child will use the write.
CHandle::CreatePipe(m_hStdErrR, m_hStdErrW, &Attr, CP_INHERIT_WRITE);
if (m_fStdIn) // Create a pipe for the child process's STDIN. The child will use the read.
CHandle::CreatePipe(m_hStdInR, m_hStdInW, &Attr, CP_INHERIT_READ);
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
ZeroStruct(SI);
SI.cb = sizeof(STARTUPINFO);
SI.hStdError = m_hStdErrW, SI.hStdOutput = m_hStdOutW, SI.hStdInput = m_hStdInR;
SI.dwFlags |= STARTF_USESTDHANDLES;
pSI = &SI;
}
// m_fCpu, m_fNuma are masks to set affinity to cpus or numas
CreateProcessTx(NULL, m_szCmdLine, fInherit, m_fFlags, pSI, &m_pi, m_fCpu, m_fNuma, 5);
m_hProc = m_pi.hProcess;
m_hThread = m_pi.hThread;
if (!m_fThread)
m_hThread.Close();
return m_hProc;
}
static void CreatePipe(CHandle &hRead, CHandle &hWrite, SECURITY_ATTRIBUTES* pAttr, BYTE fInheritMask) {
HANDLE hReadTmp = NULL, hWriteTmp = NULL;
CreatePipeTx(hReadTmp, hWriteTmp, pAttr);
SetHandleInformation(hReadTmp, HANDLE_FLAG_INHERIT, (fInheritMask&CP_INHERIT_READ) ? HANDLE_FLAG_INHERIT : 0);
SetHandleInformation(hWriteTmp, HANDLE_FLAG_INHERIT, (fInheritMask&CP_INHERIT_WRITE) ? HANDLE_FLAG_INHERIT : 0);
hRead = hReadTmp;
hWrite = hWriteTmp;
}
Anonymous pipes created with CreatePipe can't used asynchronously. From the Windows SDK documentation:
Asynchronous (overlapped) read and write operations are not supported by anonymous pipes.
This means that you cannot use the ReadFileEx and WriteFileEx functions with anonymous pipes. >In addition, the lpOverlapped parameter of ReadFile and WriteFile is ignored when these >functions are used with anonymous pipes.
Basically CreatePipe doesn't accept a FILE_FLAG_OVERLAPPED flag, and asynchronous I/O requires that you use the flag when creating the file handle.
You'll have to use CreateNamedPipe to create named pipes. The question Overlapped I/O on anonymous pipe has answer with a link to a replacement function MyCreatePipeEx you can use.
Your completion port should receive a zero length read event after attempting to read from a pipe that has been closed on the other end.
To read a variable amount of data from the client process just issue read requests of whatever size you find convenient and be prepared to handle read events that are shorter than you requested. Don't interpret a short but non-zero length as EOF. Keep issuing read requests until you get a zero length read or an error.
Also WaitForMultipleObjects won't work with completion routines, as they're only called while the thread is in an alterable state. Use WaitForMultipleObjectEx with the bAlertable argument set to to true. This function will return WAIT_IO_COMPLETION after running one or more completion routines. In that case you'll probably want to immediately call WaitForMultipleObjectEx again.
I am developing a remote shell like program. for running commands on remote machine I create a cmd.exe process and I redirect its stdin and stdout to a pair of pipes.
I use these pipes to send commands and get the result.
I used ReadFile function for returning the output of command from cmd.exe but I don't know the
exact amount of data that I must read from pipe. so if the data is not ready the readfile
goes to blocking mode and waiting for data.
I am using MSVC++ 2010 and my OS is Win7. Here is a part of my code as an example:
void CpipesDlg::OnBnClickedBtnredirstd()
{
char Cmd[]="dir *.*\r\n";
char Buff[129];
CString str;
HANDLE hStdIn_Read, hStdIn_Write;
HANDLE hStdOut_Read, hStdOut_Write;
SECURITY_ATTRIBUTES sAttr;
STARTUPINFOA StartInf;
PROCESS_INFORMATION procInf;
DWORD dwBytesToWrite,dwBytesReadFrom;
sAttr.nLength = sizeof(sAttr);
sAttr.bInheritHandle = TRUE;
sAttr.lpSecurityDescriptor = NULL;
CreatePipe(&hStdIn_Read,&hStdIn_Write,&sAttr,0);
CreatePipe(&hStdOut_Read,&hStdOut_Write,&sAttr,0);
//SetHandleInformation(hStdIn_Read, HANDLE_FLAG_INHERIT, 0);
//SetHandleInformation(hStdIn_Write, HANDLE_FLAG_INHERIT, 0);
memset(&StartInf,0, sizeof(StartInf));
memset(&procInf,0,sizeof(procInf));
StartInf.cb = sizeof(StartInf);
StartInf.dwFlags = STARTF_USESTDHANDLES;
StartInf.hStdError = hStdOut_Write;
StartInf.hStdOutput = hStdOut_Write;
StartInf.hStdInput = hStdIn_Read;
WriteFile(hStdIn_Write,Cmd,sizeof(Cmd),&dwBytesToWrite,NULL);
if(!CreateProcessA(NULL,"cmd.exe",NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW ,NULL,NULL,&StartInf,&procInf))
{
MessageBoxA(m_hWnd, "Can't Create Process","Error",MB_OK | MB_ICONERROR);
}
WriteFile(hStdIn_Write,Cmd,sizeof(Cmd),&dwBytesToWrite,NULL);
BOOL bSUCCESS =TRUE;
Sleep(100);
while(bSUCCESS)
{
BOOL bResult = ReadFile(hStdOut_Read,Buff,70,&dwBytesReadFrom,NULL);
if(!bResult)
{
break;
}
Buff[dwBytesReadFrom]=0;
str+= Buff;
bSUCCESS = dwBytesReadFrom!=0;
}
m_Disp = str;
UpdateData(FALSE);
CloseHandle(hStdIn_Read);
CloseHandle(hStdIn_Write);
CloseHandle(hStdOut_Read);
CloseHandle(hStdOut_Write);
}
In above code, in debugging mode the first calls to ReadFile function returns
true data but last call of it blocks, because there is no enough data to read.
Here is my Question:
How can I avoid the blocking mode or get the exact number of bytes for reading?
Regards!
You PROBABLY want to use the PeekNamedPipe function, which allows you to interrogate a pipe to see how much data there is available at any given time. If the lpBuffer is NULL then no data is being read.
I'm communicating between two processes on different machines via a pipe, using IO completion routines.
Occasionally, when the completion routine for WriteFileEx gets called, the completion routine parameter dwErrorCode is 0 (i.e. no error), GetOverlappedResult returns true (i.e. no error), but dwNumberOfBytesTransfered does not match nNumberOfBytesToWrite in the call to WriteFileEx. I only see this on the client end of the pipe however.
If the number of bytes transferred does not match the number of bytes that was requested to transfer, how can this be deemed a success?
This is how the client's handle to the pipe is created:
mHPipe = CreateFile(pipeName, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
FILE_FLAG_OVERLAPPED | // overlapped
FILE_FLAG_WRITE_THROUGH, // write through mode
NULL); // no template file
// do some checking...
// The pipe connected; change to message-read mode.
DWORD dwMode = PIPE_READMODE_MESSAGE;
BOOL fSuccess = SetNamedPipeHandleState(mHPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
Can anyone see why this would happen?
Thanks
EDIT:
The relevant WriteFileEx code is as follows:
void WINAPI CompletedWriteRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverLap)
{
BOOL fWrite = FALSE;
LPPIPEINST lpPipeInst = (LPPIPEINST)lpOverLap;
//
// ! 99.9% of the time, dwNumberOfBytesTransfered == lpPipeInst->cbDataSize
// but 0.1% of the time, they do not match
//
// Some stuff
// Copy next message to send
memcpy_s(lpPipeInst->chData, sizeof(lpPipeInst->chData), pMsg->msg, pMsg->size);
lpPipeInst->cbDataSize = pMsg->size;
// Some other stuff
fWrite = WriteFileEx(lpPipeInst->hPipeInst,
lpPipeInst->chData,
lpPipeInst->cbDataSize,
(LPOVERLAPPED) lpPipeInst,
(LPOVERLAPPED_COMPLETION_ROUTINE)CompletedWriteRoutine);
// Some other, other stuff
}
Where LPPIPEINST is declared as:
typedef struct
{
OVERLAPPED oOverlap; // must remain first item
HANDLE hPipeInst;
TCHAR chData[BUFSIZE];
DWORD cbDataSize;
} PIPEINST, *LPPIPEINST;
And the initial call to CompletedWriteRoutine is given the lpOverlap parameter declared thusly:
PIPEINST pipeInstWrite = {0};
pipeInstWrite.hPipeInst = client.getPipeHandle();
pipeInstWrite.oOverlap.hEvent = hEvent[eventWriteComplete];
EDIT:
After trying re-initializing the overlapped structure as Harry suggested, I noticed something peculiar.
I memset the OVERLAPPED structure to zero before each WriteFileEx, and roughly 1/5000 completion routine callbacks, the cbWritten parameter and the OVERLAPPED structure's InternalHigh member was now set to the size of the previous message, instead of the most recent message. I added some logging to file on both the client and server ends of the pipe inside the completion routines, and the data sent and received at both ends was an exact match (and the correct, expected data). This then unveiled that in the time taken to write the data to a file, the InternalHigh member in the OVERLAPPED structure had changed to now reflect the size of the message I was expecting (cbWritten remains the old message size). I removed the file logging, and am now able to reproduce the issue like clockwork with this code:
void WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten, LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst = (LPPIPEINST)lpOverLap;
// Completion routine says it wrote the amount of data from the previous callback
if (cbWritten != lpPipeInst->cbDataSize)
{
// Roughly 1 in 5000 callbacks ends up in here
OVERLAPPED ovl1 = lpPipeInst->oOverlap; // Contains size of previous message, i.e. cbWritten
Sleep(100);
OVERLAPPED ovl2 = lpPipeInst->oOverlap; // Contains size of most recent message, i.e lpPipeInst->cbDataSize
}
...
}
It seems that sometimes, the completion routine is being called before the OVERLAPPED structure and the completion routine input parameter is updated. I'm using MsgWaitForMultipleObjectsEx(eventLast, hEvent, INFINITE, QS_POSTMESSAGE, MWMO_ALERTABLE); for the completion routines to be called on Windows 7 64 bit.
This MSDN page says:
"The system does not use the OVERLAPPED structure after the completion routine is called, so the completion routine can deallocate the memory used by the overlapped structure."
...so apparently, what this code can reproduce should never happen?
Is this a WINAPI bug?
Added FILE_FLAG_NO_BUFFERING to the CreateFile call - haven't seen the problem since. Thanks everyone who commented for your time.