I have an application that regularly receives multicast updates from another application. As long as the receiver application is on the same host as the sender, I am able to get the multicast packets. If the receiver application is another host in the same LAN, then I am unable to read the multicast packets. I can see the those packets on wireshark on both machines.
Host A [Win8.1]- Both Wireshark and my app can read the packets.
Host B [Win2012 R2] - Only Wireshark can see the packets, my app reads nothing.
The sender is on Host A. The Host A also has Hyper-V enabled, if that matters.
My app uses Boost.asio sockets, I am seeing the same results using C sockets too. Here is the C example with all the error handling stripped off for simplicity. It works only on Host A, but not on Host B.
EDIT: I tried something crazy today.
I started the same sender on Host B using the same MC address and port. Now the receiver started receiving transmissions from both Host A and B. Then I shutdown the sender on Host B, but the receiver continued to receive packets from Host A. Now I restarted the receiver on Host B, it is again blind as a bat.
void Receiver(const char* mc_address, short port)
{
struct sockaddr_in addr;
int addrlen, sock;
struct ip_mreq mreq;
char message[500];
sock = socket(AF_INET, SOCK_DGRAM, 0);
memset(&addr,0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
addrlen = sizeof(addr);
bind(sock, (struct sockaddr *) &addr, sizeof(addr));
mreq.imr_multiaddr.s_addr = inet_addr(mc_address);
mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,(const char*)&mreq, sizeof(mreq));
while (1)
{
int count = recvfrom(sock, message, sizeof(message), 0, (struct sockaddr *) &addr, &addrlen);
if (count == 0) break;
message[count] = 0;
std::cout << message << std::endl;
}
}
Related
It's certainly a common question, but not in this terms (windows, server side, accept multi connexion).
My goal is to accept to start a server listing on a port for multiple connections only if before that the port is detected "unused".
At the line where I put //HERE..., binddoesn't return a SOCKET_ERROR status as I expected.
Maybe I'm doing something wrong.
How to detect that my port is not in use by some other app?
Here is the status of the port before running (it is used)
netstat -an
TCP 127.0.0.1:2005 0.0.0.0:0 LISTENING
I hope this snippet is sufficent to explain what I'm doing, it's a merge of several steps.
WSADATA WSAData;
int err = WSAStartup(MAKEWORD(2, 2), &WSAData);
SOCKADDR_IN sin;
socklen_t recsize = sizeof(sin);
int one = 1;
SOCKADDR_IN* csin;
SOCKET csock = INVALID_SOCKET;
socklen_t crecsize = sizeof(SOCKADDR_IN);
int sock_err;
if (m_socket != INVALID_SOCKET)
{
memset(&sin, 0, recsize);
if(m_blocal)
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
else
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_family = AF_INET;
sin.sin_port = htons(m_iPort);
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(int));
sock_err = bind(m_socket, (SOCKADDR*)&sin, recsize);
//HERE I want to be sure no one else runs on this port
//rest of the code using: select(m_socket + 1, &rd, &wr, &er, &timeout);
}
closesocket(m_socket);
WSACleanup();
Don't set SO_REUSEADDR. Then bind() will fail if the address is already in use and WSAGetLastError() will return WSAEADDRINUSE.
Also note that two processen can still bind to the same port if the IP addresses are different, for example, one process binding to localhost and another process binding to the LAN network address.
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.
I am working with UDP sockets over an ethernet interface between my workstation (192.168.0.1) and my WinCE6 device (192.168.0.100).
From my workstation I can send UDP packets toward my WinCE device where I have a receiving socket set up and properly receiving data on port 9002; the device then properly echoes back data to my workstation.
I want my device to answer to my workstation on a specific port: 9001.
This is the server running into my device, it is the same as this but I modified the socket bind to the address of the specific interface and I changed the PORT define:
#define BUFLEN 512 //Max length of buffer
#define PORT 9002 //The port on which to listen for incoming data
void test_udp( void )
{
SOCKET s;
struct sockaddr_in server, si_other;
int slen , recv_len;
char buf[BUFLEN];
WSADATA wsa;
slen = sizeof(si_other) ;
//Initialise winsock
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
return;
}
//Create a socket
if((s = socket(AF_INET , SOCK_DGRAM , 0 )) == INVALID_SOCKET)
{
printf( "Could not create socket : %d" , WSAGetLastError());
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl( 0xC0A80064 );
server.sin_port = htons( PORT );
//Bind
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
return;
}
//keep listening for data
while(1)
{
//clear the buffer by filling null, it might have previously received data
memset(buf,'\0', BUFLEN);
//try to receive some data, this is a blocking call
if ((recv_len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == SOCKET_ERROR)
{
return;
}
// *** CHANGE THE SEND PORT
si_other.sin_port = htons( 9001 );
//now reply the client with the same data
if (sendto(s, buf, recv_len, 0, (struct sockaddr*) &si_other, slen) == SOCKET_ERROR)
{
return;
}
}
closesocket(s);
WSACleanup();
return;
}
When I added the line below the // *** CHANGE THE SEND PORT comment to try to send the data back to port 9001, I am getting an appropriate return value for sendto which matches the number of bytes I expect to have been sent, but I don't see the data coming on my workstation (listening on 9001).
I have been banging my head against this and I cant see anything wrong. In the modified example, Any help would be greatly appreciated.
UPDATE: A firewall on my development PC was at fault. It allowed traffic back on the same port my PC was sending on, but blocked traffic on any other port. Resolving that allowed the the traffic to be sent without code changes. I had disabled the firewall previously, but did not realize that the OS had flagged the ethernet as a "public network", which still had the firewall enabled.
If, as you said, you are not getting a SOCKET_ERROR from the sendto and you are seeing an appropriate return value, this means that your OS was able to find a route toward the destination IP and was able to buffer your send request.
To change the send port it's ok if you want to answer to a different port with respect to the one from which you received data but note that this is not a typical case; the si_other struct in fact will contain the source address after the recvfrom and so the source port too. So keep your code as it is on your device side.
If you are not seeing data flowing to your workstation probably, in a simple networking context as your development environment, the problem is on the workstation: it is not receiving data.
I agree with #Daniel that you have to investigate with WireShark to see what's happening to packets.
Hope this helps
I'm encountering a strange issue using winsock when multiple network adapters are active but then one is disconnected.
This is the basic scenario:
Wifi and Ethernet are active and connected
Launch app, send UDP broadcast and receive response
Unplug Ethernet, restart app and try to send again - Nothing is sent (Wireshark shows nothing, seems Windows is dropping them before they get to NIC?)
Disable the disconnected Ethernet adapter and try again - sends fine over Wifi and gets response.
Now this is a very specific scenario but I believe it's happening in other cases, this is just the only way I know to reproduce it every time.
The following is a code snippet of the UDP send, for this example assume dstAddrStr is 192.168.1.255
struct sockaddr_in sa_remote;
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) {
printf("Error creating socket: %ld\n", WSAGetLastError());
}
int enable = 1;
if ((setsockopt(sock,
SOL_SOCKET, SO_BROADCAST, (char*)&enable, sizeof(enable))) == -1) {
printf("Error enabling broadcasts: %ld\n", WSAGetLastError());
}
const MIB_IPADDRROW & row = iptbl->table[i];
uint32 ipAddr = ntohl(row.dwAddr);
uint32 netmask = ntohl(row.dwMask);
uint32 baddr = ipAddr & netmask;
if (row.dwBCastAddr) baddr |= ~netmask;
char dstAddrStr[32]; Inet_NtoA(baddr, dstAddrStr);
memset(&sa_remote, 0, sizeof(struct sockaddr_in));
sa_remote.sin_family = AF_INET;
sa_remote.sin_addr.s_addr = inet_addr(dstAddrStr);
sa_remote.sin_port = htons(_DST_PORT);
if (sendto(sock, dpString, strlen(dpString), 0, (struct sockaddr *)&sa_remote, sizeof(struct sockaddr_in)) < 0){
printf("UDP send error Error: %ld", WSAGetLastError());
break;
}
I have problem while reading data from client on server. The read() function will always freeze (block) after all data are readed and waiting for more data what is undesirable for me.
Server program:
soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = INADDR_ANY;
bind(soc, (struct sockaddr*) &sin, sizeof(sin));
if (listen(soc, MAX))
return;
int socc; // socket for clinet
while (1) {
if ((socc = accept(soc, (struct sockaddr *) &sin, sinlen)) < 0)
break;
while ((result = read(socc, pointer, SIZE)) > 0) {
// after the data are readed, read function will block
}
// do some stuff and write reply to client => will never done
}
Client program:
...
soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
struct sockaddr_in socketAddr;
socketAddr.sin_family = AF_INET;
socketAddr.sin_port = htons(port);
memcpy(&(socketAddr.sin_addr), host->h_addr, host->h_length);
if (connect(soc, (sockaddr *)&socketAddr, sizeof(socketAddr)) == -1)
return;
if (write(soc, req.c_str(), strlen(req.c_str())) < 0)
return;
The main problem is that I don't know how much data will be client sending to server, so the server should read all data from socket and after nothing is coming, leave the reading cycle. But the server read whole message for example (30 bytes) and waiting for more (but no more is coming). The sockets are still opened because the client is waiting for reply from server.
You will need to make your socket non-blocking. The read will immediately exit in that case if there is nothing to be read with a specific error.
Look at C- Unix Sockets - Non-blocking read
As stated earlier use non blocking or add RCV_TIMEOUT to socket.
struct timeval tv;
tv.tv_sec = 30; /* 30 Secs Timeout */
setsockopt(sockid, SOL_SOCKET, SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval));