Search code examples
socketsc++11centosposix

receive wrong address from unix local socket (abstract namespace)


After building and executing the following sample I've obtained next output:

bind to: echosock
rv: 14 data: '[[[SomeData]]]' sz: 14 remAddrLen: 0
client sent: 14

Why remAddrLen is zero? And corresponding remote address was not returned?

#include <cstdlib>
#include <cstdint>
#include <vector>
#include <iostream>
#include <thread>

namespace {                                                                                                                                                                                                   
const char* SOCK_PATH = "echosock";                                                                                                                                                                           
const char* TEST_DATA = "[[[SomeData]]]";                                                                                                                                                                     
}

int main()                                                                                                                                                                                                    
{                                                                                                                                                                                                             
    pid_t childPid = ::fork();                                                                                                                                                                                
    if (childPid == 0)                                                                                                                                                                                        
    {                                                                                                                                                                                                         
        std::this_thread::sleep_for(std::chrono::milliseconds(100));     // hack: wait until server is starting reading                                                                                           
        const int d = ::socket(AF_UNIX, SOCK_DGRAM, 0);                                                                                                                                                       
        if (d == -1)                                                                                                                                                                                          
        {                                                                                                                                                                                                     
            perror("socket");                                                                                                                                                                                 
            return EXIT_FAILURE;                                                                                                                                                                              
        }                                                                                                                                                                                                     

        struct sockaddr_un locAddr;                                                                                                                                                                           
        ::memset(&locAddr, 0, sizeof(locAddr));                                                                                                                                                               
        locAddr.sun_family = AF_UNIX;                                                                                                                                                                         
        ::strncpy(locAddr.sun_path + 1, SOCK_PATH, sizeof(locAddr.sun_path) - 1);                                                                                                                             
        const socklen_t locAddrLen = ::strlen(SOCK_PATH) + 1 + sizeof(locAddr.sun_family);                                                                                                                    
        const int rv = ::sendto(d, TEST_DATA, ::strlen(TEST_DATA), 0, reinterpret_cast<sockaddr*>(&locAddr), locAddrLen);                                                                                     
        std::cout << "client sent: " << rv << std::endl;                                                                                                                                                      
        ::close(d);                                                                                                                                                                                           
    }                                                                                                                                                                                                         
    else if (childPid > 0)                                                                                                                                                                                    
    {                                                                                                                                                                                                         
        const int d = ::socket(AF_UNIX, SOCK_DGRAM, 0);                                                                                                                                                       
        if (d == -1)                                                                                                                                                                                          
        {                                                                                                                                                                                                     
            perror("socket");                                                                                                                                                                                 
            return EXIT_FAILURE;                                                                                                                                                                              
        }                                                                                                                                                                                                     

        std::cout << "bind to: " << SOCK_PATH << std::endl;                                                                                                                                                   
        struct sockaddr_un locAddr;                                                                                                                                                                           
        ::memset(&locAddr, 0, sizeof(locAddr));                                                                                                                                                               
        locAddr.sun_family = AF_UNIX;                                                                                                                                                                         
        ::strncpy(locAddr.sun_path + 1, SOCK_PATH, sizeof(locAddr.sun_path) - 1);                                                                                                                             
        const socklen_t locAddrLen = ::strlen(SOCK_PATH) + 1 + sizeof(locAddr.sun_family);                                                                                                                    
        if (::bind(d, reinterpret_cast<sockaddr*>(&locAddr), locAddrLen) == -1)                                                                                                                               
        {                                                                                                                                                                                                     
            perror("bind");                                                                                                                                                                                   
            ::close(d);                                                                                                                                                                                       
            return EXIT_FAILURE;                                                                                                                                                                              
        }
        struct sockaddr_un remAddr;                                                                                                                                                                           
        socklen_t remAddrLen = sizeof(remAddr);                                                                                                                                                               
        std::vector<char> buff(::strlen(TEST_DATA));                                                                                                                                                          
        const int rv = ::recvfrom(d, buff.data(), buff.size(), 0, reinterpret_cast<sockaddr*>(&remAddr), &remAddrLen);                                                                                        
        std::cout << "rv: " << rv << " data: '";                                                                                                                                                              
        std::cout.write(buff.data(), buff.size());                                                                                                                                                            
        std::cout << "' sz: " << buff.size() << " remAddrLen: " << remAddrLen << std::endl;                                                                                                                   

        ::close(d);                                                                                                                                                                                           
    }                                                                                                                                                                                                         
    else                                                                                                                                                                                                      
    {                                                                                                                                                                                                         
        perror("fork");                                                                                                                                                                                       
        return EXIT_FAILURE;                                                                                                                                                                                  
    }                                                                                                                                                                                                         

    return EXIT_SUCCESS;                                                                                                                                                                                      
}

