Console Application to discover Effective Named Pipe Path of a WCF net.pipe Endpoint
As I have promised in my previous post, I am making available a C++ console application to troubleshoot named pipes endpoints in WCF. Below is a screenshot of the application:
Application logic:
- It gets the endpoint from the command line and substitute the host name by +, * depending on the wildcard mode.
- It then add a “/” to the end if not present already and transform to up case all characters of pipe and path
- If the size of the resulting string is bigger than 128 characters a hash is applied to the resulting string (not implemented)
- The final name is net.pipe:E + Base64 of string generated in item 2 or net.pipe:H + Base64 of string generated in item 3 if uri is bigger than 128 characters
Post detailing the problem:
Source Code is as shown below (subject to this license: https://rodneyviana.codeplex.com/license).
// ReadMemory.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
void NormalizeEndPoint(const std::wstring &source, std::wstring& normal)
{
normal.assign(source);
if(!normal.compare(0, 10, L"net.pipe://"))
{
normal.clear();
return;
}
int hoststart = normal.find_first_of(L"//");
int hostend = normal.find(L"/", hoststart+2);
std::wstring ending(normal.substr(hostend));
std::wstring starting(normal.substr(0, hoststart).append(L"//+"));
std::transform(ending.begin(), ending.end(), ending.begin(), (int(*)(int))std::toupper);
std::wstring normalized(starting.append(ending));
if(normalized.substr(normalized.length()-1).compare(L"/"))
{
normalized.append(L"/");
}
normal.assign(normalized);
return;
}
void ShowSyntax(bool SyntaxError)
{
std::wprintf(L"ReadMemory version 1.0\n");
std::wprintf(L"Written by Rodney Viana - https://blogs.msdn.com/rodneyviana\n");
std::wprintf(L"\n");
if(SyntaxError)
std::wprintf(L"Syntax Error\n\n");
std::wprintf(L"Syntax:\n");
std::wprintf(L"ReadMemory <PipeNameEndPoint> | -file <MappedMemoryFile>\n");
std::wprintf(L"Where:\t<PipeNameEndPoint> is a endpoint for a net.pipe in WCF in\n\t the format net.pipe://host/path\n");
std::wprintf(L"\t<MappedMemoryFile> is a memory mapped file\n");
std::wprintf(L"\n");
std::wprintf(L"Examples\n");
std::wprintf(L"\tReadMemory net.pipe://localhost/Service/Service1\n");
std::wprintf(L"\tReadMemory -file \"net.pipe:EbmV0LnBpcGU6Ly8rLzhFNjFFRUM5LUYxOUEtNEIxNy04REE4LTM5NTc1QzhGMTU4QS8=\"\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
if(argc < 2)
{
ShowSyntax(false);
return 0;
}
if(argc > 3)
{
ShowSyntax(true);
return 1;
}
std::wstring original;
std::wstring normalized;
std::wstring mapFile;
if(argc == 2)
{
original.append(argv[1]);
NormalizeEndPoint(original, normalized);
std::wprintf(L"\nOriginal Endpoint: %s", original.c_str());
std::wprintf(L"\nNominal Endpoint: %s", normalized.c_str());
char base64A[1000];
CW2A ansiNormal(normalized.c_str());
int size = 1000;
Base64Encode((BYTE*)ansiNormal.m_psz, normalized.length(), base64A, &size, ATL_BASE64_FLAG_NOCRLF | ATL_BASE64_FLAG_NOPAD );
base64A[size]='=';
base64A[size+1]='';
CA2W base64W(base64A);
mapFile.append(L"net.pipe:E");
mapFile.append(base64W.m_psz);
}
if(argc == 3)
{
std::wstring force(argv[1]);
std::transform(force.begin(), force.end(), force.begin(), (int(*)(int))std::toupper);
if(!force.compare(0, 4, L"-FILE"))
{
ShowSyntax(true);
return 2;
}
mapFile.append(argv[2]);
}
//original.append(L"net.pipe://localhost/TradeService/Service1");
std::wprintf(L"\nMapped Memory Object Name: %s", mapFile.c_str());
HANDLE map = OpenFileMapping(FILE_MAP_READ, FALSE, mapFile.c_str());
MEMORY_BASIC_INFORMATION mi;
if(map)
{
std::wprintf(L"\nGood News: Mapped memory Object was found. It shows that Host is enabled.");
PVOID contents = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
SIZE_T s = VirtualQuery(contents, &mi, sizeof(mi));
if(s<sizeof(GUID)+4)
{
std::wprintf(L"\nMapped memory Object seems to be corrupted. Restart your WCF Host.\n");
}
PBYTE bytes = ((PBYTE)contents)+4;
std::wprintf(L"\nRaw Bytes:\n");
if(contents)
{
for(SIZE_T i=0;i<sizeof(GUID);i++)
{
printf("%02x ", *(bytes+i));
}
std::wprintf(L"\n");
for(SIZE_T i=sizeof(GUID);i<s-4;i++)
{
printf("%02x ", *(bytes+i));
}
GUID *guid = (GUID*)bytes;
RPC_WSTR guidStr;
UuidToString(guid, &guidStr);
std::wprintf(L"\nActual Named Pipe Name: %s", guidStr);
std::wprintf(L"\nFull Named Pipe Name: \\Device\\NamedPipe\\%s", guidStr);
std::wstring localPipe(_T("\\\\.\\pipe\\"));
localPipe.append((LPWSTR)guidStr);
std::wprintf(L"\nAttempting to connect to Named Pipe for 20 seconds ...\n");
if(!WaitNamedPipe(localPipe.c_str(), 20000))
{
std::wprintf(L"\nBad News: Unable to connect to local pipe: %s.\nReason: Time out.", localPipe.c_str());
} else
{
std::wprintf(L"\nGood News: Local pipe \"%s\" is alive.", localPipe.c_str());
HANDLE pipe;
std::wprintf(L"\nAttempting to open Named Pipe...\n");
pipe = CreateFile(localPipe.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL);
if(pipe == INVALID_HANDLE_VALUE)
{
std::wprintf(L"\nBad News: Unable to open local pipe: %s.\nLast Error: %i.", localPipe.c_str(), GetLastError());
} else
{
std::wprintf(L"\nGood News: Named Pipe opened successfully.\n");
TCHAR* send = L"<bad><\\bad>\n";
DWORD bytesUsed;
if(!WriteFile(pipe, (void*)send, wcslen(send)*sizeof(TCHAR), &bytesUsed, NULL))
{
std::wprintf(L"\nBad News: Unable to send bytes.\n");
} else
{
std::wprintf(L"\nGood News: Pipe accepted bytes\n");
std::wprintf(L"\nTest completed successfully!\n");
}
CloseHandle(pipe);
}
}
} else
{
std::wprintf(L"\nBad News: Host is not informing pipe id.");
}
UnmapViewOfFile(map);
} else
{
std::wprintf(L"\nBad News: Mapped File %s was not found. LastError: %x", mapFile.c_str(), GetLastError());
}
CloseHandle(map);
std::wprintf(L"\n");
return 0;
}
Download the project/executable here:
WCF Named Pipes Identification
Comments
Anonymous
October 04, 2011
The comment has been removedAnonymous
October 04, 2011
The comment has been removedAnonymous
October 04, 2011
The comment has been removedAnonymous
October 04, 2011
The comment has been removedAnonymous
July 30, 2015
This may not be possible but can you take the Mapped Memory Object Name and find the application that created it? I am trying to resolve a problem with the situation described here: stackoverflow.com/.../3rd-party-app-breaks-our-wcf-application In my particular situation both pipes are being created by two 3rd part applications. One of my applications fails to run correctly. One of the third party apps is aware of issues with the Garmin software but I don't have that software installed on my machine so I am left with trying to find the offending app. If you can't help with this, I do appreciate your time. Your articles on the name pipes has helped me to better understand the problems I am experiencing,Anonymous
July 30, 2015
Steve, Try to use SysInternals ProcMon and set a filter by path with some part containing the mapped memory file path. It should show you the culprit.