reactos/sdk/tools/pipetools/pipetunnel.cpp

318 lines
6.5 KiB
C++
Raw Normal View History

//
// pipetunnel.cpp
//
// Martin Fuchs, 30.11.2003
//
//
// Invoke as: "pipetunnel [pipe_name]",
// for example: "pipetunnel com_2"
//
// Then start up RectOS in VMWare, wait for the serial connect.
// After that you can connect GDB using the command "target remote :9999".
//
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock.h>
#ifdef _MSC_VER
#pragma comment(lib, "wsock32")
#endif
#include <stdio.h>
#include <errno.h>
// This definition currently missing in MinGW.
#ifndef FILE_FLAG_FIRST_PIPE_INSTANCE
#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000
#endif
static void print_error(DWORD win32_error)
{
fprintf(stderr, "WIN32 error %lu\n", win32_error);
}
#ifdef _DEBUG
// critical section wrapper
struct CritSect : public CRITICAL_SECTION
{
CritSect()
{
InitializeCriticalSection(this);
}
~CritSect()
{
DeleteCriticalSection(this);
}
};
static void dbg_trace(char mode, const char* buffer, int l)
{
static char s_mode = '\0';
static CritSect crit_sect;
EnterCriticalSection(&crit_sect);
if (l) {
for(const char*p=buffer; l--; ++p) {
if (mode != s_mode) {
putchar('\n');
putchar(mode);
putchar(' ');
s_mode = mode;
}
if (*p=='\n' || !*p /*|| *p=='#'*/) {
/*if (*p == '#')
putchar(*p);*/
s_mode = '\0';
} else
putchar(*p);
}
}
LeaveCriticalSection(&crit_sect);
}
#endif
static SOCKET s_srv_socket = (SOCKET)-1;
SOCKET open_tcp_connect()
{
if (s_srv_socket == (SOCKET)-1) {
SOCKADDR_IN srv_addr = {0};
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
srv_addr.sin_port = htons(9999);
s_srv_socket = socket(PF_INET, SOCK_STREAM, 0);
if (s_srv_socket == (SOCKET)-1) {
perror("socket()");
return 0;
}
if (bind(s_srv_socket, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) == -1) {
perror("bind()");
return 0;
}
if (listen(s_srv_socket, 4) == -1) {
perror("listen()");
return 0;
}
}
SOCKADDR_IN rem_addr;
int rem_len = sizeof(rem_addr);
for(;;) {
SOCKET sock = accept(s_srv_socket, (struct sockaddr*)&rem_addr, &rem_len);
if (sock < 0) {
if (errno == EINTR)
continue;
perror("accept()");
return 0;
}
return sock;
}
}
struct WriterThread
{
WriterThread(SOCKET sock, HANDLE hPipe)
: _sock(sock),
_hPipe(hPipe)
{
DWORD tid;
HANDLE hThread = CreateThread(NULL, 0, WriterThreadRoutine, this, 0, &tid);
if (hThread) {
SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
CloseHandle(hThread);
} else
delete this;
}
protected:
SOCKET _sock;
HANDLE _hPipe;
static DWORD WINAPI WriterThreadRoutine(LPVOID param)
{
WriterThread* pThis = (WriterThread*) param;
DWORD ret = pThis->Run();
delete pThis;
return ret;
}
DWORD Run()
{
char buffer[1024];
for(;;) {
int r = recv(_sock, buffer, sizeof(buffer), 0);
if (r == -1) {
perror("recv()");
fprintf(stderr, "debugger connection broken\n");
_sock = (SOCKET)-1;
return 1;
}
if (r) {
DWORD wrote;
if (!WriteFile(_hPipe, buffer, r, &wrote, NULL))
break;
#ifdef _DEBUG
dbg_trace('<', buffer, r);
#endif
}
}
return 0;
}
};
LONG read_pipe(HANDLE hPipe, SOCKET sock)
{
for(;;) {
DWORD read;
char buffer[1024];
// wait for input data
WaitForSingleObject(hPipe, INFINITE);
if (!ReadFile(hPipe, buffer, sizeof(buffer), &read, NULL)) {
DWORD error = GetLastError();
if (error == ERROR_PIPE_LISTENING)
Sleep(1000);
else
return error;
}
if (read) {
#ifdef _DEBUG
dbg_trace('>', buffer, read);
#endif
if (!send(sock, buffer, read, 0)) {
perror("send()");
return GetLastError();
}
}
}
}
int main(int argc, char** argv)
{
char path[MAX_PATH];
const char* pipe_name;
if (argc > 1)
pipe_name = *++argv;
else
pipe_name = "com_2";
sprintf(path, "\\\\.\\pipe\\%s", pipe_name);
// initialize winsock
WSADATA wsa_data;
if (WSAStartup(MAKEWORD(2,2), &wsa_data)) {
fprintf(stderr, "WSAStartup() failed\n");
return 0;
}
// increment priority to be faster than the cpu eating VMWare process
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
HANDLE hPipe = INVALID_HANDLE_VALUE;
for(;;) {
DWORD read;
if (hPipe == INVALID_HANDLE_VALUE) {
hPipe = CreateNamedPipe(path, PIPE_ACCESS_DUPLEX|FILE_FLAG_FIRST_PIPE_INSTANCE|FILE_FLAG_OVERLAPPED, PIPE_WAIT|PIPE_TYPE_BYTE, 1, 4096, 4096, 30000, NULL);
if (hPipe == INVALID_HANDLE_VALUE) {
print_error(GetLastError());
return 1;
}
}
// wait for the client side of the pipe
while(!ReadFile(hPipe, NULL, 0, &read, NULL) &&
GetLastError()==ERROR_PIPE_LISTENING)
Sleep(1000);
puts("\nnamed pipe connected, now waiting for TCP connection...");
SOCKET sock = open_tcp_connect();
if (sock == (SOCKET)-1)
break;
puts("TCP connection established.");
// launch writer thread
new WriterThread(sock, hPipe);
// launch reader loop
LONG error = read_pipe(hPipe, sock);
// close TCP connectiom
closesocket(sock);
sock = (SOCKET)-1;
// close named pipe
CloseHandle(hPipe);
hPipe = INVALID_HANDLE_VALUE;
if (error == ERROR_BROKEN_PIPE)
puts("\nconnection closed."); // normal connection termination
else {
print_error(GetLastError());
break;
}
}
if (hPipe != INVALID_HANDLE_VALUE)
if (!CloseHandle(hPipe))
print_error(GetLastError());
return 0;
}