Reputation: 8704
I am having trouble connecting to a Named Pipe (in this case a fast cgi named pipe) According to MSDN, I should be using CreateFile() or CallNamedPipe() (flat C API, synchronous - no overlapped I/O) http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx
Yet I am getting INVALID_HANDLE_VALUE and when I GetLastError() it is zero!?
I am also wondering if I can just enumerate all the named pipes with a . call of some sort and then parse out the one I am looking for: "\.\pipe\FastCGI\"
and does anyone have experience with these comments: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/225878
Upvotes: 6
Views: 8002
Reputation: 8704
Thank you for catching that. I converted this code to another C like language and used: FILE_NAMES_INFORMATION as I am only looking for the names
I then created a named pipe with another application:
\\.\pipe\test
Upvotes: 0
Reputation: 7825
Ok, I found another bug in the code being used to generate the pipe list (details in the the post about the first bug).
As far as the information in the link following "and does anyone have experience with these comments", I understand what they are talking about, could you be a little more specific about what you don't understand or are curious about (the part about not being able to do non-blocking operations is a bit of a lie btw, though its not done in the "traditional" way of unix systems).
Upvotes: 0
Reputation: 7825
problem lies in here:
TmpInfo = DirInfo;
while(1)
{
if(TmpInfo->NextEntryOffset==0)
break;
TmpInfo->FileDirectoryInformationClass.FileName[TmpInfo->FileNameLength/sizeof(WCHAR)] = NULL;
wprintf(L"%s (%d, %d)\n",TmpInfo->FileDirectoryInformationClass.FileName,
TmpInfo->EndOfFile.LowPart,
TmpInfo->AllocationSize.LowPart );
TmpInfo = (PFILE_QUERY_DIRECTORY)((DWORD)TmpInfo+TmpInfo->NextEntryOffset);
}
just after the "while(1)" you check if the NextEntryOffset == 0
this means that the last entry never gets reported, move the "if(...) break;" to after the "wprintf(...)" call and you should be able to enumerate all of the pipes.
EDIT
For those of you who would like the full source code (without requiring the DDK) here it is. Please not that this is not my code and was found here. The only change between this code and the original is the bug fix as detailed above.
EDIT v2.0
Found another bug in the code below. As it goes to print information about the current item it is iterating through, it places a null character at the end of the name. This null character actually overwrites the first 2 bytes of the next entry, which just happens to overwrite the 2 least significant bytes of the 'NextEntryOffset' variable in that entry (usually resulting making it equal 0), hence only the first 2 items are every enumerated from each 'NtQueryDirectoryFile' call.
I have added a fix to the code below that should resolve this issue (store the WCHAR being cleared and then restoring it after printing. Bit of a hack, but this is just some example code, for a proper implementation, either avoid using wprintf to print the name, or copy it to another buffer that you can safely NULL the end of).
// pipelist.cpp (Windows NT/2000)
//
// This example will show how you can enumerate all named pipes
// active on a system.
//
// (c)2000 Ashot Oganesyan K, SmartLine, Inc
// mailto:[email protected], http://www.protect-me.com, http://www.codepile.com
#include <windows.h>
#include <stdio.h>
#define FileDirectoryInformation 1
#define STATUS_NO_MORE_FILES 0x80000006L
typedef struct
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct
{
LONG Status;
ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef struct {
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
union {
struct {
WCHAR FileName[1];
} FileDirectoryInformationClass;
struct {
DWORD dwUknown1;
WCHAR FileName[1];
} FileFullDirectoryInformationClass;
struct {
DWORD dwUknown2;
USHORT AltFileNameLen;
WCHAR AltFileName[12];
WCHAR FileName[1];
} FileBothDirectoryInformationClass;
};
} FILE_QUERY_DIRECTORY, *PFILE_QUERY_DIRECTORY;
// ntdll!NtQueryDirectoryFile (NT specific!)
//
// The function searches a directory for a file whose name and attributes
// match those specified in the function call.
//
// NTSYSAPI
// NTSTATUS
// NTAPI
// NtQueryDirectoryFile(
// IN HANDLE FileHandle, // handle to the file
// IN HANDLE EventHandle OPTIONAL,
// IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
// IN PVOID ApcContext OPTIONAL,
// OUT PIO_STATUS_BLOCK IoStatusBlock,
// OUT PVOID Buffer, // pointer to the buffer to receive the result
// IN ULONG BufferLength, // length of Buffer
// IN FILE_INFORMATION_CLASS InformationClass,// information type
// IN BOOLEAN ReturnByOne, // each call returns info for only one file
// IN PUNICODE_STRING FileTemplate OPTIONAL, // template for search
// IN BOOLEAN Reset // restart search
// );
typedef LONG (WINAPI *PROCNTQDF)( HANDLE,HANDLE,PVOID,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,
UINT,BOOL,PUNICODE_STRING,BOOL );
PROCNTQDF NtQueryDirectoryFile;
void main(void)
{
LONG ntStatus;
IO_STATUS_BLOCK IoStatus;
HANDLE hPipe;
BOOL bReset = TRUE;
PFILE_QUERY_DIRECTORY DirInfo,
TmpInfo;
NtQueryDirectoryFile = (PROCNTQDF)GetProcAddress(
GetModuleHandle("ntdll"),
"NtQueryDirectoryFile"
);
if (!NtQueryDirectoryFile)
return;
hPipe = CreateFile("\\\\.\\Pipe\\",GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
NULL,OPEN_EXISTING,0,NULL);
if(hPipe == INVALID_HANDLE_VALUE)
return;
DirInfo = (PFILE_QUERY_DIRECTORY) new BYTE[1024];
printf("Pipe name (Number of instances, Maximum instances)\n\n");
while(1)
{
ntStatus = NtQueryDirectoryFile(hPipe,NULL,NULL,NULL,&IoStatus,DirInfo,1024,
FileDirectoryInformation,FALSE,NULL,bReset);
if (ntStatus!=NO_ERROR)
{
if (ntStatus == STATUS_NO_MORE_FILES)
break;
return;
}
TmpInfo = DirInfo;
while(1)
{
// Store old values before we mangle the buffer
const int endStringAt = TmpInfo->FileNameLength/sizeof(WCHAR);
const WCHAR oldValue = TmpInfo->FileDirectoryInformationClass.FileName[endStringAt];
// Place a null character at the end of the string so wprintf doesn't read past the end
TmpInfo->FileDirectoryInformationClass.FileName[endStringAt] = NULL;
wprintf(L"%s (%d, %d)\n",TmpInfo->FileDirectoryInformationClass.FileName,
TmpInfo->EndOfFile.LowPart,
TmpInfo->AllocationSize.LowPart );
// Restore the buffer to its correct state
TmpInfo->FileDirectoryInformationClass.FileName[endStringAt] = oldValue;
if(TmpInfo->NextEntryOffset==0)
break;
TmpInfo = (PFILE_QUERY_DIRECTORY)((DWORD)TmpInfo+TmpInfo->NextEntryOffset);
}
bReset = FALSE;
}
delete DirInfo;
CloseHandle(hPipe);
}
Upvotes: 5
Reputation: 13475
If you want a compiled tool that can do this for you, have a look at "PipeList" from SysInternals (owned by Microsoft).
Upvotes: 4
Reputation: 8704
The first backslash of the pipe name was cut off by the forum software. The pipe name is:
\\.\pipe\test
(It does not need to be escaped in the language I am using for testing)
I wrote two applications, one a pipe server, one a pipe client to test blocking etc They work perfectly.
I create the pipe with:
Pipe_Name = "\\.\pipe\test"
MaxInstances = 1
OutBufferSize = 1024
InBufferSize = 1024
hPipe = CreateNamedPipe(_
Pipe_Name, _ ' Name of the Pipe
PIPE_ACCESS_DUPLEX, _ ' Specifies the pipe access/overlapped/write-through/security access modes
PIPE_TYPE_MESSAGE OR PIPE_READMODE_MESSAGE, _ ' Specifies the type, read, and wait modes of the pipe handle
MaxInstances, _ ' Specifies the maximum number of instances that can be created for this pipe
OutBufferSize, _ ' Specifies the number of bytes to reserve for the output buffer
InBufferSize, _ ' Specifies the number of bytes to reserve for the input buffer
0, _ ' Specifies the default time-out value, in milliseconds
Security_Declaration) ' Pointer to a SECURITY_ATTRIBUTES structure
It does not return INVALID_HANDLE_VALUE, but a valid handle which I use subsequently and works perfectly They block as expected and communicate fine.
Upvotes: 0
Reputation: 8704
Using the undocumented function:
// NtQueryDirectoryFile(
// IN HANDLE FileHandle, // handle to the file
// IN HANDLE EventHandle OPTIONAL,
// IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
// IN PVOID ApcContext OPTIONAL,
// OUT PIO_STATUS_BLOCK IoStatusBlock,
// OUT PVOID Buffer, // pointer to the buffer to receive the result
// IN ULONG BufferLength, // length of Buffer
// IN FILE_INFORMATION_CLASS InformationClass,// information type
// IN BOOLEAN ReturnByOne, // each call returns info for only one file
// IN PUNICODE_STRING FileTemplate OPTIONAL, // template for search
// IN BOOLEAN Reset // restart search
// );
Upvotes: 1
Reputation: 30439
Are you escaping the pipe name properly? It should look like: \\\\.\\pipe\\FastCGI
See the Named Pipe Client Demo for more information.
Upvotes: 1