How to bind socket to a particular interface in vxWorks - c

I am trying to bind a socket to a particular network interface on my computer. I have two network interfaces named interf0 and interf1. I want bind socket to a particular interface say interf0. My OS is vxWorks 6.2.
I am trying following code:
struct sockaddr_in fromAddr;
struct sockaddr_in sin;
int fromLen;
struct ip_mreq ipMreq;
int sockDesc;
STATUS temp;
if ((sockDesc = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf (" cannot open recv socket\n");
return ERROR;
}
bzero ((char *)&sin, sizeof (sin));
bzero ((char *) &fromAddr, sizeof(fromAddr));
fromLen = sizeof(fromAddr);
#if 1
if ((temp = setsockopt(sockDesc, SOL_SOCKET, SO_BINDTODEVICE, "interf0", 7)) < 0)
{
perror("Server-setsockopt() error for SO_BINDTODEVICE");
printf("%s\n", strerror(errno));
close(sockDesc);
return ERROR;
}
#endif
sin.sin_len = (u_char) sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
//sin.sin_addr.s_addr = inet_addr(ifAddr);
/* UDP port number to match for the received packets */
sin.sin_port = htons (mcastPort);
/* bind a port number to the socket */
if (bind(sockDesc, (struct sockaddr *)&sin, sizeof(sin)) != 0)
{
perror("bind");
if (sockDesc != ERROR)
{
close (sockDesc);
}
return ERROR;
}
Here, it gives an error saying SO_BINDTODEVICE is not defined.
Is there any other way using which I can bind to a particular interface in vxWorks.
Other ref:
bind socket to network interface
Thank you.

It seems that SO_BINDTODEVICE is not part of POSIX, it's a Linux extension. So VxWorks won't necessarily implement interface binding the same way, if it does it at all. A quick look in the VxWorks manuals looks unpromising.
If you have VxWorks you likely also have access to WindRiver's support, assuming you've kept up with the support fees. If so, ask them too, that's what it's there for.

Related

socket binding with INADDR_ANY and specific interface in multicast with multiple interface

I'm trying to write multicast server. I've two questions:
How to send multicast announcements on multiple interfaces like ethernet/ wifi interface. Do I need to create multiple sockets for each interface and bind?
When bind socket with INADDR_ANY address, descriptor is ready to do I/O operation (using select call )but when I bind with specific interface address e.g ethernet/wifi then descriptor is not ready to perform any operation it is stuck at select api only.
So what is the difference between binding a socket with default address (INADDR_ANY) or specific interface address?
int sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0) {
printf("scoket() failed");
return sd;
}
int r = -1;
int on = 1;
if ((r = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on))) < 0) {
printf("recv setsockopt(SO_REUSEADDR) failed");
return r;
}
// add membership to receiving socket
struct ip_mreq mreq;
memset(&mreq, 0, sizeof(struct ip_mreq));
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_multiaddr.s_addr = inet_addr(MDNS_ADDR);
if ((r = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq))) < 0) {
printf("recv setsockopt(IP_ADD_MEM) failed");
return r;
}
// enable loopback in case someone else needs the data
if ((r = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &on, sizeof(on))) < 0) {
printf("recv setsockopt(IP_MULTICAST_LOOP) failed");
return r;
}
#ifdef IP_PKTINFO
if ((r = setsockopt(sd, SOL_IP, IP_PKTINFO, (char *) &on, sizeof(on))) < 0) {
printf("recv setsockopt(IP_PKTINFO) failed");
return r;
}
#endif
/* bind to an address */
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(MDNS_PORT);
//serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); /* receive multicast */
serveraddr.sin_addr.s_addr = inet_addr("192.168.10.23"); /* receive multicast */
if ((r = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0) {
printf("recv bind()");
}
In thread waiting for descriptors to ready for I/O (basically all are read file descriptors)
FD_ZERO(&sockfd_set);
FD_SET(svr->sockfd, &sockfd_set);
FD_SET(svr->notify_pipe[0], &sockfd_set);
printf("before select\n");
select(max_fd + 1, &sockfd_set, NULL, NULL, NULL);
printf("after select\n");
When socket id bind with INADD_ANY address select will returns and I'm able to read with file descriptor but when bind with specific interface then select never returns coz there is no file descriptors available to read.
How to send multicast announcements on multiple interfaces like ethernet/ wifi interface. Do I need to create multiple sockets for each interface and bind?
No. Loop over the network interfaces and call setsockopt() with an appropriate join parameters for each interface in turn. You only need one socket.
When bind socket with INADDR_ANY address, descriptor is ready to do I/O operation (using select call)
That's not correct. Your code only checks for readability.
but when I bind with specific interface address e.g ethernet/wifi then descriptor is not ready to perform any operation
Again that's not correct. You're only checking for readability, not 'any operation'. All this means is that no multicasts are coming in via the address you bound to.
it is stuck at select api only. So what is the difference between binding a socket with default address (INADDR_ANY) or specific interface address?
It determines the IP address you send and receive via.
Binding a socket with a specific address is a generic way to lock it down to a device. This method is a bit old-fashion, since addresses can be changed on a device after your program has started up. In general I would recommend to bind to INADDR_ANY.
You can change the output multicast device on a socket whenever you want.
Options to consider:
man 7 ip :
IP_MULTICAST_ALL - deliver to all devices (default 1)
IP_MULTICAST_IF - I'm pretty sure this only sets the output device
man 7 socket :
SO_BINDTODEVICE
Just play a little with the options and see what the result is

C listen to multicast on all interfaces, respond on same as recieved

I am trying to listen to multicast on all interfaces in system, but responds only on this on which I've received multicast packet.
What I've did is to create a socket for each of the interfaces and here the problems starts.
When I bind interface to INADDR_ANY it will receive packets for all interfaces and send on default one. If I bind port to specific interface it will not receive multicast packet (but it will be able to send it on correct interface).
I've tried setting options like IP_ADD_MEMBERSHIP or IP_MULTICAST_IF but without success.
I think the other options whould be to create one socket to receive on all ifs and senders sockets for all interfaces, but on this approach I have no idea on which ifs packet entered...
Code samples (simplified, without error handling and stuff):
Creating socket:
//here i am looping over all interfaces from getifaddrs
struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr;
sockets[i] = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
setsockopt(sockets[i], SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
mreq.imr_multiaddr.s_addr=inet_addr(MDNS_ADDRESS);
mreq.imr_interface.s_addr=pAddr->sin_addr.s_addr;
setsockopt(sockets[i], IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
setsockopt(sockets[i], IPPROTO_IP, IP_MULTICAST_IF, &pAddr, sizeof(struct in_addr));
memset(&my_addr, 0, sizeof(struct sockaddr_in));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY; //or pAddr->sin_addr.s_addr;
my_addr.sin_port = htons(port);
bind(sockets[i], (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1);
Receiving and sending:
recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, (struct sockaddr *)&their_addr, &addr_len);
//do some magic and response (response should be a multicast too)
destination.sin_addr.s_addr = inet_addr(MULTICAST_ADDRESS);
destination.sin_family = AF_INET;
destination.sin_port = htons( port );
sendto(sockfd, buffer, len, 0, (struct sockaddr *)&destination, sizeof destination);
I would like to create something similar in work to mDNS so when packet entered on specific interface program should answer on the same if with some data about this if. It should not send this on other ifs as it may not be relevant for them, but it should send it as multicast so any other host in same network will receive the respond.
You should only need one socket for this.
First bind to INADDR_ANY and your port of choice. Then call setsockopt with IP_ADD_MEMBERSHIP on each interface you want to receive multicast on. Finally, call setsockopt with IP_MULTICAST_IF on the interface you want to send multicast on. Make sure to check for errors on each call.
int socket s;
struct sockaddr_in sin;
struct ip_mreq mreq;
struct in_addr out_addr;
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr=htonl(INADDR_ANY);
sin.sin_port = htons(1044); // or whatever port you listen on
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket failed");
exit(1);
}
if (bind(s, (struct sockaddr *)&sin, sizeof(sin))==-1) {
perror("bind failed");
exit(1);
}
// Do this in a loop for each interface
mreq.imr_multiaddr = inet_addr("230.4.4.1"); // your multicast address
mreq.imr_interface = inet_addr("192.168.1.1"); // your incoming interface IP
if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) == -1) {
perror("Error joining multicast group");
exit(1);
}
out_addr.s_addr = inet_addr("192.168.1.1"); // your outgoing interface IP
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&out_addr,sizeof(out_addr))== -1) {
perror("Error setting outgoing interface");
exit(1);
}
When using multicast, you should always bind to the INADDR_ANY address. Failure to do so breaks multicast on Linux systems.
Initially, I accepted #dbush answer as it allowed me to get on right track. For sake of completeness I post more detailed answer and as suggested by him I accepted my own answer.
Some of the code was found here: Setting the source IP for a UDP socket
I was able to do all of this with single socket and setting IP_PKTINFO.
Code samples (simplified, without error handling and stuff):
Creating socket:
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
perror("socket");
exit(1);
}
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) < 0) {
perror("setsockopt");
exit(1);
}
optval2 = 1;
if(setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &optval2, sizeof(optval2)) < 0) {
perror("setsockopt");
exit(1);
}
memset(&my_addr, 0, sizeof(struct sockaddr_in));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = htons(5353);
if (bind(sockfd, (struct sockaddr *)&my_addr,
sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}
Receiving and responding:
char buf[MAXBUFLEN];
char cmsgbuf[MAXBUFLEN];
struct iovec iov[1];
iov[0].iov_base=buf;
iov[0].iov_len=sizeof(buf);
struct cmsghdr *cmsg;
struct msghdr message;
message.msg_name=&their_addr;
message.msg_namelen=sizeof(their_addr);
message.msg_iov=iov;
message.msg_iovlen=1;
message.msg_control=cmsgbuf;
message.msg_controllen=MAXBUFLEN;
if ((numbytes = recvmsg(sockfd, &message, 0)) == -1) {
perror("recvfrom");
exit(1);
}
for (cmsg = CMSG_FIRSTHDR(&message); cmsg != NULL; cmsg = CMSG_NXTHDR(&message, cmsg)) {
// ignore the control headers that don't match what we want
if (cmsg->cmsg_level != IPPROTO_IP ||
cmsg->cmsg_type != IP_PKTINFO)
{
continue;
}
struct in_pktinfo *pi = CMSG_DATA(cmsg);
addr = pi->ipi_spec_dst.s_addr;
}
//DO SOME MAGIC
//HERE WE ARE SETTING ADDR - INTERFACE WITH THIS ADDR WILL SEND MULTICAST
sock_opt_addr.s_addr = addr;
setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &sock_opt_addr, sizeof(sock_opt_addr));
sendto(sockfd, buffer, len, 0, (struct sockaddr *)&destination, sizeof destination);

