Problem creating socket with C++ in winsock2 - c++

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?

Related

POSIX UDP socket not binding to correct IP

I'm in the process of writing a project for college involving writing a chat client and server using POSIX sockets and C++.
The clients are supposed to converse with each other using P2P, such as each client has his own open UDP socket through which he sends and recieves messages from/to other clients.
My problem is 2-fold:
My UDPSocket class constructor seems to be ignoring the port number completely, binding to port 65535 regardless of the parameter.
The port is binding to IP 255.255.255.255 rather than my own IP (10.0.0.3), or at least that's what i get when I call getpeername.
To the best of my knowledge passing INADDR_ANY should bind to my local address, and passing port number 0 should make the OS choose a free port, what am I doing wrong?
This is the constructor of my UDPSocket class:
UDPSocket::UDPSocket(int port){
socket_fd = socket (AF_INET, SOCK_DGRAM, 0);
// clear the s_in struct
bzero((char *) &in, sizeof(in)); /* They say you must do this */
//sets the sin address
in.sin_family = (short)AF_INET;
in.sin_addr.s_addr = htonl(INADDR_ANY); /* WILDCARD */
in.sin_port = htons((u_short)port);
fsize = sizeof(from);
//bind the socket on the specified address
if(bind(socket_fd, (struct sockaddr *)&in, sizeof(in))<0){
perror ("Error naming channel");
}
}
This is the initialization:
m_Socket = new UDPSocket(0);
And this is the method I use to retrieve the binded address: (UDPSocket inherits Socket)
std::string Socket::GetSocketAddress()
{
struct sockaddr_in addr;
int len = sizeof(addr);
getpeername(socket_fd, (struct sockaddr*)&addr, (socklen_t*)&len);
char ipAddressBuffer[50];
memset(ipAddressBuffer, 0, sizeof(ipAddressBuffer));
sprintf(ipAddressBuffer, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
return ipAddressBuffer;
}
Any help would be greatly appreciated,
Avi.
You're using getpeername , which gives you the remote address of a connected socket. If you check the return value of getpeername(), it should indicate failure.
You need to use getsockname() instead of getpeername() to get the address of your local socket
You need to check that getsockname() succeeds.
Note that your socket is bound to the special 0.0.0.0 address, which means "all local interfaces", so that's what getsockname() will also return.
Answering the more general question "How to set up peer-to-peer communications with UDP":
With UDP sockets, while you can use connect, you generally don't want to, as that restricts you to a single peer per socket. Instead, you want to use a single unconnected UDP socket in each peer with the sendto and recvfrom system calls to send and receive packets with a different address for each packet.
The sendto function takes a packet and a peer address to send it to, while the recvfrom function returns a packet and the peer address it came from. With a single socket, there's no need to multiplexing with select or poll -- you just call recvfrom to get the next packet from any source. When you get a packet, you also get the peer address to send packets (back) to.
On startup, your peer will create a single socket and bind it to INADDR_ANY (allowing it to receive packets on any interface or broadcast address on the machine) and either the specific port assigned to you program or port 0 (allowing the OS to pick any unused port). In the latter case, you'll need to use getsockname to get the port and report it to the user. Once the socket is set up, the peer program can sendto any peer it knows about, or recvfrom any peer at all (including those it does not yet know about).
So the only tricky part is bootstrapping -- getting the first packet(s) flowing so that peers can recieve them and figure out their peer addresses to talk to. One method is specifying peer addresses on the command line when you start each peer. You'll start the first one with no arguments (as it has no peers -- yet). It will just recvfrom (after socket setup) to get packets from peers. Start the second with the address of the first as an argument. It sends a packet (or several) to the first peer, which will then know about the new peer as soon as it gets the first packet. Now start a third client with the addresses of the first two on the command line...

UDP Broadcasting using winsock on a win 10 machine not working

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.

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().

Nothing received from recvfrom on windows

I have some problems on Windows 8 using recvfrom. I have a socket which is bound to INADDR_ANY (0.0.0.0), and i'd like to receive some packets on it.
The problem is that I see those packets in Wireshark, but recvfrom never tells me that the received size is greater than 0. I've tried biding the socket to 127.0.0.1 or even to my local IPv4 address, I never get anything. The port used is 7321 (locally)
I use the ENet library for the creation of the socket, and then I used that socket in recvfrom. Here's the code that never returns the expected packets.
uint8_t* buffer; // max size needed normally (only used for stun)
buffer = (uint8_t*)(malloc(sizeof(uint8_t)*2048));
memset(buffer, 0, 2048);
socklen_t from_len;
struct sockaddr addr;
from_len = sizeof(addr);
int len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, &addr, &from_len); //m_host is of type ENetHost, the socket in it is a file descriptor like standard sockets
As I said, it's a bit weird as Wireshark shows me the packets (which are STUN responses if you want to know).
Can someone help me find out what is missing that may be causing this issue?
Your addr variable is declared as a sockaddr. It needs to be declared as a sockaddr_in (works with IPv4 only) or SOCKADDR_STORAGE (works with both IPv4 and IPv6), and then typecast it to sockaddr* when passing it to recvfrom().
Aside from that, you say that recvfrom() is not returning >= 0. So what is it actually returning? If it returns 0, then a 0-length packet was received (impossible for TCP, but possible for UDP). If it returns -1 (aka SOCKET_ERROR), then an error occured so use WSAGetLastError() to find out what that error actually is.
I can think of 2 possible reasons you are having the problem:
1) You might not have the port correct on your sendto & recvfrom socket. So say you are sending packets to port 6000, but your recvfrom is listening on port 6001 or something. Just double check both programs are using the same port.
2) Windows firewall. I would run the program as an admin just to be safe, but also make sure you allow your program through windows firewall to communicate using private or public networks.

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.