ReadFile(Client end named pipe) Hangs - Win32 VC++ - c++

I have the following code as part of another module that sends messages to the client. This was for IPC. Two dll's are loaded by the exe and these two need to communicate
In DLL-1 I have the following line of code as the server named pipe.
pipe = CreateNamedPipe("\\\\.\\pipe\\S2D8",PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED /**1-way, send only with overlapped IO*/,
PIPE_TYPE_MESSAGE,1,0,0, 0, NULL);
if( INVALID_HANDLE_VALUE != pipe )
{
log("Created Named Pipe as Serverl\n");
}
else
{
log("Cannot create Named Pipe as Server\n");
}
And somewhere else in the DLL-1 I have the following for the server
bool result = ConnectNamedPipe(pipe, NULL);
if (!result)
{
CloseHandle(pipe); // close the pipe
}
else
{
DWORD numWritten;
WriteFile(pipe,KeyBoardBuffer,strlen(KeyBoardBuffer) * sizeof(char),&numWritten,0);
log("Bytes writtern to pipe:%d\n",numWritten);
}
When I look at the logs, I can see the that named pipe. Good so far.
While in DLL-2 I have the following as the client part
log("Connecting to named pipe at client\n");
if(pipe2 == NULL || pipe2 == INVALID_HANDLE_VALUE)
{
pipe2 = CreateFile("\\\\.\\pipe\\S2D8", GENERIC_READ ,
FILE_SHARE_READ | FILE_SHARE_WRITE,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
if (pipe2 == INVALID_HANDLE_VALUE)
{
log("Cannot connect to named pipe at client%x\n", GetLastError());
CloseHandle(pipe2);
}
else
{
log("Connected to named pipe at client! Going to read!!!\n");
char buffer[256] = {'\0'};
DWORD numBytesRead = 0;
BOOL result = ReadFile(
pipe2,
buffer, // the data from the pipe will be put here
sizeof(buffer) * sizeof(char), // number of bytes allocated
&numBytesRead, // this will store number of bytes actually read
NULL // not using overlapped IO
);
if (result)
{
kbBuffer[numBytesRead / sizeof(char)] = '\0'; // null terminate the string
log( "Number of bytes read: %d\n",numBytesRead);
log(kbBuffer );
}
else
{
log("Failed to read data from the pipe.\n");
}
}
}
And in my logs, I can see the line "Connecting to named pipe at client" and then "Connected to named pipe at client! Going to read!!!", after that there is nothing in the log, everything seems stuck.
Is the naming convention of pipe correct? Or is there any security settings I have to define?
I am using VS2010, Win7 x64.
Any guidance is much appreciated.

You're calling the wrong method. The pipe is supposed to pre-exist, so you should be calling OpenFile(), not CreateFile().

Ah, I found the answer to the hang, I had to do a PeekNamedPipe(pipe2, NULL, 0, NULL, &bytesAvailable, NULL); and then check for the bytesAvailable to be greater than zero before I did a ReadFile()

Related

Which ReadFile parameter in this code is incorrect? (Error code 87)

(Edit: I didn't exclude any code except the headers and the main() function's brackets. Nothing is written between lines of code listed here.)
.
I used the ReadFile function to read this COM3 port (which returned no INVALID_HANDLE_VALUE or ERROR_FILE_NOT_FOUND):
LPCTSTR portName = "COM3" ;
HANDLE hSerial;
hSerial = CreateFile(portName,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // default security attributes
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
And the ReadFile function in question uses following parameters:
DWORD n = 512 ;
char szBuff[n] = {0};
DWORD dwBytesRead = 0;
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL))
{
cout << "ReadFile error. Error code: " << GetLastError() << endl ;
cin.get() ;
return 0 ;
}
What changes should I introduce to cause the read to succeed?
(I searched through the function's documentation and other StackOverflow questions, tested lots of things, but couldn't find an answer.)
In ReadFile documentation you can read:
lpOverlapped [in, out, optional]
A pointer to an OVERLAPPED structure is required if the hFile parameter was opened with FILE_FLAG_OVERLAPPED, otherwise it can be NULL.
so since you specified FILE_FLAG_OVERLAPPED in CreateFile you should provide OVERLAPPED in ReadFile.
In CreateFile you can read on parameters for Communications Resources:
... and the handle can be opened for overlapped I/O.
so you can skip FILE_FLAG_OVERLAPPED in CreateFile
Marcin Jędrzejewski's answer is correct about the mismatch between the overlapped IO Flag and the ReadFile function, but I will leave this up just to be helpful.
You are missing a lot of initialisation which may be helpful to you when operating a COM port.
This code is used to open, configure, and read from a COM port on windows using C++.
FOR REFERENCE
READ_BUFFER_SIZE = 1024;
WRITE_BUFFER_SIZE = 1024;
COM_READ_BUFFER_SIZE = 1024;
COM_WRITE_BUFFER_SIZE = 1024;
READ_TIMEOUT = 50;
WRITE_TIMEOUT = 100;
port = "\\.\COM6"
portFormat = "9600,N,8,1" /* for information on this, google the MODE command for windows. */
HANDLE hComPort;
DCB dcbComConfig;
OPENING COM PORT
DWORD dwStoredFlags = EV_BREAK | EV_ERR | EV_RXCHAR;
COMMTIMEOUTS timeouts;
FillMemory(&dcbComConfig, sizeof(dcbComConfig), 0);
dcbComConfig.DCBlength = sizeof(dcbComConfig);
/* assign a COM format to the COM Port. */
if(!BuildCommDCB(portFormat, &dcbComConfig))
{
printf("Failed to build comm format data %s\n", portFormat);
}
/* Open the COM port with overlapped IO. */
hComPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (hComPort == INVALID_HANDLE_VALUE)
{
printf("Error opening port %s\n", port);
}
/* Set the COM Ports internal Read and Write buffer sizes. */
if(!SetupComm(hComPort, COM_READ_BUFFER_SIZE, COM_WRITE_BUFFER_SIZE))
{
printf("Could not set COM buffers\n");
}
/* assign the previously created COM Format to the COM Port. */
if(!SetCommState(hComPort, &dcbComConfig))
{
printf("Error setting com to format data.\n");
}
/* Mask what events you want to look for in the COM Port. */
if (!SetCommMask(hComPort, dwStoredFlags))
{
printf("Error setting communications mask\n");
}
/*-- Read Timeouts set like this so we can use the event based reading. --*/
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 100;
if (!SetCommTimeouts(hComPort, &timeouts))
{
printf("Error setting time-outs.\n");
}
READING COM PORT
DWORD dwRead = 0;
DWORD dwComEvent = EV_RXCHAR;
DWORD lpErrors = 0;
char readBuffer[READ_BUFFER_SIZE];
/* Create the Overlapped IO Read Event. */
OVERLAPPED osRead = {0};
osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
/* Used to monitor the COM Port State. */
COMSTAT ComStatus;
/* Loop at 20Hz to read the COM Port until a Kill event has been set. */
while(WaitForSingleObject(hKillEvent, 50) == WAIT_TIMEOUT)
{
/* Wait for a COM Event to occur ( Read Event in this Case ). */
if (WaitCommEvent(hComPort, &dwComEvent , NULL))
{
/* If the COM Port had an error Clear it. */
ClearCommError(hComPort, &lpErrors, &ComStatus);
/*-- Reset read operation's OVERLAPPED structure's hEvent --*/
ResetEvent(osRead.hEvent);
if (ReadFile(hComPort, readBuffer, ComStatus.cbInQue, &dwRead, &osRead))
{
/*-- bytes have been read; process it --*/
USE_DATA(readBuffer, dwRead);
}
else
{
/*-- An error occurred in the ReadFile call --*/
printf("ReadFile encountered an error.\n");
break;
}
}
else
{
/*-- Error in WaitCommEvent --*/
printf("WaitCommEvent encountered an error.\n");
break;
}
}
/* Close the Overlapped IO Read Event. */
CloseHandle(osRead.hEvent);
The top answer is correct. In this case, opening with FILE_FLAG_OVERLAPPED, ReadFile expects an OVERLAPPED structure as last argument.
Would like to add that you can also get 'parameter is incorrect' error if you do supply an OVERLAPPED struct, but forget to ZeroMemory it.
From the documentation:
Any unused members of this structure should always be initialized to zero before the structure is used in a function call. Otherwise, the function may fail and return ERROR_INVALID_PARAMETER.
So don't forget to:
OVERLAPPED ovl;
ZeroMemory(&ovl, sizeof(ovl));
...
ReadFile(hSerial, szBuff, n, &dwBytesRead, &ovl);

