In Linux environment, you can use recvmsg to get local ip address.
//create socket and bind to local address:INADDR_ANY:
int s = socket(PF_INET,SOCK_DGRAM,0);
bind(s,(struct sockaddr *)&myAddr,sizeof(myAddr)) ;
// set option
int onFlag=1;
int ret = setsockopt(s,IPPROTO_IP,IP_PKTINFO,&onFlag,sizeof(onFlag));
// prepare buffers
// receive data buffer
char dataBuf[1024] ;
struct iovec iov = {
.iov_base=dataBuf,
.iov_len=sizeof(dataBuf)
} ;
// control buffer
char cBuf[1024] ;
// message
struct msghdr msg = {
.msg_name=NULL, // to receive peer addr with struct sockaddr_in
.msg_namelen=0, // sizeof(struct sockaddr_in)
.msg_iov=&iov,
.msg_iovlen=1,
.msg_control=cBuf,
.msg_controllen=sizeof(cBuf)
} ;
while(1) {
// reset buffers
msg.msg_iov[0].iov_base = dataBuf ;
msg.msg_iov[0].iov_len = sizeof(dataBuf) ;
msg.msg_control = cBuf ;
msg.msg_controllen = sizeof(cBuf) ;
// receive
recvmsg(s,&msg,0);
for( struct cmsghdr* pcmsg=CMSG_FIRSTHDR(&msg);
pcmsg!=NULL; pcmsg=CMSG_NXTHDR(&msg,pcmsg) ) {
if(pcmsg->cmsg_level==IPPROTO_IP && pcmsg->cmsg_type==IP_PKTINFO) {
struct in_pktinfo * pktinfo=(struct in_pktinfo *)CMSG_DATA(pcmsg);
printf("ifindex=%d ip=%s\n", pktinfo->ipi_ifindex, inet_ntoa(pktinfo->ipi_addr)) ;
}
}
}
The following does not work in asymmetric routing environment.
you can first set SO_REUSEADDR to true
BOOL bOptVal = 1;
setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&boOptVal, sizeof(bOptVal));
after receive_from( ..., &remoteAddr, ... );
create another socket, and connect back to remoteAddr. Then call getsockname can get the ip address.
SOCKET skNew = socket( )
// Same local address and port as that of your first socket
// INADDR_ANY
bind(skNew, , )
// set SO_REUSEADDR to true again
setsockopt(skNew, SOL_SOCKET, SO_REUSEADDR, (char *)&boOptVal, sizeof(bOptVal));
// connect back
connect(skNew, remoteAddr)
// get local address of the socket
getsocketname(skNew, )