xref: /reactos/sdk/tools/pipetools/pipetunnel.cpp (revision c2c66aff)
1 //
2 // pipetunnel.cpp
3 //
4 // Martin Fuchs, 30.11.2003
5 //
6 
7 //
8 // Invoke as:   "pipetunnel [pipe_name]",
9 // for example: "pipetunnel com_2"
10 //
11 // Then start up RectOS in VMWare, wait for the serial connect.
12 // After that you can connect GDB using the command "target remote :9999".
13 //
14 
15 
16 #define WIN32_LEAN_AND_MEAN
17 #include <windows.h>
18 
19 #include <winsock.h>
20 
21 #ifdef _MSC_VER
22 #pragma comment(lib, "wsock32")
23 #endif
24 
25 #include <stdio.h>
26 #include <errno.h>
27 
28 
29  // This definition currently missing in MinGW.
30 #ifndef FILE_FLAG_FIRST_PIPE_INSTANCE
31 #define FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000
32 #endif
33 
34 
print_error(DWORD win32_error)35 static void print_error(DWORD win32_error)
36 {
37     fprintf(stderr, "WIN32 error %lu\n", win32_error);
38 }
39 
40 
41 #ifdef _DEBUG
42 
43  // critical section wrapper
44 struct CritSect : public CRITICAL_SECTION
45 {
CritSectCritSect46     CritSect()
47     {
48         InitializeCriticalSection(this);
49     }
50 
~CritSectCritSect51     ~CritSect()
52     {
53         DeleteCriticalSection(this);
54     }
55 };
56 
dbg_trace(char mode,const char * buffer,int l)57 static void dbg_trace(char mode, const char* buffer, int l)
58 {
59     static char s_mode = '\0';
60     static CritSect crit_sect;
61 
62     EnterCriticalSection(&crit_sect);
63 
64     if (l) {
65         for(const char*p=buffer; l--; ++p) {
66             if (mode != s_mode) {
67                 putchar('\n');
68                 putchar(mode);
69                 putchar(' ');
70 
71                 s_mode = mode;
72             }
73 
74             if (*p=='\n' || !*p /*|| *p=='#'*/) {
75                 /*if (*p == '#')
76                     putchar(*p);*/
77 
78                 s_mode = '\0';
79             } else
80                 putchar(*p);
81         }
82     }
83 
84     LeaveCriticalSection(&crit_sect);
85 }
86 
87 #endif
88 
89 
90 static SOCKET s_srv_socket = (SOCKET)-1;
91 
open_tcp_connect()92 SOCKET open_tcp_connect()
93 {
94     if (s_srv_socket == (SOCKET)-1) {
95         SOCKADDR_IN srv_addr = {0};
96 
97         srv_addr.sin_family = AF_INET;
98         srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
99         srv_addr.sin_port = htons(9999);
100 
101         s_srv_socket = socket(PF_INET, SOCK_STREAM, 0);
102         if (s_srv_socket == (SOCKET)-1) {
103             perror("socket()");
104             return 0;
105         }
106 
107         if (bind(s_srv_socket, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) == -1) {
108             perror("bind()");
109             return 0;
110         }
111 
112         if (listen(s_srv_socket, 4) == -1) {
113             perror("listen()");
114             return 0;
115         }
116     }
117 
118     SOCKADDR_IN rem_addr;
119     int rem_len = sizeof(rem_addr);
120 
121     for(;;) {
122         SOCKET sock = accept(s_srv_socket, (struct sockaddr*)&rem_addr, &rem_len);
123 
124         if (sock < 0) {
125             if (errno == EINTR)
126                 continue;
127 
128             perror("accept()");
129             return 0;
130         }
131 
132         return sock;
133     }
134 }
135 
136 
137 
138 struct WriterThread
139 {
WriterThreadWriterThread140     WriterThread(SOCKET sock, HANDLE hPipe)
141         : _sock(sock),
142           _hPipe(hPipe)
143     {
144         DWORD tid;
145 
146         HANDLE hThread = CreateThread(NULL, 0, WriterThreadRoutine, this, 0, &tid);
147 
148         if (hThread) {
149             SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
150 
151             CloseHandle(hThread);
152         } else
153             delete this;
154     }
155 
156 protected:
157     SOCKET  _sock;
158     HANDLE  _hPipe;
159 
WriterThreadRoutineWriterThread160     static DWORD WINAPI WriterThreadRoutine(LPVOID param)
161     {
162         WriterThread* pThis = (WriterThread*) param;
163 
164         DWORD ret = pThis->Run();
165 
166         delete pThis;
167 
168         return ret;
169     }
170 
RunWriterThread171     DWORD Run()
172     {
173         char buffer[1024];
174 
175         for(;;) {
176             int r = recv(_sock, buffer, sizeof(buffer), 0);
177 
178             if (r == -1) {
179                 perror("recv()");
180                 fprintf(stderr, "debugger connection broken\n");
181                 _sock = (SOCKET)-1;
182                 return 1;
183             }
184 
185             if (r) {
186                 DWORD wrote;
187 
188                 if (!WriteFile(_hPipe, buffer, r, &wrote, NULL))
189                     break;
190 
191 #ifdef _DEBUG
192                 dbg_trace('<', buffer, r);
193 #endif
194             }
195         }
196 
197         return 0;
198     }
199 };
200 
201 
read_pipe(HANDLE hPipe,SOCKET sock)202 LONG read_pipe(HANDLE hPipe, SOCKET sock)
203 {
204     for(;;) {
205         DWORD read;
206         char buffer[1024];
207 
208         // wait for input data
209         WaitForSingleObject(hPipe, INFINITE);
210 
211         if (!ReadFile(hPipe, buffer, sizeof(buffer), &read, NULL)) {
212             DWORD error = GetLastError();
213 
214             if (error == ERROR_PIPE_LISTENING)
215                 Sleep(1000);
216             else
217                 return error;
218         }
219 
220         if (read) {
221 #ifdef _DEBUG
222             dbg_trace('>', buffer, read);
223 #endif
224 
225             if (!send(sock, buffer, read, 0)) {
226                 perror("send()");
227                 return GetLastError();
228             }
229         }
230     }
231 }
232 
233 
main(int argc,char ** argv)234 int main(int argc, char** argv)
235 {
236     char path[MAX_PATH];
237     const char* pipe_name;
238 
239     if (argc > 1)
240         pipe_name = *++argv;
241     else
242         pipe_name = "com_2";
243 
244     sprintf(path, "\\\\.\\pipe\\%s", pipe_name);
245 
246 
247     // initialize winsock
248     WSADATA wsa_data;
249 
250     if (WSAStartup(MAKEWORD(2,2), &wsa_data)) {
251         fprintf(stderr, "WSAStartup() failed\n");
252         return 0;
253     }
254 
255 
256     // increment priority to be faster than the cpu eating VMWare process
257     SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
258     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
259 
260 
261     HANDLE hPipe = INVALID_HANDLE_VALUE;
262 
263     for(;;) {
264         DWORD read;
265 
266         if (hPipe == INVALID_HANDLE_VALUE) {
267             hPipe = CreateNamedPipe(path, PIPE_ACCESS_DUPLEX|FILE_FLAG_FIRST_PIPE_INSTANCE|FILE_FLAG_OVERLAPPED, PIPE_WAIT|PIPE_TYPE_BYTE, 1, 4096, 4096, 30000, NULL);
268 
269             if (hPipe == INVALID_HANDLE_VALUE) {
270                 print_error(GetLastError());
271                 return 1;
272             }
273         }
274 
275         // wait for the client side of the pipe
276         while(!ReadFile(hPipe, NULL, 0, &read, NULL) &&
277               GetLastError()==ERROR_PIPE_LISTENING)
278             Sleep(1000);
279 
280         puts("\nnamed pipe connected, now waiting for TCP connection...");
281 
282         SOCKET sock = open_tcp_connect();
283         if (sock == (SOCKET)-1)
284             break;
285 
286         puts("TCP connection established.");
287 
288         // launch writer thread
289         new WriterThread(sock, hPipe);
290 
291         // launch reader loop
292         LONG error = read_pipe(hPipe, sock);
293 
294 
295         // close TCP connectiom
296         closesocket(sock);
297         sock = (SOCKET)-1;
298 
299         // close named pipe
300         CloseHandle(hPipe);
301         hPipe = INVALID_HANDLE_VALUE;
302 
303 
304         if (error == ERROR_BROKEN_PIPE)
305             puts("\nconnection closed.");   // normal connection termination
306         else {
307             print_error(GetLastError());
308             break;
309         }
310     }
311 
312     if (hPipe != INVALID_HANDLE_VALUE)
313         if (!CloseHandle(hPipe))
314             print_error(GetLastError());
315 
316     return 0;
317 }
318