Named pipe sometimes doesn't work - c++

So I wrote a C++ application that connects to an Unreal Engine 4 game through a named pipe. 95% of the time it works perfectly, but sometimes it doesn't seem to connect properly. It is very random so it is hard for me to find the problem that is causing this. The Server is created in my application and the Client is created in the UE4 game. And sometimes the UE4 game doesn't connect and displays error 121:
//
// MessageId: ERROR_SEM_TIMEOUT
//
// MessageText:
//
// The semaphore timeout period has expired.
//
#define ERROR_SEM_TIMEOUT 121L
As I said the problem occurs very randomly and I can't seem to find a specific reason that could cause the problem. The pipe is successfully created, I can see this in windows powershell (get-childitem \.\pipe).
I was thinking maybe it has something todo with the pipe settings I use?
This is my code for creating the pipe server:
DWORD erPipeServer::CreatePipeServer() {
// create a SECURITY_ATTRIBUTES structure.
if (!CreatePipeSecurity(&pSa))
{
dwError = GetLastError();
//wprintf(L"CreatePipeSecurity failed w/err 0x%08lx\n", dwError);
Cleanup();
return dwError;
}
// Create the named pipe.
hNamedPipe = CreateNamedPipe(
pipename, // Pipe name.
PIPE_ACCESS_DUPLEX, // The pipe is duplex; both server and
// client processes can read from and
// write to the pipe
PIPE_TYPE_MESSAGE | // Message type pipe
PIPE_READMODE_MESSAGE | // Message-read mode
PIPE_NOWAIT, // Blocking mode is enabled
PIPE_UNLIMITED_INSTANCES, // Max. instances
BUFFER_SIZE, // Output buffer size in bytes
BUFFER_SIZE, // Input buffer size in bytes
NMPWAIT_WAIT_FOREVER, // Time-out interval
pSa // Security attributes
);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
dwError = GetLastError();
//wprintf(L"Unable to create named pipe w/err 0x%08lx\n", dwError);
Cleanup();
return dwError;
}
//wprintf(L"The named pipe (%s) is created.\n", pipename);
return dwError;
}
And this is my code for creating the client in Unreal Engine 4:
// Try to open the named pipe identified by the pipe name.
while (true)
{
hPipe = CreateFile(
FULL_PIPE_NAME, // Pipe name
GENERIC_READ | GENERIC_WRITE, // Read and write access
0, // No sharing
NULL, // Default security attributes
OPEN_ALWAYS, // Opens existing pipe
0, // Default attributes
NULL // No template file
);
// If the pipe handle is opened successfully ...
if (hPipe != INVALID_HANDLE_VALUE)
{
GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Green, FString::Printf(TEXT("The named pipe %d is connected."), FULL_PIPE_NAME));
break;
}
dwError = GetLastError();
// Exit if an error other than ERROR_PIPE_BUSY occurs.
if (ERROR_PIPE_BUSY != dwError)
{
GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, FString::Printf(TEXT("Unable to open named pipe ------ %d"),dwError));
goto Cleanup;
}
// All pipe instances are busy, so wait for 5 seconds.
if (!WaitNamedPipe(FULL_PIPE_NAME, 5000))
{
dwError = GetLastError();
GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, FString::Printf(TEXT("Could not open pipe: 5 second wait timed out. %d"),dwError));
**THE 121 ERROR OCCURED HERE^^**
goto Cleanup;
}
}
Could it be a problem with the pipe settings or something? I do not understand why it works almost all the time, but sometimes not with no clear reason why or when...
Thanks for any help in advance!

Ok, so I think I fixed the problem, maybe not in the best way but it seems to work good enough for my purpose.
After managing to reproduce the problem, I started working with the idea that the Handle could be open or busy ( Thanks to Karsten!!). I could bug the game into showing the 121 error by using windows powershell and running \.\pipe\name (where name is the pipes name). This would open the pipe and the game could not connect anymore, displaying error 121.
How I "fixed" it: Recreating the pipe when no connection is made after a second. Normally in my application when the server is connected the client is already ready. So connection should be immediately. When it isn't, now the pipe is recreated after a second and then it will work. Off-course this is not a clean fix, but I have no idea how the handle normally can open, because normally the only application trying to connect to the pipe is the game...
But anyway it is a decent work-around for the 1 in 30 times the problem occured for (still) some strange reason...
Any other ideas would be appreciated but this is working for now I think :)

