Search code examples
cc89

How to memcpy() a struct sockaddr_in


I'm programming a server-client program. On the server I manage the clients through an array of this data structure:

struct Client
{
    struct sockaddr_in addr;
    /*...*/
}; 

struct Client CLIENTS[MAX_CLI];

When I receive the first packet from the client through my UDP socket

struct sockaddr_in addr_cli;

memset(&addr_cli,0,sizeof(struct sockaddr_in));
b=recvfrom(SOCK_UDP_FATHER, &pdu, sizeof(pdu), MSG_DONTWAIT,
    (struct sockaddr *)&addr_cli, (socklen_t *)&laddr_cli);

I want to copy his address to my struct. So I do:

memcpy(&CLIENTS[client].addr,(struct sockaddr*)&addr_cli,
    sizeof(struct sockaddr_in));

printf("IP client: %s",inet_ntoa(CLIENTS[client].addr.sin_addr);

The strange thing is that the first try of communication fails, printing 0.0.0.0. But the next try that the client does, is successful and everything goes fine. Why that happens?


Solution

  • The addr_cli was not filled by the call to recvfrom. The last two arguments of recvfrom are a little bit tricky. They are

    struct sockaddr *src_addr,
    socklen_t *addrlen
    

    If src_addr is not NULL, the recvfrom expects that addrlen points to the length of src_addr buffer. (Normally it is the size of sockaddr structure). If the value of addrlen is too small, the returned address will be truncated. After the call to recvfrom the addrlen will be set to the actual address length. Look at documentation for details.

    So you need to initialize laddr_cli before calling recvfrom():

    struct sockaddr_in addr_cli;
    socklen_t laddr_cli = sizeof(addr_cli); // <--
    
    memset(&addr_cli,0,laddr_cli);    
    b=recvfrom(SOCK_UDP_FATHER, &pdu, sizeof(pdu), MSG_DONTWAIT,
        (struct sockaddr *)&addr_cli, &laddr_cli);