Solution

  • I've found the reason:

    1. Client and server should use different addresses (even on the same node)
    2. Client also should use bind.

    Corrected code:

    #include <sys/un.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <unistd.h>
    
    #include <cstdlib>
    #include <cstdint>
    #include <vector>
    #include <iostream>
    #include <thread>
    
    namespace {                                                                                                                                                                                                   
    const char* SOCK_PATH1 = "echosock1";                                                                                                                                                                         
    const char* SOCK_PATH2 = "echosock2";                                                                                                                                                                         
    const char* TEST_DATA = "[[[SomeData]]]";                                                                                                                                                                     
    }
    
    int main()                                                                                                                                                                                                    
    {                                                                                                                                                                                                             
        pid_t childPid = ::fork();                                                                                                                                                                                
        if (childPid == 0)                                                                                                                                                                                        
        {                                                                                                                                                                                                         
            std::this_thread::sleep_for(std::chrono::milliseconds(100)); // hack: wait until server is starting reading                                                                                           
            const int d = ::socket(AF_UNIX, SOCK_DGRAM, 0);                                                                                                                                                       
            if (d == -1)                                                                                                                                                                                          
            {                                                                                                                                                                                                     
                perror("socket");                                                                                                                                                                                 
                return EXIT_FAILURE;                                                                                                                                                                              
            }                                                                                                                                                                                                     
    
            struct sockaddr_un locAddr;                                                                                                                                                                           
            ::memset(&locAddr, 0, sizeof(locAddr));                                                                                                                                                               
            locAddr.sun_family = AF_UNIX;                                                                                                                                                                         
            ::strncpy(locAddr.sun_path + 1, SOCK_PATH1, sizeof(locAddr.sun_path) - 1);                                                                                                                            
            const socklen_t locAddrLen = ::strlen(SOCK_PATH1) + 1 + sizeof(locAddr.sun_family);                                                                                                                   
    
            std::cout << "cl bind to: " << SOCK_PATH1 << std::endl;                                                                                                                                               
            if (::bind(d, reinterpret_cast<sockaddr*>(&locAddr), locAddrLen) == -1)                                                                                                                               
            {                                                                                                                                                                                                     
                perror("bind");                                                                                                                                                                                   
                ::close(d);                                                                                                                                                                                       
                return EXIT_FAILURE;                                                                                                                                                                              
            }                                                                                                                                                                                                     
    
            struct sockaddr_un remAddr;                                                                                                                                                                           
            ::memset(&remAddr, 0, sizeof(remAddr));                                                                                                                                                               
            remAddr.sun_family = AF_UNIX;                                                                                                                                                                         
            ::strncpy(remAddr.sun_path + 1, SOCK_PATH2, sizeof(remAddr.sun_path) - 1);                                                                                                                            
            const socklen_t remAddrLen = ::strlen(SOCK_PATH2) + 1 + sizeof(remAddr.sun_family);                                                                                                                   
            const int rv = ::sendto(d, TEST_DATA, ::strlen(TEST_DATA), 0, reinterpret_cast<sockaddr*>(&remAddr), remAddrLen);                                                                                     
            std::cout << "client sent: " << rv << " to " << SOCK_PATH2 << std::endl;                                                                                                                              
            ::close(d);                                                                                                                                                                                           
        }
        else if (childPid > 0)                                                                                                                                                                                    
        {                                                                                                                                                                                                         
            const int d = ::socket(AF_UNIX, SOCK_DGRAM, 0);                                                                                                                                                       
            if (d == -1)                                                                                                                                                                                          
            {                                                                                                                                                                                                     
                perror("socket");                                                                                                                                                                                 
                return EXIT_FAILURE;                                                                                                                                                                              
            }                                                                                                                                                                                                     
    
            std::cout << "bind to: " << SOCK_PATH2 << std::endl;                                                                                                                                                  
            struct sockaddr_un locAddr;                                                                                                                                                                           
            ::memset(&locAddr, 0, sizeof(locAddr));                                                                                                                                                               
            locAddr.sun_family = AF_UNIX;                                                                                                                                                                         
            ::strncpy(locAddr.sun_path + 1, SOCK_PATH2, sizeof(locAddr.sun_path) - 1);                                                                                                                            
            const socklen_t locAddrLen = ::strlen(SOCK_PATH2) + 1 + sizeof(locAddr.sun_family);                                                                                                                   
            if (::bind(d, reinterpret_cast<sockaddr*>(&locAddr), locAddrLen) == -1)                                                                                                                               
            {                                                                                                                                                                                                     
                perror("bind");                                                                                                                                                                                   
                ::close(d);                                                                                                                                                                                       
                return EXIT_FAILURE;                                                                                                                                                                              
            }                                                                                                                                                                                                     
    
            struct sockaddr_un remAddr;                                                                                                                                                                           
            socklen_t remAddrLen = sizeof(remAddr);                                                                                                                                                               
            std::vector<char> buff(::strlen(TEST_DATA));                                                                                                                                                          
            const int rv = ::recvfrom(d, buff.data(), buff.size(), 0, reinterpret_cast<sockaddr*>(&remAddr), &remAddrLen);                                                                                        
            std::cout << "rv: " << rv << " data: '";                                                                                                                                                              
            std::cout.write(buff.data(), buff.size());                                                                                                                                                            
            std::cout << "' sz: " << buff.size() << " remAddrLen: " << remAddrLen << std::endl;                                                                                                                   
    
            ::close(d);                                                                                                                                                                                           
        }                                                                                                                                                                                                         
        else                                                                                                                                                                                                      
        {                                                                                                                                                                                                         
            perror("fork");                                                                                                                                                                                       
            return EXIT_FAILURE;                                                                                                                                                                                  
        }                                                                                                                                                                                                         
    
        return EXIT_SUCCESS;                                                                                                                                                                                      
    }