11

I am trying to get the client address, but i am unsure how do i cast the sockaddr structure to sockaddr_in?

struct sockaddr_in cliAddr, servAddr;

    n = recvfrom(sd, msg, MAX_MSG, 0,(struct sockaddr *) cliAddr,sizeof(cliAddr));

 //i tried this but it does not work
    struct sockaddr cliSockAddr = (struct sockaddr *) cliAddr; 
    char *ip = inet_ntoa(cliSockAddr.sin_addr);

Thanks in advance! :)


i've found questions that brought me to this step: Getting IPV4 address from a sockaddr structure


Sorry to avoid confusion, this is my real implementation where "ci" is an object to store pointers such as sockaddr_in.

    /* receive message */
    n = recvfrom(*(ci->getSd()), msg, MAX_MSG, 0,(struct sockaddr *) ci->getCliAddr(),ci->getCliLen());

    char *ip = inet_ntoa(ci->getCliAddr().sin_addr);

i will get the following errors:

udpserv.cpp:166: error: request for member ‘sin_addr’ in ‘ci->clientInfo::getCliAddr()’, which is of non-class type ‘sockaddr_in*’
Community
  • 1
  • 1
mister
  • 3,303
  • 10
  • 31
  • 48

3 Answers3

27

I would point out that if this is actually C++ the idiomatic way to do this would be:

sockaddr *sa = ...; // struct not needed in C++
char ip[INET6_ADDRSTRLEN] = {0};

switch (sa->sa_family) {
  case AF_INET: {
    // use of reinterpret_cast preferred to C style cast
    sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(sa);
    inet_ntop(AF_INET, &sin->sin_addr, ip, INET6_ADDRSTRLEN);
    break;
  }
  case AF_INET6: {
    sockaddr_in6 *sin = reinterpret_cast<sockaddr_in6*>(sa);
    // inet_ntoa should be considered deprecated
    inet_ntop(AF_INET6, &sin->sin6_addr, ip, INET6_ADDRSTRLEN);
    break;
  }
  default:
    abort();
}

This sample code handles IPv4 and IPv6 addresses and also would be considered more C++ idiomatic than either of the suggested implementations.

Blake Mathman
  • 2,699
  • 1
  • 23
  • 20
  • 1
    I really like that you've used reinterpret_cast. It makes everything so much cleaner, and less pointers need to be used. On a side note, I didn't set sa as a pointer to begin with. I simply passed the address to it in via reference in like this (mine is a school project and only using IPv4 -- inet_ntoa(reinterpret_cast(&clientIpAddress)->sin_addr) – adprocas Nov 27 '16 at 03:54
17

It is actually very simple!

struct sockaddr *sa = ...;

if (sa->sa_family == AF_INET)
{
    struct sockaddr_in *sin = (struct sockaddr_in *) sa;
    ip = inet_ntoa(sin->sin_addr);
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 3
    And while you're doing that, make your program IPv6 capable by checking for AF_INET6 too. ;) – onitake Jul 27 '12 at 11:10
  • 3
    I know this is an old thread but for sake of correctness, @bmatheny's answer below is the correct one since this question is tagged "C++". `reinterpret_cast(sa)` is the right way to convert the two types and though the old C conversion still works, it is too obscure and won't let clear the intentions for any reader. – j4x Jul 02 '18 at 19:29
3

I think this will compile just fine for you and do what you want.

struct sockaddr_in cliAddr={}, servAddr={};

socklen_t cliAddrLength = sizeof(cliAddr);

n = recvfrom(sd, msg, MAX_MSG, 0,(struct sockaddr *)&cliAddr, &cliAddrLength);
selbie
  • 100,020
  • 15
  • 103
  • 173