UDP Broadcasting using winsock on a win 10 machine not working - c++

I'm making a LAN multiplayer game using c++ and winsock, were I've created my own protocol for connecting two machines to eachother. The protocol involves broadcasting a message over the local LAN, which strangely isn't working on one of the two machines I'm using to test my code. The strange part is that it's as mentioned working on one machine, whereas not on the other. I've used wireshark to monitor outgoing packets, and the packets isn't being sent on the failing machine, even though that sendto() is returning the correct amount of bytes. The only difference between the machines is that one (the failing one) is using win10 and the other win8.
Is there any difference in the winsock library/networking layer between windows 10 and windows 8 that could cause this? Else, do you have any other ideas of what could cause the failure?
The code for sending a broadcast looks like this:
sockaddr_in send_addr;
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(PORT);
send_addr.sin_addr.s_addr = inet_addr("255.255.255.255");
int iResult = sendto(sock,
reinterpret_cast<char*>(&packet),
sizeof(Packet),
0,
(SOCKADDR *)&send_addr,
sizeof(send_addr));
if (iResult == SOCKET_ERROR)
{
printf("Failed to send broadcastmsg");
}
And the code to recieve it looks like this:
sockaddr_in sender_addr;
int sender_addrLen = sizeof(sender_addr);
Packet recvdPacket = {};
int iResult = recvfrom(sock,
reinterpret_cast<char*>(&recvdPacket),
sizeof(recvdPacket),
0,
(SOCKADDR*)&sender_addr,
&sender_addrLen);
if (iResult > 0)
{
return recvdPacket;
}
return Packet{};

You need to enable broadcast setting SO_BROADCAST before sending a broadcast message: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740476(v=vs.85).aspx ,
Why do we need SocketOptions.SO_BROADCAST to enable broadcast?
char broadcast = 1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast))
Also you should use directed broadcast (for example, 192.168.0.255) instead of Internet broadcast (255.255.255.255). I believe you don't need Internet broadcast.
Also, can you print the value returned by sendto? is iResult == sizeof(Packet)?
Last, which is the size of Packet? Is it a class? you are reinterpreting &packet as a char *. You must be sure there is no error there.
Could broadcast be blocked in the Win10 PC? I don't know if it's possible.
Consider using multicast.

Related

socket() and sendto() dont return error codes when theres no internet connection

Why does socket() not return INVALID_SOCKET when I have no internet connection? I thought it would fail and then I could exit my function. My function's error checking continues till recvfrom() and then just hangs when I have no internet connection. I thought that socket() or sendto() would return an error code when I have no internet connection but they are not. I am trying to rely on their failure as a sign the user has no internet connection and exit my function but thats just not working for some weird reason.
void myFunc()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("myipaddress");
server_addr.sin_port = htons(123);
// Doesn't fail when there's no internet connection
protoent *proto = getprotobyname("udp");
int s = socket(PF_INET, SOCK_DGRAM, proto->p_proto);
if (s == INVALID_SOCKET) {
goto Cleanup;
}
// Doesn't fail when there's no internet connection
char msg[48] = { 0x08, 0, 0, 0, 0, 0, 0, 0, 0 };
int iResult = sendto(s, msg, sizeof(msg), 0, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (iResult == SOCKET_ERROR) {
goto Cleanup;
}
// Hangs when there's no internet connection
memset(msg, 0, sizeof(msg));
struct sockaddr saddr;
socklen_t saddr_l = sizeof(saddr);
iResult = recvfrom(s, msg, 48, 0, &saddr, &saddr_l);
if (iResult == SOCKET_ERROR) {
goto Cleanup;
}
Cleanup:
closesocket(s);
WSACleanup();
}
Because there is no requirement for sockets to be connected to the internet. Many applications use sockets for inter-process communication on a single machine. Such applications can still run fine when there is no internet connection.
sendto() could arguably return an error code; it can (under certain situations, as demonstrated by the desktop notification about network connection status) know that the packet can never be delivered. However, UDP communication and sendto() make no guarantees about delivery whatsoever, and apparently the implementation you are using does not consider the lack of connection worthy of an error code. Arguably this is a quality of implementation issue.
recvfrom() simply waits as long as you have specified (possibly indefinitely) for a message, but never receives one. Again, this is within spec, and again it could be considered a quality of implementation issue whether or not this particular situation is flagged or not.
I looked into the linux man page for sendto (assuming that all relevant the implementations are sufficiently similar to the berkley sockets baseline) here:
http://linux.die.net/man/2/sendto
The documentation does not mention reporting and error if the network stack 'knows' that the message is undeliverable. This is reasonable, since the socket's transport may well not be IP4 or IP6. It could be any transport we chose to write a driver for: packet radio, serial cables or carrier-pigeons (if we could figure out the hardware for loading the printed messages into their satchels).
The only reference to possible errors from the transport is here:
These are some standard errors generated by the socket layer. Additional errors may be generated and returned from the underlying protocol modules; see their respective manual pages.
As mentioned by others, UDP is an unreliable datagram protocol. Unreliability is expected. Non-delivery of a message is expected. Therefore not really an error. There would be little incentive for a protocol-layer author to code for handling transport errors - since they too are expected and not an error in the context of this protocol.
When a socket is opened over TCP, then lack of socket continuity is an error. If the transport reports that packet delivery is not possible (for a sufficiently long time) then this is an error condition in the protocol.