Named pipe wait for client in background until client connects

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.

multiple writefile and readfile in named-pipe

I need to pass some string by pipe. we can't pass a pointer by pipe and we must pass data. for passing a string we can send an array of chars. but I don't want to use array. I need a way to send strings in variable size.
I used msdn samples for creating pipe server and pipe client:
but inestead of only one writeFile and readFile function in pipe client and pipe server I used them three time in this way:
I used a structure for saving my strings size. first of all this structure is sent. then my two string will be sent. so in pipe server at first, the size of strings will be read and after that the two strings will be received.
i defined a structure like this in both client and server programs:
typedef struct
{
int fileNameLen;
int commandArgLen;
}pipeData,*PpipeData;
pipeData dataToWrite;
pipeData *pdataToWrite = &dataToWrite;
in pipe client I want to send this strings:
LPTSTR s1 = TEXT("file1");
LPTSTR s2 = TEXT("startCmd");
dataToWrite.commandArgLen = sizeof(s1);
dataToWrite.fileNameLen = sizeof(s2);
I sent the structure by pipe client in this way.
fSuccess = WriteFile(
hPipe, // pipe handle
pdataToWrite, // message
sizeof(dataToWrite), // message length
&cbWritten, // bytes written
NULL); // not overlapped
if ( ! fSuccess)
{
_tprintf( TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError() );
return -1;
}
fSuccess = WriteFile(
hPipe, // pipe handle
s1, // message
sizeof(s1), // message length
&cbWritten, // bytes written
NULL); // not overlapped
if ( ! fSuccess)
{
_tprintf( TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError() );
return -1;
}
fSuccess = WriteFile(
hPipe, // pipe handle
s2, // message
sizeof(s2), // message length
&cbWritten, // bytes written
NULL); // not overlapped
if ( ! fSuccess)
{
_tprintf( TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError() );
return -1;
}
in pipe server for read the pipe i use 3 readFile like this:
fSuccess = ReadFile(
hPipe, // handle to pipe
pdataToWrite, // buffer to receive data
sizeof(pdataToWrite), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess || cbBytesRead == 0)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
{
_tprintf(TEXT("InstanceThread: client disconnected.\n"), GetLastError());
break;
}
else
{
_tprintf(TEXT("InstanceThread ReadFile failed, GLE=%d.\n"), GetLastError());
break;
}
}
// Process the incoming message.
GetAnswerToRequest(TEXT("structure recieved"), pchReply, &cbReplyBytes);
fSuccess = ReadFile(
hPipe, // handle to pipe
s1, // buffer to receive data
dataToWrite.commandArgLen, // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess || cbBytesRead == 0)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
{
_tprintf(TEXT("InstanceThread: client disconnected.\n"), GetLastError());
}
else
{
_tprintf(TEXT("InstanceThread ReadFile failed, GLE=%d.\n"), GetLastError());
}
break;
}
GetAnswerToRequest(s1, pchReply, &cbReplyBytes);
fSuccess = ReadFile(
hPipe, // handle to pipe
s2, // buffer to receive data
dataToWrite.fileNameLen, // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess || cbBytesRead == 0)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
{
_tprintf(TEXT("InstanceThread: client disconnected.\n"), GetLastError());
}
else
{
_tprintf(TEXT("InstanceThread ReadFile failed, GLE=%d.\n"), GetLastError());
}
break;
}
GetAnswerToRequest(s2, pchReply, &cbReplyBytes);
this way doesn't work properly. when pipe server read data in first readFile, it may return this error : ERROR_MORE_DATA (if I used PIPE_TYPE_MESSAGE in createNamedPipe)
I don't know how can i use multiple writeFile and readFile in pipe client and server.
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 PeekNamedPipe function. By MSDN
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
FYI

