Search code examples
c++socketswinsock2unix-socket

Problems intercommunicating processes in c++ using winsock2


I am having terrible trouble intercommunicating processes, using UNIX sockets. My server is written in c++, but I can't get past calling the bind method.

c++ code.

OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Entry"));

    WCHAR strbuf[256];
    WSADATA wsaData;
    int iResult;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wsprintfW(strbuf, L"My Sample Service : WSAStartup failed with error: %d", iResult);
        OutputDebugString(strbuf);
        OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
        return 1;
    }

    int opt = TRUE;
    int master_socket, addrlen, new_socket, client_socket[30],
        max_clients = 30, activity, i, valread, sd;
    int max_sd;
    struct sockaddr_in address;
    
    char buffer[1025];  //data buffer of 1K

    //set of socket descriptors 
    fd_set readfds;

    TIMEVAL tv = { 2, 0 };

    //a message 
    char *message = "ECHO Daemon v1.0 \r\n";

    //initialise all client_socket[] to 0 so not checked 
    for (i = 0; i < max_clients; i++)
    {
        client_socket[i] = 0;
    }

    /*struct addrinfo *result = NULL;
    struct addrinfo hints;

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

    iResult = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        wsprintfW(strbuf, L"My Sample Service : getaddrinfo failed with error: %d", iResult);
        OutputDebugString(strbuf);
        OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit 2"));
        WSACleanup();
        return 1;
    }*/

    //create a master socket 
    if ((master_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == 0)
    {
        OutputDebugString(_T("My Sample Service : socket failed with error"));
        OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
        return 1;
    }

    //set master socket to allow multiple connections , 
    //this is just a good habit, it will work without this 
    if (setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
        sizeof(opt)) < 0)
    {
        OutputDebugString(_T("My Sample Service : setsockopt failed with error"));
        OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
        return 1;
    }

    //type of socket created 
    address.sin_family = AF_UNIX;
    address.sin_addr.s_addr = inet_addr("127.0.0.1"); //I really don't know what to put here
    //address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    ////bind the socket to localhost port 8000 
    //if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
    //{
    //  wsprintfW(strbuf, L"My Sample Service : bind failed with error: %d", WSAGetLastError());
    //  OutputDebugString(strbuf);
    //  OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit 2"));
    //  closesocket(master_socket);
    //  WSACleanup();
    //  return 1;
    //}

    // Setup the TCP listening socket
    iResult = bind(master_socket, (struct sockaddr *)&address, sizeof(address));
    if (iResult == SOCKET_ERROR) {
        wsprintfW(strbuf, L"My Sample Service : bind failed with error: %d", WSAGetLastError());
            OutputDebugString(strbuf);
            OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
            closesocket(master_socket);
            WSACleanup();
            return 1;
    }

    //freeaddrinfo(result);

    //try to specify maximum of 3 pending connections for the master socket 
    if (listen(master_socket, 3) < 0)
    {
        wsprintfW(strbuf, L"My Sample Service : listen failed with error: %d\n", WSAGetLastError());
        OutputDebugString(strbuf);
        OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
        closesocket(master_socket);
        WSACleanup();
        return 1;
    }

    addrlen = sizeof(address);
    //accept the incoming connection 
    
    wsprintfW(strbuf, L"My Sample Service : Listener on port %d", PORT);
    OutputDebugString(strbuf);
    OutputDebugString(_T("My Sample Service: Waiting for connections ..."));

    //  Periodically check if the servC:\Users\Administrator\Desktopice has been requested to stop
    while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
    {
        /*
        * Perform main service function here
        */

        //clear the socket set 
        FD_ZERO(&readfds);

        //add master socket to set 
        FD_SET(master_socket, &readfds);
        max_sd = master_socket;

        //add child sockets to set 
        for (i = 0; i < max_clients; i++)
        {
            //socket descriptor 
            sd = client_socket[i];

            //if valid socket descriptor then add to read list 
            if (sd > 0)
                FD_SET(sd, &readfds);

            //highest file descriptor number, need it for the select function 
            if (sd > max_sd)
                max_sd = sd;
        }

        //wait for an activity on one of the sockets , timeout is NULL , 
        //so wait indefinitely 
        activity = select(max_sd + 1, &readfds, NULL, NULL, &tv);

        if ((activity < 0) && (errno != EINTR))
        {
            OutputDebugString(_T("My Sample Service: select failed with error"));
        }

        //If something happened on the master socket , 
        //then its an incoming connection 
        if (FD_ISSET(master_socket, &readfds))
        {
            if ((new_socket = accept(master_socket,
                (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
            {
                wsprintfW(strbuf, L"My Sample Service : accept failed with error: %d", WSAGetLastError());
                OutputDebugString(strbuf);
                OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
                closesocket(master_socket);
                WSACleanup();
                return 1;
            }

            //inform user of socket number - used in send and receive commands
            wsprintfW(strbuf, L"My Sample Service : New connection , socket fd is %d , ip is : %s , port : %d" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
            OutputDebugString(strbuf);

            //send new connection greeting message
            if (send(new_socket, message, strlen(message), 0) != strlen(message))
            {
                OutputDebugString(_T("My Sample Service: Welcome message sent failed with error"));
            }
            else
            {
                OutputDebugString(_T("My Sample Service: Welcome message sent successfully"));
            }

            //add new socket to array of sockets 
            for (i = 0; i < max_clients; i++)
            {
                //if position is empty 
                if (client_socket[i] == 0)
                {
                    client_socket[i] = new_socket;
                    wsprintfW(strbuf, L"My Sample Service: Adding to list of sockets as %d", i);
                    OutputDebugString(strbuf);
                    break;
                }
            }
        }

        //else its some IO operation on some other socket
        for (i = 0; i < max_clients; i++)
        {
            sd = client_socket[i];

            if (FD_ISSET(sd, &readfds))
            {
                //Check if it was for closing , and also read the 
                //incoming message 
                if ((valread = recv(sd, buffer, 1024, 0)) == 0)
                {
                    //Somebody disconnected , get his details and print 
                    getpeername(sd, (struct sockaddr*)&address, \
                        (socklen_t*)&addrlen);
                    wsprintfW(strbuf, L"My Sample Service: Host disconnected , ip %s , port %d",
                        inet_ntoa(address.sin_addr), ntohs(address.sin_port));
                    OutputDebugString(strbuf);

                    //Close the socket and mark as 0 in list for reuse 
                    closesocket(sd);
                    client_socket[i] = 0;
                }

                //Echo back the message that came in 
                else
                {
                    //set the string terminating NULL byte on the end 
                    //of the data read 
                    buffer[valread] = '\0';
                    send(sd, buffer, strlen(buffer), 0);
                }
            }
        }
    }

The error returned by the bind method is 10022. I only want to accept connections from my own machine. The commented part of the code is because somewhere, I read that for UNIX sockets, getaddrinfo should not be done. Can someone help me to solve my problem??

I can't find any complete example project of process intercommunication using winsock either, if you point me to one it would also be very helpful.

THANK

EDIT

I am trying to intercommunicate two processes in windows. The link left by @Hans_Passant in the comments, points out that for this I must Download the Windows Insiders SDK for the Windows build 17061, but it is not available to everyone, it says: "To access this page, you need to be a member of the Windows Insider Program". so how can I do it?


Solution

  • Unix sockets are already local, you must put nothing but the address family in the address:

           memset(&my_addr, 0, sizeof(my_addr));
           my_addr.sun_family = AF_UNIX;
    

    Example (source: doc):

           int sfd, cfd;
           struct sockaddr_un my_addr, peer_addr;
           socklen_t peer_addr_size;
    
           sfd = socket(AF_UNIX, SOCK_STREAM, 0);
           if (sfd == -1)
               handle_error("socket");
    
           memset(&my_addr, 0, sizeof(my_addr));
           my_addr.sun_family = AF_UNIX;
           strncpy(my_addr.sun_path, MY_SOCK_PATH,
                   sizeof(my_addr.sun_path) - 1);
    
           if (bind(sfd, (struct sockaddr *) &my_addr,
                   sizeof(my_addr)) == -1)
               handle_error("bind");
    
           if (listen(sfd, LISTEN_BACKLOG) == -1)
               handle_error("listen");
    
           /* Now we can accept incoming connections one
              at a time using accept(2). */
    
           peer_addr_size = sizeof(peer_addr);
           cfd = accept(sfd, (struct sockaddr *) &peer_addr,
                        &peer_addr_size);
    

    Update: I would recommend you to stick to TCP sockets:

    master_socket = socket(AF_INET, SOCK_STREAM, 0)
    

    and then:

    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_LOOPBACK;
    address.sin_port = htons(PORT);
    

    Listening in the loopback interface ensures that no connections from the outside world will ever reach the socket.