poll() with non blocking udp socket - c++

I am trying to make a c++ program work which is written by somebody else. I am having hard time understanding it. I am not even %100 sure that we can use poll() with a UDP socket but the code I am refactoring, is using poll() to read from udp socket as follows:
fd.fd = m_bsocket;
fd.events = POLLIN;
iPollResult = poll(&fd, 1, iTimeout);
if(iPollResult > 0)
{
int iReceivedByteCount = recv(m_bsocket, p_pBuffer, p_iBufferSize, 0);
if(iReceivedByteCount > 0)
{
*p_pReadSize = iReceivedByteCount;
}
else
{
eReturnValue = UDP_READ_ERROR;
}
}
return eReturnValue;
I tried sending udp packets to this program using command line:
echo "123" | nc -u 127.0.0.1 25
It looks like poll() always times out and returns 0, therefore I can not read anything.
I also wrote a small c# program that sends udp datagram, but I can not receive the message. I am wondering what I am doing wrong...

While UDP sockets can be used to connect to another host, they are mostly used "connectionless". Reading your question and comments it makes no sense that you have a connected socket. Instead it should be connectionless as suggested by WouterH in his comment.
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in sin = { 0 };
sin.sin_family = AF_INET;
sin.sin_port = htons(25);
sin.sin_addr.s_addr = INADDR_ANY;
bind(sockfd, (struct sockaddr *) &sin, sizeof(sin));
// Make socket non-blocking if needed
With the above code, whenever someone sends UDP packets to port 25 on any address of your host, your socket will intercept it. Use e.g. poll or select to know when data is available.

You don't need to call connect() as UDP is connectionless. You need to bind() the socket to the IP of the interface you are listening on or 0.0.0.0 (INADDR_ANY) for all interfaces. And when sending to a destination, use sendto().
For completeness: if you call connect() on a UDP socket, you are just setting a default destination for the send() function (then you can use send instead of sendto).
If you want to receive data, you always have to bind() the socket to the interface, or all interfaces. Beware that you will have to verify the source address from the messages you are receiving. So you might want to filter the sender by using recvfrom() and checking the source address.

Related

winsock2 client return self port number

I'm using lib winsock2 in Visual Studio community, using simple client example.
After executing connect() function, would like to know how can I get/return self/source port number of open connection.
In winsock2, when a connection is established you can bind socket port to some specific port you want to use. For example, let´s say you are creating an UDP or TCP socket and you want that a specific local port is used. In that case you can do that by calling bind function ( https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind )
if (port != 0) {
int rv = -1;
struct sockaddr_in recv_addr;
ZeroMemory(&recv_addr, sizeof(struct sockaddr_in));
recv_addr.sin_family = AF_INET;
recv_addr.sin_port = htons(port);
recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
rv = bind(udp_channel->socket, (SOCKADDR *)& recv_addr, sizeof(recv_addr));
}
This is the same bind function you will use to set listening port when your socket will act as a server in UDP or TCP, it's the same.
In case you don't do socket binding, socket port will be assigned on connection. There seems to be the function getsockname that user207421 mentioned.
getsockname() or getpeername()
returning Structured data with short sin_family and char sa_data[] with different amount of data depending on the protocols used
after connection to server use fuction getsockname() or getpeername() to get the structured data we need to extract the data to get the port
you use function ntohs() for extracting the port data with macro function SS_PORT to convert struct to sockaddr_in
example:
sockaddr struc_;
int struc_len = sizeof(struc_);
/* connect function*/
getsockname(ConnectSocket, (LPSOCKADDR)&struc_, &struc_len);
int port_int_ = ntohs(SS_PORT(&struc_));
or you can define a ready-made structure / create your own, with a pointer to port number data.

C++ UDP Broadcast using ::write

I am writing a UDP client/server application. The server is a broadcast server, that broadcasts on a particular port to two clients on the same subnet. Each client receives a datagram and sends a response to the server. Each client knows the ip address of the server in advance.
My client is basically as in the client example of http://man7.org/linux/man-pages/man3/getaddrinfo.3.html, i.e. it uses the connect() function to specify the endpoint of all outgoing packets. By using connected UDP, the client can use read() and write() to the socket file descriptor rather than sendto/recvfrom.
For my server, I want to adopt a similar approach - configure the socket for broadcasting, and call read/write on the file descriptor. I can bind() the socket to listen for incoming datagrams on the specified port, and these are collected fine.
Minus error checking, my server code looks like this:
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
int broadcast = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof int);
struct sockaddr_in servaddr;
memset((char*) &servaddr, 0, sizeof servaddr);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int success = bind(sockfd, (struct sockaddr*) &servaddr, sizeof servaddr);
int BUFSIZE = 256;
char buf[BUFSIZE];
while (1)
{
// this works fine
int bytes_read = read(sockfd, buf, BUFSIZE);
// WANT TO BROADCAST HERE
int bytes_written = write(sockfd, buf, bytes_read);
}
However, when I try and broadcast a packet in the write() line, I get a 'Destination address not specified' error. I could call connect() to set the destination address, but I don't think connect() works on a broadcast socket.
Is there a way of broadcasting using write() rather than sendto?
The problem with using connect() for broadcast is that (in addition to modifying the behavior of send()/write()), connect() will install a filter on the socket so that it only receives packets whose source-IP field matches the IP address specified in the argument to connect().
That means if you call connect() on your socket with a broadcast-address as its argument, then your socket will only receive packets coming from that broadcast-address -- but packets are never (AFAIK) tagged as coming from a broadcast address -- rather, their Source-IP field is set to the IP address of the computer that sent the packet, as usual. The upshot is that if you connect() your socket to a broadcast address, you won't receive any packets on that socket.

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.

Port to Port data transfer with UDP

I'm working on this project where the source and destination ports are specified for sending a message via a UDP socket in C++. I've got the TCP portion of the project working fine, but I don't understand how to specify both the source and destination ports when setting this up.
The way I would know how to do it is the "receiver" sets up a recvfrom() call, with the port that the "sender" will also use in the sendto() command... but it would need to be the same port.
So, given that I need port x on the "receiver" to talk to port y on the "sender", how would I do that?
Thanks
You can define a source port when you call bind on the sender side. For instance:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) { /*error*/}
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(source_port); // here
int res = bind(sockfd,(struct sockaddr*)&sin, sizeof(sin));
if (res < 0) { /*error*/}
And the destination port goes into the sockaddr parameter passed to sendto.
If this is one-to-one mapping, i.e. one source talks to one destination, then simply bind(2) the local port and connect(2) to the remote IP and port (contrary to common misconception you can connect UDP sockets). Do that on both sides (with appropriate remote and local IPs/ports of course), and now you can just use recv(2) and send(2) without explicit addressing.
If one side needs to wait for the other to send the first packet, then extract source address/port received with recvfrom(2), and then connect(2) to it.
If, on the other hand, one side acts as a multi-client server, then do same bind(2)/connect(2) dance on the client, but only do bind(2) to local port and then use recvfrom(2)/sendto(2) on the server.
If you need simultaneous duplex communication, then you should use sockets in blocking mode -- fcntl(...O_NONBLOCK...), and use select() to determine if your socket is writable or readable or both. Here is a nice example on how this can be done http://www.lowtek.com/sockets/select.html