how in C++ send file to browser

I need to send file from my directory to user. The problem file was not send.
Can any one help me?
My code is like:
CHttpServerContext* pCtxt;
// ... there i set headers for open
DWORD dwRead;
CString fileName = "c:\txt.doc";
HANDLE hFile = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, (HANDLE) NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return;
}
int c = 0;
CHAR szBuffer [2048];
do
{
if (c++ > 20) {
break;
return;
}
// read chunk of the file
if (!ReadFile (hFile, szBuffer, 2048, &dwRead, NULL))
{
return;
}
if (!dwRead)
// EOF reached, bail out
break;
// Send binary chunk to the browser
if (!pCtxt->WriteClient( szBuffer, &dwRead, 0))
{
return;
}
}
while (1);
CloseHandle (hFile);
}
Doctor, I'm sick. What's wrong with me?
I mean, you give almost no information about what happened.
Do you know if some function returned you an error in your code?
Why do you abort the loop after 20 iterations? This limits you to 40KB.
How exactly do you initialize CHttpServerContext?
You might use high-performance TransmitFile function if you just send the file as-is.
What is your client? How do you know it didn't get the file?
No point in re-inventing the wheel - just use the TransmitFile API instead - it is built into CHttpServerContent::TransmitFile().

C++: Implementing Named Pipes using the Win32 API