C++ UDP sendto fails, needs sleep

I have a UDP client C++ code - based on WSA sockets - that works well. The code was originally written in VS6 and I recently recompiled it in VS2010 for 64bit environment, with only little adjustments.
Now, the sendto() fails to send something, if there is no Sleep(..) or any equivalent delay after the sendto() and before closesocket(). "Fails" means, that sendto() returns the proper amount of data, but I see no message on the network (I used wireshark to check this).
This is my code:
void CTest::SendHello()
{
SOCKET sSocket;
sSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(m_strDstIpAddr);
addr.sin_port = htons(m_nTxPort);
int nMsgLen = 8;
char pTxBuffer[8];
*((DWORD*) &pTxBuffer[ 0]) = 0x11223344;
*((DWORD*) &pTxBuffer[ 4]) = 0;
int nSent = sendto(sSocket, pTxBuffer, nMsgLen, 0, (struct sockaddr *) &addr, sizeof(addr));
Sleep(10); // <- this seems to be necessary
if (nSent != nMsgLen)
{
CString s = "error sending HELO\n";
AfxMessageBox(s);
}
closesocket(sSocket);
}
Without the Sleep(), the code does not send anything, yet it returns no errors. With the Sleep() it works. Also, this is happens in release version, when compiled for debug, the code also works without the Sleep().
It seems, as if the closesocket() shuts the socket down, before the message is finally sent, but I thought sendto() is a synchronous function. I tried using SO_LINGER, but this is not applicable for SOCK_DGRAM sockets.
Since the code is inside a DLL, I can't create the socket in ctor and delete it in the dtor, because SendHello() might be called from different thread contexts, and I like to avoid to make the code too complicated.
thanks for any help
With UDP there is no ordering of data between the sender and receiver and data sent using UDP datagram sockets isn't guaranteed to arrive. All sleep is doing in your case is practically providing enough time for the data to arrive at the other end. If you want confirmation of receipt and error checking, then you can either code a scheme for UDP or use TCP. In fact, you can turn off the server completely and your client will happily fire UDP packets out without error even though there is nobody listening.
to insure a connection, look at connect(). Nothing prevents using connect with UDP and you can then use send() recv().

Receiving broadcast packet addressed to 255.255.255.255 in C++

I have a device that is discovered by sending a broadcast packet to 255.255.255.255 on port 4930 and the device responds by sending a packet back to 255.255.255.255 on port 4930.
I have a snippet of C++ code which can send a packet to 255.255.255.255 on port 4930 (both source and destination port), but it can't receive a packet back from the broadcast address 255.255.255.255.
I can see the device is working fine, wireshark can see the packets coming back and forth and the propriety software supplied with the device can discover the device just fine, the problem is with the C++ program so please keep on topic with your responses.
Now, as I have said I can send a packet just find, but firstly I can't bind to the IP address 255.255.255.255 to receive the packets. I can change the multicast address to 239.255.255.250 and the socket will bind but I need the address 255.255.255.255.
My snippet of code is below, I am using VC++2010
bool CPTUProgramDlg::FindPTU(u_short port, const char * Destaddress){
{
//Data to send
char packet_data[10] = {0x44,0x43,0x55,0x44,0x5f,0x50,0x49,0x4e,0x47,0x00};
int packet_size=10;
SOCKET sock;
struct sockaddr_in addr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
// set SO_BROADCAST on a socket to true (1): (so we can transmit to 255 addr)
//In order to use broadcast the options of socket must change
char broadcastON = 1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcastON, sizeof broadcastON);
if (sock < 0)
return false;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(Destaddress); // Specify dest IP
sendto(sock, packet_data, packet_size, 0, (struct sockaddr*)&addr, sizeof(addr));
if (bind(sock,(struct sockaddr*) &addr,sizeof(addr)) != -1){
char Buff[512];
recv(sock,Buff,512,0);
}
closesocket(sock);
}
return 1;
}
Wireshark screenshot to prove packets are being send:
From the wireshark output its seen that the special device is using broadcast to communicate and will use the same port number as source and destination.
Normal socket communication will require using matching port numbers but broadcast messages cannot be exchanged over the same socket, especially when the port numbers do not match as seen with wireshark.
Binding on 255.255.255.255 (INADDR_BROADCAST) should generally work but may be limited by your OS privileges and permissions.
You may try to solve the problem by using two sockets - one for receiving and one for sending. Of course the listening socket have to be setup first and bound to 0.0.0.0 (INADDR_ANY) and port 4930. In this case there is no easy way to filter by destination address (as I wrongly written in my comment) because most standard socket APIs do not provide a way to get the destination addess from the socket. On Linux there is an exception - IP_PKTINFO at SOL_IP...
By using recvfrom you will get the source unicast address of the responding device(s). You have to note that if you have more that one such device on your network you will get more than one response.

