xref: /reactos/sdk/tools/pipetools/pipespy.cpp (revision c2c66aff)
1 /*
2  * PipeSpy
3  * Copyright (c) 2004, Skywing (skywing@valhallalegends.com)
4  * Released under the GNU GPL for the ReactOS project
5  *
6  * This program can be used to spy on a named pipe in Windows NT(+)
7  * or ReactOS.  It is particularly intended to be used for
8  * understanding the remote kernel debugging protocol used
9  * by windows kd.
10  *
11  * USE:
12  *
13  * PipeSpy \\.\pipe\debug_server \\.\pipe\debug_client > PipeSpy.log
14  *
15  * VMware: act as client, connect to \\.\pipe\debug_server, pipe is connected
16  * to application
17  *
18  * WinDbg -k com:pipe,port=\\.\pipe\debug_client,resets=0
19  *
20  * NOTE:
21  *
22  * This program hasn't really been tested against ReactOS, and has only
23  * been built with Visual Studio .NET 2003.
24  */
25 #include <process.h>
26 #include <windows.h>
27 #include <stdio.h>
28 
29 HANDLE g_DebugServerPipe, g_DebugClientPipe;
30 CRITICAL_SECTION g_OutputLock;
31 
dumphex(const char * buf,int len,int pos)32 void dumphex(const char *buf, int len, int pos)
33 {
34     int i, j;
35     for(j = 0; j < len; j += 16) {
36         for(i = 0; i < 16; i++) {
37             if(i + j < len)
38                 printf("%02x%c", (unsigned char)buf[i + j], j + i + 1 == pos ? '*' : ' ');
39             else
40                 printf("   ");
41         }
42         for(i = 0; i < 16; i++) {
43             if(i + j < len)
44                 printf("%c", buf[i + j] >= ' ' ? buf[i + j] : '.');
45             else
46                 printf(" ");
47         }
48         printf("\n");
49     }
50 }
51 
52 enum {
53     PIPEBUF_INITIAL_SIZE    = 4096,
54     PIPEBUF_MAX_SIZE        = 16384
55 };
56 
57 typedef struct _READ_OVERLAPPED {
58     OVERLAPPED ReadOverlapped;
59     char* Buffer;
60     HANDLE Pipe, OtherPipe;
61     bool Server;
62     bool Connected;
63 } READ_OVERLAPPED;
64 
WritePipeCompletion(DWORD dwErrorCode,DWORD dwNumberOfBytesTransferred,LPOVERLAPPED lpOverlapped)65 VOID WINAPI WritePipeCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped)
66 {
67     if(dwErrorCode) {
68         EnterCriticalSection(&g_OutputLock);
69         printf(lpOverlapped->hEvent ? "Server> Error %u writing to client pipe\n" : "Client> Error %u writing to server pipe\n", dwErrorCode);
70         LeaveCriticalSection(&g_OutputLock);
71     }
72 
73     free((void*)lpOverlapped);
74 }
75 
ReadPipeCompletion(DWORD dwErrorCode,DWORD dwNumberOfBytesTransferred,LPOVERLAPPED lpOverlapped)76 VOID WINAPI ReadPipeCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped)
77 {
78     READ_OVERLAPPED* ReadOverlapped = (READ_OVERLAPPED*)lpOverlapped;
79     LPOVERLAPPED WriteOverlapped;
80 
81     EnterCriticalSection(&g_OutputLock);
82 
83     if(dwErrorCode) {
84         printf(ReadOverlapped->Server ? "Server> Error %u reading from pipe\n" : "Client> Error %u reading from pipe\n", dwErrorCode);
85         ReadOverlapped->Connected = false;
86     } else {
87         SYSTEMTIME SystemTime;
88 
89         GetLocalTime(&SystemTime);
90         printf(ReadOverlapped->Server ? "Server> [%02u:%02u:%02u.%03u] Received %u byte message:\n" : "Client> [%02u:%02u:%02u.%03u] Received %u byte message:\n",
91             SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, dwNumberOfBytesTransferred);
92         dumphex(ReadOverlapped->Buffer, (int)dwNumberOfBytesTransferred, -1);
93         printf("\n");
94     }
95 
96     LeaveCriticalSection(&g_OutputLock);
97 
98     WriteOverlapped = (LPOVERLAPPED)malloc(sizeof(OVERLAPPED)+dwNumberOfBytesTransferred);
99 
100     if(!WriteOverlapped)
101         printf(ReadOverlapped->Server ? "Server> Out of memory\n" : "Client> Out of memory\n");
102     else {
103         ZeroMemory(WriteOverlapped, sizeof(OVERLAPPED));
104         WriteOverlapped->hEvent = (HANDLE)ReadOverlapped->Server;
105         memcpy(((char*)WriteOverlapped)+sizeof(OVERLAPPED), ReadOverlapped->Buffer, dwNumberOfBytesTransferred);
106         WriteFileEx(ReadOverlapped->OtherPipe, ((char*)WriteOverlapped)+sizeof(OVERLAPPED), dwNumberOfBytesTransferred, WriteOverlapped,
107                     WritePipeCompletion);
108     }
109 
110     if(!dwErrorCode) {
111         ZeroMemory(ReadOverlapped, sizeof(OVERLAPPED));
112         ReadFileEx(ReadOverlapped->Pipe, ReadOverlapped->Buffer, PIPEBUF_INITIAL_SIZE, &ReadOverlapped->ReadOverlapped, ReadPipeCompletion);
113     }
114 }
115 
pipeserver(void * param)116 void __cdecl pipeserver(void* param)
117 {
118     READ_OVERLAPPED ReadOverlapped;
119 
120     ReadOverlapped.Pipe = (HANDLE)param, ReadOverlapped.OtherPipe = ReadOverlapped.Pipe == g_DebugServerPipe ? g_DebugClientPipe : g_DebugServerPipe;
121     ReadOverlapped.Server = ReadOverlapped.Pipe == g_DebugServerPipe;
122     ReadOverlapped.Buffer = (char*)malloc(PIPEBUF_INITIAL_SIZE);
123 
124     for(;;) {
125         if(!ConnectNamedPipe(ReadOverlapped.Pipe, 0) && GetLastError() != ERROR_PIPE_CONNECTED) {
126             printf(ReadOverlapped.Server ? "Server> Error %u accepting pipe connection\n" : "Client> Error %u accepting pipe connection\n",
127                    GetLastError());
128             break;
129         }
130 
131         ReadOverlapped.Connected = true;
132         printf(ReadOverlapped.Server ? "Server> Connected\n" : "Client> Connected\n");
133 
134         ZeroMemory(&ReadOverlapped.ReadOverlapped, sizeof(OVERLAPPED));
135         ReadFileEx(ReadOverlapped.Pipe, ReadOverlapped.Buffer, PIPEBUF_INITIAL_SIZE, &ReadOverlapped.ReadOverlapped, ReadPipeCompletion);
136 
137         do {
138             SleepEx(INFINITE, TRUE);
139         } while(ReadOverlapped.Connected) ;
140 
141         DisconnectNamedPipe(ReadOverlapped.Pipe);
142         printf(ReadOverlapped.Server ? "Server> Disconnected\n" : "Client> Disconnected\n");
143     }
144 
145     printf(ReadOverlapped.Server ? "Server> Shutting down\n" : "Client> Shutting down\n");
146 
147     free(ReadOverlapped.Buffer);
148     CloseHandle(ReadOverlapped.Pipe);
149     SleepEx(0, TRUE);
150 }
151 
main(int ac,char ** av)152 int main(int ac, char **av)
153 {
154     if(ac != 3) {
155         printf("syntax: pipespy serverpipe clientpipe\n");
156         return 0;
157     }
158 
159     g_DebugServerPipe = CreateNamedPipe(av[1], PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
160         1, 4096, 4096, NMPWAIT_WAIT_FOREVER, 0);
161 
162     if(g_DebugServerPipe == INVALID_HANDLE_VALUE) {
163         printf("Error %u creating server pipe\n", GetLastError());
164         return 0;
165     }
166 
167     g_DebugClientPipe = CreateNamedPipe(av[2], PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
168                                         1, 4096, 4096, NMPWAIT_WAIT_FOREVER, 0);
169 
170     if(g_DebugClientPipe == INVALID_HANDLE_VALUE) {
171         printf("Error %u creating client pipe\n", GetLastError());
172         CloseHandle(g_DebugServerPipe);
173         return 0;
174     }
175 
176     InitializeCriticalSection(&g_OutputLock);
177     _beginthread(pipeserver, 0, (void*)g_DebugServerPipe);
178     pipeserver((void*)g_DebugClientPipe);
179     DeleteCriticalSection(&g_OutputLock);
180     return 0;
181 }
182 
183 
184 /*
185         while(!Error) {
186             SleepEx(0, TRUE);
187             BufferPos = 0;
188 
189             if(BufferSize > PIPEBUF_MAX_SIZE) {
190                 char* NewBuf = (char*)realloc(Buffer, PIPEBUF_MAX_SIZE);
191 
192                 if(NewBuf) {
193                     Buffer = NewBuf;
194                     BufferSize = PIPEBUF_MAX_SIZE;
195                 }
196             }
197 
198             for(;;) {
199                 char* NewBuf;
200 
201                 if(ReadFile(Pipe, Buffer+BufferPos, BufferSize-BufferPos, &Read, 0)) {
202                     BufferPos += Read;
203                     Error = 0;
204                     break;
205                 }
206 
207                 Error = GetLastError();
208 
209                 printf("Error=%u read=%u\n", Error, Read);
210 
211                 if(Error != ERROR_MORE_DATA) {
212                     printf(Server ? "Server> Error %u reading from pipe\n" : "Client> Error %u reading from pipe\n", GetLastError());
213                     break;
214                 }
215 
216                 NewBuf = (char*)realloc(Buffer, BufferSize << 1);
217 
218                 if(!NewBuf) {
219                     printf(Server ? "Server> Out of memory\n" : "Client> Out of memory\n");
220                     break;
221                 }
222 
223                 BufferSize <<= 1;
224                 BufferPos += Read;
225                 Error = 0;
226             }
227 
228             if(Error)
229                 break;
230 
231             WriteOverlapped = (LPOVERLAPPED)malloc(sizeof(OVERLAPPED)+BufferPos);
232 
233             if(!WriteOverlapped)
234                 printf(Server ? "Server> Out of memory\n" : "Client> Out of memory\n");
235             else {
236                 ZeroMemory(WriteOverlapped, sizeof(OVERLAPPED));
237                 memcpy(((char*)WriteOverlapped)+sizeof(OVERLAPPED), Buffer, BufferPos);
238                 WriteFileEx(OtherPipe, ((char*)WriteOverlapped)+sizeof(OVERLAPPED), BufferPos, WriteOverlapped, WritePipeCompletion);
239             }
240 
241             EnterCriticalSection(&g_OutputLock);
242             printf(Server ? "Server> Received %u byte message:\n" : "Client> Received %u byte message:\n", BufferPos);
243             dumphex(Buffer, (int)BufferPos, -1);
244             printf("\n");
245             LeaveCriticalSection(&g_OutputLock);
246         }
247 
248         DisconnectNamedPipe(Pipe);
249         printf(Server ? "Server> Disconnected\n" : "Client> Disconnected\n");
250 
251  */
252