Related

How to access the file pointer of each blocks of a file from the $MFT file in NTFS?

I am working on file virtualization and versioning project. For that, I need to access the logical blocks of file contents directly without copying into memory. Anyone could you help me with code snippets that works on my 64 bit windows?
I tried the following code to access the MFT file. But it responds like 'Access denied' even though I ran with administrator privileges.
#include<windows.h>
#include<stdio.h>
#include<winioctl.h>
// Format the Win32 system error code to string
void ErrorMessage(DWORD dwCode);
int wmain(int argc, WCHAR **argv){
HANDLE hVolume;
WCHAR lpDrive[] = L"\\\\.\\C:";
PNTFS_VOLUME_DATA_BUFFER ntfsVolData = {0};
BOOL bDioControl = FALSE;
DWORD dwWritten = 0;
hVolume = CreateFile(lpDrive, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
if(hVolume == INVALID_HANDLE_VALUE){
wprintf(L"CreateFile() failed!\n");
ErrorMessage(GetLastError());
if(CloseHandle(hVolume) != 0)
wprintf(L"hVolume handle was closed successfully!\n");
else{
wprintf(L"Failed to close hVolume handle!\n");
ErrorMessage(GetLastError());
}
}
else
wprintf(L"CreateFile() is pretty fine!\n");
ntfsVolData = (PNTFS_VOLUME_DATA_BUFFER)malloc(sizeof(NTFS_VOLUME_DATA_BUFFER)+sizeof(NTFS_EXTENDED_VOLUME_DATA));
bDioControl = DeviceIoControl(hVolume, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, ntfsVolData,sizeof(NTFS_VOLUME_DATA_BUFFER)+sizeof(NTFS_EXTENDED_VOLUME_DATA), &dwWritten, NULL);
if(bDioControl == 0){
wprintf(L"DeviceIoControl() failed!\n");
ErrorMessage(GetLastError());
if(CloseHandle(hVolume) != 0)
wprintf(L"hVolume handle was closed successfully!\n");
else{
wprintf(L"Failed to close hVolume handle!\n");
ErrorMessage(GetLastError());
}
}
getchar();
}
void ErrorMessage(DWORD dwCode){
DWORD dwErrCode = dwCode;
DWORD dwNumChar;
LPWSTR szErrString = NULL; // will be allocated and filled by FormatMessage
dwNumChar = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM, 0, dwErrCode, 0, (LPWSTR)&szErrString, 0,0 ); // since getting message from system tables
if(dwNumChar == 0)wprintf(L"FormatMessage() failed, error %u\n", GetLastError());//else//wprintf(L"FormatMessage() should be fine!\n");
wprintf(L"Error code %u:\n %s\n", dwErrCode, szErrString) ;// This buffer used by FormatMessage()
if(LocalFree(szErrString) != NULL)
wprintf(L"Failed to free up the buffer, error %u\n", GetLastError());//else//wprintf(L"Buffer has been freed\n");
}
CreateFile() failed!
Error code 5:
Access is denied.
hVolume handle was closed successfully!
DeviceIoControl() failed!
Error code 6:
The handle is invalid.
hVolume handle was closed successfully!
Thank you
Admin privileges aren't enough. What you need to do is request backup and restore privileges for your process. MSDN has sample code. Keep in mind that you probably need both SE_BACKUP_NAME and SE_RESTORE_NAME.
The process is a bit cumbersome:
Use OpenProcessToken on your process with TOKEN_ADJUST_PRIVILEGES
Use LookupPrivilegeValue to get the privilege based on the string constants (one for SE_BACKUP_NAME, one for SE_RESTORE_NAME)
Use AdjustTokenPrivileges to acquire the backup and restore privileges
If you do this properly, the rest of your code should work. To actually enumerate the MFT, you'll want to use the FSCTL_ENUM_USN_DATA variant of DeviceIOControl.

GetCommState always false

I was trying to make a simple console program that reads all signals from my mouse plugged in with USB. I faced a problem: GetCommState(nCom, &dcb) always returns zero, which is not very usefull for my task.
Here is the code:
int _tmain(int argc, TCHAR *argv[]) {
DCB dcb;
HANDLE hCom;
BOOL fSuccess;
TCHAR *pcCommPort = TEXT("\\\\.\\HCD0"); // USB name
// Open a handle to the specified com port.
hCom = CreateFile(pcCommPort,
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // not overlapped I/O
NULL); // hTemplate must be NULL for comm devices
if (hCom == INVALID_HANDLE_VALUE) {
// Handle the error.
printf("CreateFile failed with error %d.\n", GetLastError());
Sleep(15000);
return (1);
}
// Initialize the DCB structure.
SecureZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
// Build on the current configuration by first retrieving all current
// settings.
fSuccess = GetCommState(hCom, &dcb);
if (!fSuccess) {
// Handle the error.
printf("GetCommState failed with error %s.\n", GetLastError());
printf("Cannot get first time");
Sleep(12000);
return (2);
}
.......
GetLastError() returns 1, but lurking for this problem gave me no results.
Thats simply a copypaste from msdn example, but it occurs that it didn't work for me.
Tell me please: what should i change to make it return nonzero and let me proceed with another part of task.
USB mice have nothing to do with COM ports, thus calling GetCommState makes no sense at all.
A serial mouse is ancient hardware that is outdated since about 1995. Modern USB mice are based on USB HID protocol.

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

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()

CreateFile fails with error ERROR_SHARING_VIOLATION

Im using the CreateFile api and some times it randomly fails with the error: ERROR_SHARING_VIOLATION.
I have googled and there is almost nothing about this error. The strange thing is next time it is quite happy to open the same file.
Here is my code:
void FileHandle::open(const char* fileName, FILE_MODE mode)
{
if (m_bIsOpen)
close();
HANDLE fh = NULL;
DWORD dwDesiredAccess = GENERIC_READ;
DWORD dwShareMode = FILE_SHARE_READ;
DWORD dwCreationDisposition = OPEN_EXISTING;
switch (mode)
{
case FILE_READ:
break;
case FILE_WRITE:
dwDesiredAccess = GENERIC_WRITE;
dwShareMode = 0;
dwCreationDisposition = CREATE_ALWAYS;
break;
case FILE_APPEND:
dwDesiredAccess = GENERIC_WRITE;
dwShareMode = 0;
dwCreationDisposition = OPEN_ALWAYS;
break;
default:
throw gcException(ERR_INVALID, "The mode was invalid");
break;
}
fh = CreateFile(fileName, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, 0, NULL);
if (!fh || fh == INVALID_HANDLE_VALUE)
throw gcException(ERR_INVALIDFILE, GetLastError(), gcString("Failed to open the file {0}", fileName));
m_hFileHandle = fh;
m_bIsOpen = true;
if (mode == FILE_APPEND)
{
DWORD high = 0;
DWORD low = GetFileSize(fh, &high);
uint64 pos = (((uint64)high)<<32) + (uint64)low;
seek(pos);
}
}
Am i doing something wrong or is there an issue with the api?
Edit:
Im using the full file name (i.e. C:\somefile.txt) and mode=FILE_WRITE
There is nothing wrong with CreateFile - a sharing violation means that something else has the same file open. Which could be your own program, if you have the file open with a share mode of 0, you won't be able to open it again.
When you get the error you can use Process Explorer to determine what processes have the file open.
Is there anti-virus on the machine? Sometimes an AV's (or other software that monitors files) operations and timing can cause sharing conflicts.
This is particularly true if you're opening an existing file for exclusive access (this would be the case for the FILE_WRITE and FILE_APPEND cases if the file already exists).
I mean no disrespect, but I just shot myself in the foot last week on something similar:
Are you sure nothing else has the file open in a way which would prevent the access being requested?
In my case, I had used ctrl-Z in a Linux command window to suspend a program which created a socket connection, then I went to bed. Next morning after a few simple changes, I kept getting "unable to create socket: service in use" messages when running the program. Sadly, I spent hours debugging what I had broken. Once I killed the offending suspended process, it worked fine.
Microsoft say here that this can happen and it up to the application to retry when it does. Horrid but there you go.

Not getting any Response from Named Pipe Server

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?