Receiving UDP broadcast

I have to receive an UDP broadcast (in Ubuntu if that makes any difference). Using Wireshark, I can see the packet being sent from the server machine, and I can see it being received by my client machine, but my program is completely oblivious. This is what I have:
sockaddr_in si_me, si_other;
int s;
assert((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))!=-1);
int port=6000;
int broadcast=1;
setsockopt(s, SOL_SOCKET, SO_BROADCAST,
&broadcast, sizeof broadcast);
memset(&si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(port);
si_me.sin_addr.s_addr = INADDR_ANY;
assert(::bind(s, (sockaddr *)&si_me, sizeof(sockaddr))!=-1);
while(1)
{
char buf[10000];
unsigned slen=sizeof(sockaddr);
recvfrom(s, buf, sizeof(buf)-1, 0, (sockaddr *)&si_other, &slen);
printf("recv: %s\n", buf);
}
It is compiled in debug mode, the asserts aren't being erased during compilation, and my program just blocks on recvfrom.
Is there any other hoop I have to jump through to receive an untargeted UDP broadcast?
Edit: just a bit more info, I have the two computers connected on a dedicated switch, no outside interference. I also have a second network card on my client computer that connects to the company network, which also works.
I can ping both the outside (Internet working) and my server machine (plus I can see the actual packets in Wireshark), but you never know what might cause this problem.
As it turns out my code is perfectly fine, as I thought it would be. There was a problem with the network setup itself.
For posterity, I had set up two static IP'd computers on their own hub, instead of using the built in DHCP server on the server machine to allocate the IP address for the other computer. Pretty localized for my problem but you never know..
To send and receive broadcast
Be sure that netmask is correct. in windows mask for broadcast packets does not matters, but not in linux.
bind socket to INADDR_ANY
setsockopt to BROADCAST
call sendto with sendaddr.sin_addr.s_addr = inet_addr("your_interface_broadcast_address").
or - call sento several times for each interface with its broadcast ip address.
call recvfrom. any time before calling recvfrom, set up length parameter.

Problem creating socket with C++ in winsock2

I'm having the weirdest problem causing me headaches. Consider the following code:
// Create and bind socket
std::map<Connection, bool> clients;
unsigned short port=6222;
struct sockaddr_in local_address, from_address;
int result;
char buffer[10000];
SOCKET receive_socket;
local_address.sin_family = AF_INET;
local_address.sin_addr.s_addr = INADDR_ANY;
local_address.sin_port = htons(port);
receive_socket = socket(AF_INET,SOCK_DGRAM,0);
What's happening is receive_socket is not binding, I get SOCKET_ERROR. When I debug the program and check receive_socket, it appears to just be garbled crap. I put a breakpoint on the 'std::map' line. When I step into each line of the above code, the debug cursor jumps straight from the 'unsigned short port' line to the first 'local_address.sin' line, even though I am using step into (F11), it does not stop at struct, int, char or SOCKET lines, it jumps straight over them.
At this point I hover my mouse over local_address, from_address, result, buffer and receive_socket. They are all full of garbled crap. Is this because I have not defined these variables yet? I've also noticed that when I reach the bottom of the above code, local_address.sin_port is set to 19992, but it should be 6222?
Edit: here is my binding code which is failing because the if statement is true:
if(bind( receive_socket, (SOCKADDR*) &local_address, sizeof(local_address)) == SOCKET_ERROR)
{
closesocket(receive_socket);
return 1;
}
I figured out the answer! The problem was I was not calling WSAStartup anywhere in my program. The following code at the beginning fixed it:
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
return 1;
}
I found this out by getting the error number from WSAGetLastError() and looking it up on msdn.
Try changing SOCK_DGRAM to SOCK_STREAM
According to MSDN,
SOCK_STREAM - A socket type that provides sequenced, reliable, two-way, connection-based byte streams with an OOB data transmission mechanism. This socket type uses the Transmission Control Protocol (TCP) for the Internet address family (AF_INET or AF_INET6).
SOCK_DGRAM - A socket type that supports datagrams, which are connectionless, unreliable buffers of a fixed (typically small) maximum length. This socket type uses the User Datagram Protocol (UDP) for the Internet address family (AF_INET or AF_INET6).
And as far as the port goes...
local_address.sin_port is set to 19992, but it should be 6222?
htons converts a port number in host byte order to network byte order (see here)
local_address.sin_port = htons(port);
I found that rather weird. Also, why htons() the port? That makes no sense. Couldn't you just use getaddrinfo() or something like that, or does winsock require to manually fill in info?