c connect() error - invalid argument

I'm writing a simple UDP client and an error returned as "invalid argument", but I don't know what's wrong. It is compiled on linux. My code is as below.
int udp_fd = -1;
struct sockaddr_in addr;
int port = 1701;
udp_fd = socket(AF_PPPOX, SOCK_DGRAM, 0);
if (udp_fd < 0) {
printf("fail to get UDP socket\n");
return 0;
}
memset((char *) &addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("31.25.210.118");
addr.sin_port = htons(port);
if(connect(udp_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 ) {
printf("UDP connect failed, errno = %s\n", strerror(errno));
return 0;
}
You are using an AF_INET address with an AF_PPPoX socket. This is mixing apples and parakeets.
PPP stands for "point-to-point", there is no such thing as IP address in this domain. Pick your game. You either connect over the Internet, and use socket(AF_INET, ..., or connect over PPP and use one of the PPP protocols like PX_PROTO_OLAC or PX_PROTO_OPNS, and a corresponding socket address type (sockaddr_pppolac or sockaddr_pppopns) instead of sockaddr_in.

getpeername() won't return a correct port but it returns a correct address of remote host socket language C

I would like to ask about the getpeername() function since it returns data as the title states. I tried to get value directly from accept() function, and the result also happens the same. Value of port seems to appear randomly even though value of address is correct(address is 127.0.0.1 since I run multi-processes on an only machine). The return code of getpeername() is 0 (status = 0). I'm using gcc version 4.8.1. I write a peer 2 peer chat application without server. The following is my code:
struct sockaddr_in addr;
socklen_t addr_len;
int tempPort, serverSockfd;
char test[100];
// Get serverSockfd successfully....
serverSockFd = initializeSock(PORT) // In this function I initialize socket(), bind() and listen(), serverSockFd is returned by the value of socket()
addr_len = sizeof addr;
newSock = accept(serverSockfd, (struct sockaddr *)&addr, &addr_len);
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
addr_len = sizeof addr;
if ((status = getpeername(newSock, (struct sockaddr *) &addr, &addr_len)) != 0){
printf("getpeername() error!\n");
}
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
Thanks very much for any your comment. Here is a partial code in initializeSock():
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("SocketInit(): socket() error!\n");
exit(1);
}
ret_val = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
if(ret_val == -1)
{
perror("SocketInit(): setsockopt(SO_REUSEADDR) error!\n");
exit(1);
}
gethostname(hostname,100);
host_entry = gethostbyname(hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
ret_val = bind(sd, (struct sockaddr*) &addr, sizeof(addr));
if(ret_val == -1)
{
perror("SocketInit(): bind() error!\n");
printf("For port:%d\n",port);
exit(1);
}
....
return sd;
This is the code to connect to server part of a peer. ConnectSock(portOfPeerA):
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("ConnectToServer(): socket() error!\n");
exit(1);
}
if (port != 0) {
addr.sin_family = AF_INET;
addr.sin_port = htons(portOfPeerA);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
// Do I need to bind() the port of peer B when it would like to connect to peer A?
ret_val = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
if(ret_val == -1)
{
printf("Error connect());
exit(1);
}
...
I don't know which port you accept from the peer, but if the peer is connecting to your server (e.g. then one calling accept) it will connect from a (more or less) random port, that's how TCP works. It connects from a fixed port only if the peer explicitly binds to that port before connecting.
This means, that the peers originating port is not defined on the server side (where your code fragments are from) but on the client side (the side which calls connect and where you only do connect but no bind).
But, please note that it might give problems with repeated connections, if both client and server use fixed IP and ports, because then you will get the same 4-tupel in TCP which defines the connections for repeated connections and thus go into all this trouble with the various TIME_WAIT states. So it is better to let the client just pick an available port and not force it to use a specific one.
getpeername() (and accept()) reports the IP and port that the remote party is locally bound to on its end. If the remote party is a client that did not call bind() before calling connect() then connect() performs an implicit bind to a random available port. That is what you are seeing, and that it typical usage. Most clients do not need to call bind() before connect(), but there are use cases where doing so is necessary, so don't rule it out.

UDP Broadcast in Windows 7 - does it work?

I'm trying to write some code under Windows 7 to broadcast across my local network and can't get the following code to work. I come from a Linux background so apologies for style - the full code compiles etc and works and if I use an address of:
unsigned long broadcastAddr = inet_addr("192.168.10.0") | ~(inet_addr("255.255.240.0"));
Then that works fine, I just would really like to use the preferred INADDR_BROADCAST/255.255.255.255 method.
<snip>
SOCKET sockfd;
int broadcast = 1;
WSADATA wsaData; // Windows socket
// Initialize Winsock
if (WSAStartup(MAKEWORD(2,2), &wsaData) == SOCKET_ERROR) {
perror("WinSock Error");
getc(stdin);
exit(EXIT_FAILURE);
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("Socket Error");
getc(stdin);
exit(1);
}
if ((setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast))) == SOCKET_ERROR) {
perror("Setsockopt - SOL_SOCKET");
getc(stdin);
exit(1);
}
struct sockaddr_in recvaddr;
recvaddr.sin_family = AF_INET;
recvaddr.sin_port = htons(PORT);
recvaddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
memset(recvaddr.sin_zero,'\0', sizeof(recvaddr.sin_zero));
int numbytes = 0;
while ((numbytes = sendto(sockfd, greet, strlen(greet) , MSG_DONTROUTE, (struct sockaddr *)&recvaddr, sizeof(struct sockaddr_in))) != -1) {
printf("Sent a packet %d\n", numbytes);
Sleep(100);
}
There is a huge bug in Windows 7 for UDP broadcast which makes broadcasting on 255.255.255.255 not work on most windows 7 install: https://serverfault.com/questions/72112/how-to-alter-the-global-broadcast-address-255-255-255-255-behavior-on-windows
Basically it will send the broadcast only on a single network interface, which could be anything, even something like a VM network interface or bluetooth one, which can end up not broadcasting to any device.
Unless my bit maths is out, inet_addr("192.168.10.0") | ~(inet_addr("255.255.240.0")) is the same as inet_addr("192.168.15.255") which is the broadcast address for that subnet.
It looks to me like the most likely possibility is not that the sending code is wrong but that the receiving code is wrong. What address have you bound the receiving socket to? What subnet is it on?

Resources