Ryanman
Ryanman

Reputation: 880

Extracting IP Address and Port Info from sockaddr_storage

I'm currently working on a UDP server that receives a request from a client. The datagram I receive is a byte (char) array 5 elements long, with the final two elements being a port number.

Eventually this server will have to return both the IP address and the port number in a datagram of its own.

I already know how to use inet_ntop and the sockaddr struct I've connected with and received from to print out the ip, but it returns a string that's not in the format I want. For instance:

string1 = inet_ntop(their_addr.ss_family,get_in_addr(
    (struct sockaddr *)&their_addr),s, sizeof s);

returns:

127.0.0.1

or:

[1][2][7][.][0][.][0][.][1]

when I need something like:

[127][0][0][1]

Should I be using some sort of character and array manipulation to make my 4-element byte array? Or does a sockaddr have this information in a way that I can leave it in this hex form and return it?

Upvotes: 7

Views: 20816

Answers (3)

SubMachine
SubMachine

Reputation: 507

Here is a simple immutable class I used for the same purpose you mentioned in your question:

class address_t {

private:
    uint16_t m_Port = 0;
    std::string m_Ip = "";

public:
    address_t(const sockaddr_in & address) {
        m_Ip = inet_ntoa(address.sin_addr);
        m_Port = ntohs(address.sin_port);
    }

    uint16_t GetPort() const { return m_Port; }
    std::string GetIp() const { return m_Ip; }
    std::string ToString() const {
        return "IP: " + m_Ip + ", Port: " + std::to_string(m_Port);
    }
};

Upvotes: 1

Ales Teska
Ales Teska

Reputation: 1288

You want to probably use getnameinfo() function:

int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                   char *host, size_t hostlen,
                   char *serv, size_t servlen, int flags);

E.g.:

struct sockaddr_storage client_addr;
socklen_t client_len = sizeof(struct sockaddr_storage);

/* Accept client request */
int client_socket = accept(server_socket, 
    (struct sockaddr *)&client_addr, &client_len);

char hoststr[NI_MAXHOST];
char portstr[NI_MAXSERV];

int rc = getnameinfo((struct sockaddr *)&client_addr, 
    client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), 
    NI_NUMERICHOST | NI_NUMERICSERV);

if (rc == 0) 
    printf("New connection from %s %s", hoststr, portstr);

Upvotes: 5

Kludas
Kludas

Reputation: 571

Assuming for IPv4.

After taking the address of your sockaddr_storage or sockaddr structure and casting it to the IPv4 version sockaddr_in, you can then access the individual bytes of the IPv4 address.

struct sockaddr_in *sin = (struct sockaddr_in *)&their_addr;

Then you can take address of the s_addr member which is a 32 bit value (in_addr_t) that holds the 4 bytes of the ip address (in network byte order) and cast it to a pointer to an unsigned char which then lets you access the individual bytes of the value.

unsigned char *ip = (unsigned char *)&sin->sin_addr.s_addr;

printf("%d %d %d %d\n", ip[0], ip[1], ip[2], ip[3]);

Upvotes: 13

Related Questions