I'm trying to implement named pipes in C++, but either my reader isn't reading anything, or my writer isn't writing anything (or both). Here's my reader:
int main()
{
HANDLE pipe = CreateFile(GetPipeName(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
char data[1024];
DWORD numRead = 1;
while (numRead >= 0)
{
ReadFile(pipe, data, 1024, &numRead, NULL);
if (numRead > 0)
cout << data;
}
return 0;
}
LPCWSTR GetPipeName()
{
return L"\\\\.\\pipe\\LogPipe";
}
And here's my writer:
int main()
{
HANDLE pipe = CreateFile(GetPipeName(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
string message = "Hi";
WriteFile(pipe, message.c_str(), message.length() + 1, NULL, NULL);
return 0;
}
LPCWSTR GetPipeName()
{
return L"\\\\.\\pipe\\LogPipe";
}
Does that look right? numRead in the reader is always 0, for some reason, and it reads nothing but 1024 -54's (some weird I character).
Solution:
Reader (Server):
while (true)
{
HANDLE pipe = CreateNamedPipe(GetPipeName(), PIPE_ACCESS_INBOUND | PIPE_ACCESS_OUTBOUND , PIPE_WAIT, 1, 1024, 1024, 120 * 1000, NULL);
if (pipe == INVALID_HANDLE_VALUE)
{
cout << "Error: " << GetLastError();
}
char data[1024];
DWORD numRead;
ConnectNamedPipe(pipe, NULL);
ReadFile(pipe, data, 1024, &numRead, NULL);
if (numRead > 0)
cout << data << endl;
CloseHandle(pipe);
}
Writer (client):
HANDLE pipe = CreateFile(GetPipeName(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (pipe == INVALID_HANDLE_VALUE)
{
cout << "Error: " << GetLastError();
}
string message = "Hi";
cout << message.length();
DWORD numWritten;
WriteFile(pipe, message.c_str(), message.length(), &numWritten, NULL);
return 0;
The server blocks until it gets a connected client, reads what the client writes, and then sets itself up for a new connection, ad infinitum. Thanks for the help, all!
You must use CreateNamedPipe() to create the server end of a named pipe. Be sure to specify a non-zero buffer size, zero (documented by MSDN as 'use system default buffer size') doesn't work. MSDN has decent samples for a multi-threaded client&server.
A named pipe client can open the named pipe with CreateFile -- but the named pipe server needs to use CreateNamedPipe to create the named pipe. After it's created the named pipe, the server uses ConnectNamedPipe to wait for a client to connect. Only after the client has connected should the server do a blocking read like your call to ReadFile.