Reading from UDP socket over WiFi always timeout - c++

I have a piece of code that send a UDP broadcast to scan for device on our local network. It works fine when im plugged via ethernet, but it doesnt when im connected via WiFi.
Is there something different to do to connect in UDP when using WiFi?
You can find the code im using below. When using WiFi, select always return 0
struct sockaddr_in addr;
//Create socket
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
perror("socket");
exit(1);
}
/* set up destination address */
memset((char *)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(48620);
addr.sin_addr.s_addr = inet_addr("192.168.3.255");
//TRYING TO BIND, NOT WORKING
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
{
int a = WSAGetLastError(); //ERROR 10049
perror("bind"); //Says NO ERROR
}
//allow broadcast
int broadcast = 1;
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof(broadcast)) == -1)
exit(1);
if (sendto(fd, (const char *)&request, sizeof(request), 0, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
perror("sendto");
exit(1);
}
do
{
FD_ZERO(&rdFs);
FD_SET(fd, &rdFs);
lTimeout.tv_sec = 1;
lTimeout.tv_usec = 000000;
lSelRet = select(fd, (fd_set*)&rdFs, NULL, NULL, &lTimeout);
if (lSelRet > 0 && FD_ISSET(fd, &rdFs))
{
addrFromSize = sizeof(addrFrom);
lResult = recvfrom(fd, bufferIn, sizeof(bufferIn), 0, (struct sockaddr *) &addrFrom, &addrFromSize);
//Treat result
}
} while (lSelRet > 0);
Note : Even using WiFi, i can estalbish a TCP connection and communicate with the device, its just the UDP broadcast that doesnt work
Note2: currently testing on windows, but I will port it to Linux after
Edit : added the SO_BROADCAST as advised by Remy

Finally got it working, it was a code issue, not a router issue.
The issue was a misuse of the bind function, I needed to use my IP and not the broadcast IP.
/* set up destination address */
memset((char *)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(48620);
addr.sin_addr.s_addr = inet_addr("192.168.3.134"); //<== Windows : My IP, not the broadcast IP
addr.sin_addr.s_addr = INADDR_ANY; //Linux
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
{
perror("bind");
}
EDIT : strangely enough, in windows you must bind to the ip sending the request, and on linux you must bind to INADDR_ANY.

Related

How can I restrict my server to start only on specified port?

I have a server which listens on certain port (fixed).
Now if that port is not available, it starts on any random port. I don't want this.
How can I make sure that if the specified port is not available, my service should not start?
int fd = ::socket(AF_INET, SOCK_STREAM, 0);
int32_t const opt = 1;
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(61014);
::bind(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
::listen(fd, 5);
As showed above your code won't compile. But I think you want to achieve something like the code below:
You have to check if the bind() call fails. If so than this would mean that this port is already in use. It can also happen that you already own a port, so it is recommended to use the SO_REUSEADDR flag.
if( bind(fd_desc,(struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
//print the error message
perror("Bind failed.");
return 1;
}

IP_ADD_MEMBERSHIP on a socket, will the socket listen to unicast also?

Considering the code below,
I'm trying to bind a UDP socket for multicast.
I've bound it to a specific port, and set IP_ADD_MEMBERSHIP for the address to listen to.
My question: will the socket receive unicast UDP packets bound for that port? If so, how can I prevent it? I wish to only receive multicast.
int fd;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
u_int yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
{
perror("Reusing ADDR failed");
exit(1);
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = (source_iface.empty()
? htonl(INADDR_ANY)
: inet_addr(source_iface.c_str()));
if (bind(fd,(struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
exit(1);
}
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group.c_str());
mreq.imr_interface.s_addr = (source_iface.empty()
? htonl(INADDR_ANY)
: inet_addr(source_iface.c_str()));
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
perror("setsockopt");
exit(1);
}
I believe you'll also need to bind on the particular multicast address on which you want to listen, and not just in the setsockopt call - the latter also being necessary to make sure that the network card and IGMP also do the right thing.
See also What does it mean to bind a multicast (UDP) socket?
Okay, I got my instance to work so I know what the problem was. The bind() has to occur against the multicast IP address:
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = (group.empty()
? htonl(INADDR_ANY) // <-- this will work here but not below
: inet_addr(group.c_str()));
if (bind(fd,(struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
exit(1);
}
The difference here is group instead of source_iface. Until I changed that, it would not receive broadcasted packets at all.

While trying to connect to a server get two different errors 10056 and 10061

This is a program i use to test
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
int noDelay = 1;
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast < const char* >(&noDelay), sizeof(noDelay)
sockaddr_in serverAddress;
serverAddress.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(static_cast<unsigned short int>(port));
iResult = connect(s, (struct sockaddr*) &serverAddress, sizeof(serverAddress));
iResult = connect(s, (struct sockaddr*) &serverAddress, sizeof(serverAddress));
from the start after second connect i have WSAError set to 10056 - pretty understandible, but in some tries i start to get 10061 even with first call to connect. I think it starts to happen at 5 or 6 program execution.
Why it could be?
UPDATE:
At least i souldn't call connect twice with one socket:)

Unable to get local host IP address from getsockname?

I am able to get the port returned, but the IP is not. Should I be using something else other than getsockname? thx
if ((sock = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) {
c.Format("Socket Error: %d", GetLastError());
tcpMESSAGE = 1;
break;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(4000); //port setting
server_addr.sin_addr.s_addr = INADDR_ANY;
if (::bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
c.Format("Bind Error: %d", GetLastError());
tcpMESSAGE = 1;
break;
}
if(1==1){
int len = sizeof server_addr;
if(::getsockname(sock,(struct sockaddr*)&server_addr,&len) == -1)
MessageBox("Error local host ip");
c.Format("local addr %s:%u\n errno: %d",inet_ntoa(server_addr.sin_addr),ntohs(server_addr.sin_port), errno);
MessageBox(c);
}
You are binding to INADDR_ANY, but you have not connected the socket to a peer yet, so there is no IP for getsockname() to return. After a connection has been established via connect() or accept(), then getsockname() can return the specific IP that is being used for that connection. Binding alone is not enough, unless you bind to a specific IP, which you are not doing.

Multicast is not working on Windows Vista

While I try to Multicast something to range of IP in win XP , it works fine but while I run the same application on Win VIsta I am unable to multicast. Do I need to configure or add a publisher info for Win Vitsa?
Edit:
struct sockaddr_in staddr;
memset(&staddr, 0, sizeof(struct sockaddr_in));
staddr.sin_family = AF_INET;
staddr.sin_port = htons(SSDP_PORT); // Use the first free port
staddr.sin_addr.s_addr=inet_addr(SSDP_MULTICAST_ADDRESS);
int socklen = sizeof(struct sockaddr_in);
Edit 2
Socket Creation
int ibindstatus =0 ;
try
{
//Initailize the WinSock
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
struct in_addr iaddr;
struct sockaddr_in staddr;
// set content of struct saddr and imreq to zero
memset(&staddr, 0, sizeof(struct sockaddr_in));
memset(&iaddr, 0, sizeof(struct in_addr));
// open a UDP socket
m_iSocket = socket(AF_INET, SOCK_DGRAM, 0);
if ( m_iSocket < 0 )
{
return SOCKET_NOT_AVAILABLE;
}
staddr.sin_family = AF_INET;
staddr.sin_port = htons(SSDP_PORT); // Use the first free port
staddr.sin_addr.s_addr = htonl(INADDR_ANY); // bind socket to any interface
ibindstatus = bind(m_iSocket, (struct sockaddr *)&staddr, sizeof(struct sockaddr_in));
if ( ibindstatus < 0 )
{
return SOCKET_BIND_ERROR;
}
//send the buffer
int iSendStatus = sendto(m_iSocket, cSendData, lSendDataLen, 0,
(struct sockaddr *)&staddr, socklen);
if(iSendStatus< 0)
{
return SEND_ERROR;
}
Well after lotz of experiments I was not able to figure out why Multi casting was not working, and found out suddenly this is because Network Discovery was off on my Vista.
So If here what I did , Go to Control Panel->SetUp File Sharing(Under Network and Internet) ->Sharing and Discovery and then switch on or off the network discovery
Well thatz what work for my application and the source code is what I have posted in my question. Hope fully this will save some of your time and frustation.