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