2
votes

I have project code which creates a UDP socket to receive multicast packets. The code is portable for Linux and Solaris operating systems. An extension of my project is looking to retrieve the source IP address of the UDP packet when using the recvmsg() function. I had asked a fellow expert on the matter, and she mentioned that Linux appears to be able to provide the source IP address, but Solaris may not when using the recvmsg() function. So I pose the question here, am I able to retrieve the source IP address using recvmsg() on Solaris 10?

OS: Solaris 10, Sunstudio 12 cc (no U1 or U2). Code base: C/C++

//Socket initially opened with the following options from a different function.
// This connects the socket to receive multicast:
setsockopt(data->fd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
    (char *)&mregs, sizeof(mregs) ) < 0)

//A different function performs an infinite loop reading from the socket:

struct iovec vector;
vector.iov_base = buf;     //passed in param
vector.iov_len = len;      //passed in param
struct msghdr msg;
char    caddr[100] ;
msg.msg_name =  caddr;
msg.msg_namelen = 100;
msg.msg_iov = &vector;
msg.msg_iovlen = 1;
int flags = 0;

char controlBuffer[1024];
msg.msg_control = controlBuffer;
msg.msg_controllen = 1024;

bytes = ::recvmsg(data->fd, &msg, flags);

//removed error checking    

struct cmsghdr *cmsg;
struct in_pktinfo *dest_ip_ptr;
rrcp_u32_t dest_ip = 0;
cmsg = CMSG_FIRSTHDR(&msg);
for ( cmsg = CMSG_FIRSTHDR(&msg);
    cmsg != NULL;
    cmsg = CMSG_NXTHDR( &msg, cmsg ) )
{
    //if ( cmsg->cmsg_type == IPPROTO_IP && cmsg->cmsg_level == IP_PKTINFO )
    {
#ifdef Linux
        struct in_pktinfo *dest_ip_ptr = (struct in_pktinfo*)CMSG_DATA(cmsg);
        dest_ip = dest_ip_ptr->ipi_addr.s_addr;
#else
        //in_addr only has 1 address
        struct in_addr * dest_ip_ptr = (struct in_addr *)CMSG_DATA(cmsg);
        dest_ip = dest_ip_ptr->_S_un._S_addr;
#endif
    }
}
if( ipaddr ) 
    ipaddr->IP = dest_ip;

//according to the Linux article mentioned below, the caddr should have the source
//socket address.  In my case, the caddr field is not filled with any coherent data,
//so this does not seem to be the source address.  Then again, "source socket" could
//be the interface IP on the local machine, which isn't what I need.

I also saw the following articles, but they didn't seem to answer my questions: Get destination address of a received UDP packet, solution at: Get destination address of a received UDP packet

1

1 Answers

1
votes

There are two problems: One is that you don't use caddr anywhere and you don't say what it is, so it's hard to help you; The other (and likely the problem you're having) is that the address you get from recvmsg is not a string.

msg.msg_name should point to a struct sockaddr_in and msg.msg_namelen should sizeof(struct sockaddr_in). You then get the address from that.