Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect IO of process to Windows socket

I am new to winsock, I tried to write a server socket that accepts new connection, then it calls an external executable file. How can we redirect the stdin and stdout of the external executable file to the client socket which has been accepted. I googled and found the code below but it does not work. The new process was created successfully but the client could not receive any data from the new process. I am using Windows 7 and Visual Studio 2008 Express edition. Any helps and comments are appreciated. Thank a lot!

the server

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

#pragma comment(lib, "Ws2_32.lib")

#define DEFAULT_PORT "27015"
#define DEFAULT_BUFLEN 512

int _tmain(int argc, _TCHAR* argv[])
{

        WSADATA wsaData;
        int iResult;

        // Initialize Winsock
        iResult = WSAStartup(MAKEWORD(2,2), &wsaData);

        struct addrinfo *result = NULL, *ptr = NULL, hints;

        ZeroMemory(&hints, sizeof (hints));
        hints.ai_family = AF_INET;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_flags = AI_PASSIVE;

        // Resolve the local address and port to be used by the server
        iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);

        SOCKET ListenSocket = INVALID_SOCKET;

        ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);

         // Setup the TCP listening socket
        iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);

        freeaddrinfo(result);

        if ( listen( ListenSocket, SOMAXCONN ) == SOCKET_ERROR ) {
            printf( "Listen failed with error: %ld\n", WSAGetLastError() );
            closesocket(ListenSocket);
            WSACleanup();
            return 1;
        }

        SOCKET ClientSocket;

        ClientSocket = INVALID_SOCKET;

        // Accept a client socket
        ClientSocket = accept(ListenSocket, NULL, NULL);
        if (ClientSocket == INVALID_SOCKET) {
            printf("accept failed: %d\n", WSAGetLastError());
            closesocket(ListenSocket);
            WSACleanup();
            return 1;
        }

        STARTUPINFO si;
        memset( &si, 0, sizeof( si ) );
        si.cb = sizeof( si );
        si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_HIDE;

        si.hStdInput = (HANDLE)ClientSocket;
        si.hStdOutput = (HANDLE)ClientSocket;
        si.hStdError = (HANDLE)ClientSocket;

        PROCESS_INFORMATION pi;

        TCHAR cmd[] = TEXT("C:\\Users\\dell\\Desktop\\hello.exe");

        if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
            printf("create process successfully\n");
            DWORD i = WaitForSingleObject( pi.hProcess, INFINITE );
            printf("%8x\n", i);
        }


        CloseHandle( pi.hProcess );
        CloseHandle( pi.hThread );
        closesocket( ClientSocket );
        WSACleanup();

}

the client

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>


// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")


#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"


int _tmain(int argc, _TCHAR* argv[])
{
        WSADATA wsaData;
        SOCKET ConnectSocket = INVALID_SOCKET;
        struct addrinfo *result = NULL,
                        *ptr = NULL,
                        hints;
        char recvbuf[DEFAULT_BUFLEN];
        int iResult;
        int recvbuflen = DEFAULT_BUFLEN;

        // Initialize Winsock
        iResult = WSAStartup(MAKEWORD(2,2), &wsaData);

        ZeroMemory( &hints, sizeof(hints) );
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;

        // Resolve the server address and port
        iResult = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);

        // Attempt to connect to an address until one succeeds
        for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
            // Create a SOCKET for connecting to server
            ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
                ptr->ai_protocol);
            if (ConnectSocket == INVALID_SOCKET) {
                printf("socket failed with error: %ld\n", WSAGetLastError());
                WSACleanup();
                return 1;
            }

            // Connect to server.
            iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
            if (iResult == SOCKET_ERROR) {
                closesocket(ConnectSocket);
                ConnectSocket = INVALID_SOCKET;
                continue;
            }
            break;
        }

        freeaddrinfo(result);

        if (ConnectSocket == INVALID_SOCKET) {
            printf("Unable to connect to server!\n");
            WSACleanup();
            return 1;
        }

        // Receive until the peer closes the connection
        do {

            iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
            if ( iResult > 0 )
                printf("Bytes received: %d\n", iResult);
            else if ( iResult == 0 )
                printf("Connection closed\n");
            else
                printf("recv failed with error: %d\n", WSAGetLastError());

        } while( iResult > 0 );

        // cleanup
        closesocket(ConnectSocket);
        WSACleanup();

        return 0;
}

external program hello.cpp

int _tmain(int argc, _TCHAR* argv[])
{
    printf("hello world!\n");       
    return 0;
}
like image 293
Dien Nguyen Avatar asked Nov 28 '22 18:11

Dien Nguyen


1 Answers

Actually, you can redirect IO to sockets. Just make sure you open the socket with WSASocket instead of socket(), and do NOT specify the WSA_FLAG_OVERLAPPED.

The reason for this is a bit involved. Any "Standard Handles" that you supply to CreateProcess for I/O redirection must be non-overlapped (i.e, do not support overlapped I/O). sockets on Windows are opened overlapped when created with socket() and non-overlapped if created as above with WSASocket.

Also make sure you set bInheritHandles to TRUE in the StartupInfo

like image 78
a_mole Avatar answered Dec 15 '22 20:12

a_mole