I am starting out with named pipes and need to use them for IPC between two local processes. I have both the server and client process using the pipe in nonblocking overlapped mode.
Everything works fine (the server successfully receives a string sent by the client) except that the event passed to ConnectNamedPipe() via the OVERLAPPED structure is not getting signaled as expected (signaled when a client connects).
While the server is blocked on the WaitForSingleObject() call the client process connected to the pipe, sent its data and terminated yet the event does not get signaled. What am I missing?
Server code:
HANDLE hPipe = ::CreateNamedPipeW(
L"\\\\.\\pipe\\ThePipe",
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT,
1,
4096,
4096,
100,
nullptr);
OVERLAPPED ov = {0};
ov.hEvent = ::CreateEventW(nullptr, TRUE, FALSE, nullptr);
BOOL retVal = ::ConnectNamedPipe(hPipe, &ov);
if (retVal == 0)
{
DWORD err = ::GetLastError();
if (err == ERROR_IO_PENDING)
{
::WaitForSingleObject(ov.hEvent, 30000);
}
if (err == ERROR_PIPE_LISTENING)
{
::WaitForSingleObject(ov.hEvent, 30000); // this blocks until time-out???
}
}
You shouldn't use (deprecated) PIPE_NOWAIT together with overlapped mode. PIPE_NOWAIT makes ConnectNamedPipe immediately return ERROR_PIPE_LISTENING if no client is connected; overlapped I/O just doesn't happen, and waiting for event is useless.
Either you set PIPE_NOWAIT and poll the pipe periodically until success, or you set FILE_FLAG_OVERLAPPED and use an event to check/wait for completion.
Related
I am trying to communicate with device through usb hid. At some point I want to read data from the device using winapi. I start by creating file
HidDeviceObject = CreateFile (
(LPCTSTR)DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, //&SecurityAttributes,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
This part seems to work has already been tested. Then I create a thread when initializing my app. The thread looks like this
int result;
BOOL fWaitingOnRead = FALSE;
while(TRUE)
{
if(!write)
{
if (HidDeviceObject != INVALID_HANDLE_VALUE)
{
HIDOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
result = ReadFile(HidDeviceObject, &InputReport, Capabilities.InputReportByteLength, &NumberOfBytesRead, &HIDOverlapped);
if (GetLastError() != ERROR_IO_PENDING)
// Error
else
fWaitingOnRead = TRUE;
if(fWaitingOnRead)
DWORD dwRes = WaitForSingleObject(HIDOverlapped.hEvent, INFINITE);
}
}
}
This code is executed knowing that there is periodically data coming from my other usb device. But the problem is that WaitForSingleObject does not return. Of course by putting a value of for example 500ms instead of INFINITE will get me a timeout code. So what would be the reason for this behavior. Thanks
You're looking for GetOverlappedResult instead of WaitForSingleObject. Don't pick out the event, use the whole OVERLAPPED object.
GetOverlappedResultEx accepts a tiemout value, if you need the 500 milliseconds again.
I wanna get client ip address or host name.
I'm using VS6.0 & VS2010 on Windows 7 Ultimate.
CreateNamedPipe(...) on Server is as follows :
SECURITY_ATTRIBUTES sa = {0};
hPipe = CreateNamedPipe(
_T("\\\\.\\pipe\\AnonymousPipe"), // pipe name
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
0xD000,
0xD000,
NMPWAIT_USE_DEFAULT_WAIT,
&sa);
if (hPipe == INVALID_HANDLE_VALUE)
{
_tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());
return -1;
}
fConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected)
{
printf("Client connected, creating a processing thread.\n");
// Get Information Of Connected Client.
// Client Ip Address or Hostname.
}
How can I detect which client connected to server?
I can see the connection between server and client using netstat cmd line.
netstat -an|find "445"
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING
TCP 0.0.0.0:445 192.168.125.115:4124 ESTABLISHED
TCP 0.0.0.0:445 192.168.125.192:4882 ESTABLISHED
String "192.168.125.115"&"192.168.125.192" is my target.
But I cannot find a way to detect connected client ip in programmatically in VS6.0.
Someone told me that use GetNamedPipeClientComputerName() to solve this problem. But
GetNamedPipeClientComputerName()
Minimum supported client Windows Vista [desktop apps only]
Minimum supported server Windows Server 2008 [desktop apps only]
Many client still using Windows XP.
I have searched a lot to solve the problem, but I could not find the code describing for this.
Thank you for all viewers.
how already answered in comments GetNamedPipeClientComputerName can be used for this. it available from Windows Vista. if want it on xp also it can be implemented in next way:
ULONG AltGetNamedPipeClientComputerName(HANDLE Pipe, PWSTR ClientComputerName, ULONG ClientComputerNameLength)
{
static const char AttributeName[] = "ClientComputerName";
if (HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL))
{
IO_STATUS_BLOCK iosb;
NTSTATUS status = NtFsControlFile(Pipe,
hEvent,
NULL,
NULL,
&iosb,
FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE,
(void*)AttributeName,
sizeof(AttributeName),
ClientComputerName,
ClientComputerNameLength*sizeof(WCHAR));
if (status == STATUS_PENDING)
{
WaitForSingleObject(hEvent, INFINITE);
status = iosb.Status;
}
CloseHandle(hEvent);
return status == STATUS_NOT_FOUND ? ERROR_PIPE_LOCAL : RtlNtStatusToDosError(status);
}
return GetLastError();
}
this is general how really GetNamedPipeClientComputerName implemented internal. however if we use synchronous pipes (so created without FILE_FLAG_OVERLAPPED) we can simplify function - not need create event - NtFsControlFile never return STATUS_PENDING for synchronous handle.
ULONG AltGetNamedPipeClientComputerNameSync(HANDLE Pipe, PWSTR ClientComputerName, ULONG ClientComputerNameLength)
{
static const char AttributeName[] = "ClientComputerName";
IO_STATUS_BLOCK iosb;
NTSTATUS status = NtFsControlFile(Pipe,
hEvent,
NULL,
NULL,
&iosb,
FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE,
(void*)AttributeName,
sizeof(AttributeName),
ClientComputerName,
ClientComputerNameLength*sizeof(WCHAR));
return status == STATUS_NOT_FOUND ? ERROR_PIPE_LOCAL : RtlNtStatusToDosError(status);
}
from another side if we use asynchronous pipe - we can and not wait when FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE completed, but handle it asyncronous like other requests, which you handle async
one very important note - we can not use DeviceIoControl here, but only NtFsControlFile - this is because DeviceIoControl internally check dwIoControlCode and if it for FILE_DEVICE_FILE_SYSTEM call NtFsControlFile otherwise NtDeviceIoControlFile. the FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE defined in ntifs.h (from wdk) as
#define FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)
for FILE_DEVICE_NAMED_PIPE DeviceIoControl call NtDeviceIoControlFile but we need NtFsControlFile exactly.
note that this worked only for server side pipe end (created by CreateNamedPipe) and in case client is remote. otherwise STATUS_NOT_FOUND will be returned from NtFsControlFile. the GetNamedPipeClientComputerName implementation special check for this code and convert it to ERROR_PIPE_LOCAL
I'm trying to make my named pipe server skip the block-wait of the ConnectNamedPipe function until my client tries to connect. So I want is for my code to continue past the ConnetNamedPipe line until the end but keep the connection for my pipe open in the backgroun. If I use the PIPE_NOWAIT mode when creating the pipe it just returns imediatelly and the pipe closes before my client can connect.
I know that I tried doing this using a thread but even when I create a thread and execute the ConnectNamedPipe part of the code within the thread it still waits on this line instead of continuing with my code. Once it reaches the end of my server cpp file code I want to connect to the pipe with my client.
My Pipe:
hPipe = CreateNamedPipe(
lpszPipename,
PIPE_ACCESS_OUTBOUND, // one way access, only send data
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
512,
512,
0,
NULL);
if (hPipe == INVALID_HANDLE_VALUE)
{
Out->msg(ERR,"Creating the pipe failed.");
}
// Create a thread for this client.
hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
InstanceThread, // thread proc
(LPVOID) hPipe, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
if (hThread == NULL)
{
Out->msg(ERR,"Creating the thread failed.");
}
else CloseHandle(hThread);
// Close the pipe.
CloseHandle(hPipe);
My Thread:
DWORD WINAPI InstanceThread(LPVOID lpvParam)
{
Out->msg(output::SEV_INFO,"Waiting for client to connect.");
fConnected = ConnectNamedPipe(hPipe, NULL) ? //This is where the execution hangs
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
HANDLE hHeap = GetProcessHeap();
TCHAR* pchReply = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(TCHAR));
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
HANDLE hPipe = NULL;
// The thread's parameter is a handle to a pipe object instance.
hPipe = (HANDLE) lpvParam;
uint32_t startTime = time(NULL);
uint32_t elapsedTime;
// Loop until done reading
while ((elapsedTime < 60))
{
elapsedTime = difftime(time(NULL), startTime);
// Write to the pipe.
fSuccess = WriteFile(
hPipe, // handle to pipe
pchReply, // buffer to write from
cbReplyBytes, // number of bytes to write
&cbWritten, // number of bytes written
NULL); // not overlapped I/O
if (!fSuccess || cbReplyBytes != cbWritten)
{
Out->msg(ERR,"InstanceThread WriteFile failed.");
break;
}
}
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the pipe, and close the
// handle to this pipe instance.
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
HeapFree(hHeap, 0, pchReply);
Out->msg(output::SEV_INFO,"InstanceThread exitting.\n");
return 1;
}
I'm trying to make my named pipe server skip the block-wait of the ConnectNamedPipe function until my client tries to connect.
So you're talking about the server.
So I want my code to continue past the ConnectNamedPipe line while still being able to connect to my server.
So you're talking about the client.
It doesn't make sense. ConnectNamedPipe() is a server-side function, and you don't have anything useful to do in a thread dedicated to it except block until a client connects. So do that.
I have a long-running console-based application Sender that sends simple text to STDOUT using non-buffered output such as cout << "Message" << flush(). I want to create an MFC dialog-based application (named Receiver) that starts Sender and can read it's output. Receiver should also be able to detect when Sender has died, or be able to kill Sender if it wants to. Sender knows nothing of Reciever, and I can't change Sender's code.
I have asked a separate question about the best way to do this. My first attempt was to create pipes with redirected STDIN and STDOUT for the child process and use asynchronous ReadFileEx calls to read in Sender's data. This isn't working correctly, because the ReadFileEx function only fires once, and only with zero bytes transferred even though I know for a fact that Sender is sending data.
I am creating 2 pipes with redirected STDIN and STDOUT, ala this MS example:
// allow the child process to inherit handles
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(sa);
sa.bInheritHandle = 1;
// create pipes with rerouted stdin & stdout
CreatePipe(&handles[h_Child_StdOut_Read], &handles[h_Child_StdOut_Write], &sa, 0);
SetHandleInformation(handles[h_Child_StdOut_Read], HANDLE_FLAG_INHERIT, 0);
CreatePipe(&handles[h_Child_StdIn_Read], &handles[h_Child_StdIn_Write], &sa, 0);
SetHandleInformation(handles[h_Child_StdIn_Read], HANDLE_FLAG_INHERIT, 0);
...Receiver then goes on to start Sender via CreateProcess():
// create child process
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
si.cb = sizeof(si);
si.hStdOutput = handles[h_Child_StdOut_Write];
si.hStdInput = handles[h_Child_StdIn_Read];
si.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess( 0, "Sender.EXE", 0, 0, 1, 0, 0, 0, &si, &pi);
handles[h_Child_Process] = pi.hProcess;
handles[h_Child_Thread] = pi.hThread;
My main loop is based on WaitForObjectsEx, placed in to an alertable wait state to support the asynch file read. I am waiting on two handles: one that signals when Sender dies prematurely, and one that signals when Receiver's main thread wants Sender to die. Before starting the loop, I kick off an overlapped (asynchronous) file read operation on Sender's STDOUT. Ignore the obvious memory leaks and other hacks -- this is illustrative:
vector<HANDLE> wait_handles;
wait_handles.push_back(handles[h_Die_Sig]);
wait_handles.push_back(handles[h_Child_Process]);
for( bool cont = true; cont; )
{
IO* io = new IO;
memset(io, 0, sizeof(IO));
io->buf_size_ = 16 * 1024;
io->buf_ = new char[io->buf_size_];
memset(io->buf_, 0, io->buf_size_);
io->thread_ = ¶m;
io->file_ = handles[h_Child_StdOut_Read];
if( !ReadFileEx(io->file_, io->buf_, io->buf_size_, io, OnFileRead) )
{
DWORD err = GetLastError();
string err_msg = util::strprintwinerr(err);
}
DWORD rc = WaitForMultipleObjectsEx(wait_handles.size(), &wait_handles[0], FALSE, INFINITE, TRUE);
// ...
}
The IO object above is derived publicly from OVERLAPPED:
struct IO : public OVERLAPPED
{
char* buf_;
DWORD buf_size_;
DWORD read_;
ThreadParam* thread_;
HANDLE file_;
};
When the overlapped Read function completes, I read the incoming data and generate a string:
void CALLBACK OnFileRead(DWORD err, DWORD bytes, OVERLAPPED* ovr)
{
IO* io = static_cast<IO*>(ovr);
string msg(io->buf_, bytes);
}
Sender knows nothing of Receiver, and it sends text to the console using very simple, but non-buffered means.
The problem: I know that Sender is sending data to its STDOUT, but my OnFileRead function is called only once, and only with zero bytes transferred.
Why can't I receive Sender's output this way? Do I have a bug, or am I doing something wrong?
Besides the error pointed out by #DyP, you are assuming that CreatePipe opened the handle in overlapped mode. Your assumption is incorrect. Microsoft documents it:
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.
(Indeed, if you look inside kernel32.dll, on Windows XP for example, CreatePipe does not set the lower bit on the seventh parameter to NtCreateNamedPipeFile; that bit is set when CreateNamedPipe is called with FILE_FLAG_OVERLAPPED.)
Look for Dave Hart's MyCreatePipeEx implementation; it can be used as a drop-in replacement for CreatePipe when overlapped I/O is needed. Simply change PipeSerialNumber++ to InterlockedIncrement(&PipeSerialNumber) to avoid race conditions in MT code.
I think you have a typo:
CreatePipe(&handles[h_Child_StdOut_Read], &handles[h_Child_StdOut_Write], &sa, 0);
SetHandleInformation(handles[h_Child_StdOut_Read], HANDLE_FLAG_INHERIT, 0);
CreatePipe(&handles[h_Child_StdIn_Read], &handles[h_Child_StdIn_Write], &sa, 0);
SetHandleInformation(handles[h_Child_StdIn_Read], HANDLE_FLAG_INHERIT, 0);
change the last one to
SetHandleInformation(handles[h_Child_StdIn_Write], HANDLE_FLAG_INHERIT, 0);
that's also what they do at the MSDN example.
I have created a NamedPipe inside a Windows Service and starting the Service Manually or as the System Starts up.
EDIT:
lpszPipename = TEXT("\\\\.\\pipe\\1stPipe");
OVERLAPPED m_OverLaped;
HANDLE hEvent;
hPipe=CreateNamedPipe (lpszPipename,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT,
PIPE_UNLIMITED_INSTANCES,BUFSIZE,
BUFSIZE,0,NULL);
m_OverLaped.hEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
m_OverLaped.Internal=0;
m_OverLaped.InternalHigh=0;
m_OverLaped.Offset=0;
m_OverLaped.OffsetHigh=0;
ConnectNamedPipe(hPipe,&m_OverLaped);
Now I want to Access the Named Pipe, Write some Message and Response back.
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\1stPipe");
OVERLAPPED m_OverLaped;
m_OverLaped.hEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
m_OverLaped.Internal=0;
m_OverLaped.InternalHigh=0;
m_OverLaped.Offset=0;
m_OverLaped.OffsetHigh=0;
hPipe=CreateFile (lpszPipename, // Gets the Pipename
GENERIC_READ | GENERIC_WRITE,// Client only writes to this pipe.
0, // Do not share this pipe with others.
NULL, // Do not inherit security.
OPEN_EXISTING, // Pipe must exist.
FILE_ATTRIBUTE_NORMAL, // I have no special requirements on
//file attributes
NULL);
dwMode = PIPE_READMODE_MESSAGE;
fSuccess = SetNamedPipeHandleState (hPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
fSuccess = TransactNamedPipe (hPipe, // pipe handle
lpszWrite, // message to server
(lstrlen(lpszWrite)+1)*sizeof(TCHAR),//message length
chReadBuf, // buffer to receive reply
BUFSIZE*sizeof(TCHAR), // size of read buffer
&cbRead, // bytes read
&m_OverLaped);
fSuccess = ReadFile (hPipe, // pipe handle
chReadBuf, // buffer to receive reply
BUFSIZE*sizeof(TCHAR), // size of buffer
&cbRead, // number of bytes read
&m_OverLaped); // overlapped
I have ommited the Error Checking Codes to be make it readable here. I get stuck for long(infinite may be ) time while executing TransactNamedPipe. I must be setting some parameters wrong , but I have tried the options as specified at MSDN.
m_OverLaped.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
...
ConnectNamedPipe(hPipe, &m_OverLaped);
Since the pipe is created with FILE_FLAG_OVERLAPPED flag, you must pass LPOVERLAPPED parameter to every pipe I/O call (including TransactNamedPipe). If function returns FALSE and GetLastError returns ERROR_IO_PENDING, wait for m_OverLaped.hEvent - when it is set, operation is completed.
For starters
m_OverLaped.hEvent=hPipe;
Is wrong, hEvent needs to be set to the event you've created, not the pipe. Before you do the read you need to call:
WaitForSingleObject( oOverlap.hEvent,
and then:
GetOverlappedResult()
Have you got the pipe working in non-overlapped mode?