Directed UDP to IP address that doesn't exist - c++

I am experiencing slowdowns when attempting to send a UDP message to an IP address that is non-existent. We read a list of IP/ports out of a configuration file and expect that those combinations will exist. In some situations, the remote machine may not be online yet and the IP will not exist on the network. In this case, i would prefer that we do not attempt to send the data.
I'm looking for suggestions on a good way to determine that the IP doesn't exist in order to skip sending the data. I do not want to completely remove it from the list because there is the chance that the machine may come online and i'd like to continue sending data.
Relevant code:
int SendData(const char *data, int size, bool openIfClosed)
{
std::lock_guard<std::mutex> lock(sendMutex);
//if the socket was not already opened, close it after i do my send
bool closeAfterSend = mySocket == INVALID_SOCKET ? true : false;
if (!OpenSocket(openIfClosed))
return 0;
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(remotePort);
address.sin_addr.s_addr = remoteIPAddress.GetIPAddressAsULong();
//check if remote address exists prior to send?
int bytesSent = sendto(mySocket, data,
size, 0, (struct sockaddr *)&address, sizeof(address));
if (bytesSent == size)
numMsgsOut++;
else
{
//fail
}
if (closeAfterSend && openIfClosed)
{
closesocket(mySocket);
mySocket = INVALID_SOCKET;
}
return bytesSent;
}

Related

UDP broadcast and multicast messages arrive but recvfrom does not receive anything

I am new to stackoverflow and also pretty much a beginner at programming and hope to find a solution here.
My code is written in C++ and should run on a computer on module with linux operating system. The program should receive messages from other linux or windows systems and then depending on the content of the messages execute further subroutines and send back a response. The windows program is also written in C++. The linux system and the windows system are connected via a switch and the switch is connected to the home network via a powerline adapter. The multicast function is enabled and supported in the switch settings, as well as in the linux system.
The linux code to test the functionality looks like this:
int createIPv4MulticastSocket(uint16_t socket_port, int allowReuseAddress)
{
int Socket;
int broadcast = 1;
sockaddr_in localSock = {};
// Bind to the proper port number with the IP address specified as INADDR_ANY
memset(&localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(socket_port);
localSock.sin_addr.s_addr = INADDR_ANY;
// Creating the Socket
printf("Creating a socket...");
if ((Socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Creating a socket failed:");
printf("\n");
}
else
{
printf("Socket created. \n");
}
// set the reuse address options
if (setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, (char*)&allowReuseAddress, sizeof(allowReuseAddress)) < 0)
{
perror("Error setting the reuse address option");
printf("\n");
}
else
printf("Setting the reuse address option...OK. \n");
// bind the socket to the defined address
printf("Try to bind the created Socket to my address. \n");
if (bind(Socket, (struct sockaddr*)&localSock, sizeof(localSock)) == -1) {
perror("Binding socket failed:");
printf("\n");
}
else
{
printf("Bind was succesful. \n");
}
// sets the socket options so you can send Broadcast messages
printf("Setting the socket options to allow Broadcast. \n");
if (setsockopt(Socket, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof(broadcast)) == -1) {
perror("Setting the socket options for allowing broadcast failed:");
printf("\n");
}
else
{
printf("Setting the broadcast options...OK. \n");
}
return Socket;
}
void joinMulticastGroup(const char* IPMulticastGroup, const char* IPLocalInterfaceAddr, int SocketDescriptor)
{
struct ip_mreq group;
int LocalIP;
int conv_ip;
if (IPLocalInterfaceAddr[0] == '\0')
{
conv_ip = inet_pton(AF_INET, IPMulticastGroup, &group.imr_multiaddr.s_addr);
if (conv_ip == 0) {
printf("Destination IP-address doesn't contain a valid network address in the specified address family.\n");
}
else if (conv_ip == -1) {
perror("No valid address family:");
printf("\n");
}
group.imr_interface.s_addr = htonl(INADDR_ANY);
}
else
{
conv_ip = inet_pton(AF_INET, IPMulticastGroup, &group.imr_multiaddr.s_addr);
if (conv_ip == 0) {
printf("Destination IP-address doesn't contain a valid network address in the specified address family.\n");
}
else if (conv_ip == -1) {
perror("No valid address family:");
printf("\n");
}
conv_ip = inet_pton(AF_INET, IPLocalInterfaceAddr, &group.imr_interface.s_addr);
if (conv_ip == 0) {
printf("Destination IP-address doesn't contain a valid network address in the specified address family.\n");
}
else if (conv_ip == -1) {
perror("No valid address family:");
printf("\n");
}
}
if (setsockopt(SocketDescriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&group, sizeof(group)) < 0)
{
perror("Adding multicast group error");
printf("\n");
}
else
printf("Adding multicast group...OK. \n");
}
void sendUDP(int sending_socket, const char* destination_ipaddress,
uint16_t destination_port, unsigned char sending_message[], int size_of_sending_message)
{
struct sockaddr_in destination_address;
long int numbytes_send;
int conv_ip;
// define destination address
printf("Convert the destination address to sockaddr_in. \n");
destination_address.sin_family = AF_INET; // IPv4 address
destination_address.sin_port = htons(destination_port); // destination port
conv_ip = inet_pton(AF_INET, destination_ipaddress, &destination_address.sin_addr.s_addr);
if (conv_ip == 0) {
printf("Destination IP-address doesn't contain a valid network address in the specified address family.\n");
}
else if (conv_ip == -1) {
perror("No valid address family:");
printf("\n");
}
memset(destination_address.sin_zero, '\0', sizeof(destination_address.sin_zero)); // fill up sin_zero with "0"
printf("Correct destination address sockaddr. \n");
printf("Sending a message...");
if ((numbytes_send = sendto(sending_socket, sending_message, size_of_sending_message, 0,
(struct sockaddr*)&destination_address, sizeof(destination_address))) == -1) {
perror("sendto() failed:");
printf("\n");
}
else
{
printf(" %i Bytes of data have been sent. \n", numbytes_send);
}
}
void receiveUDP(int receiving_socket, struct sockaddr* received_from,
unsigned char receiving_message[], int size_of_receiving_message)
{
long int numbytes_received;
unsigned int len_received_from = sizeof(*received_from);
socklen_t len_recv_from = len_received_from;
printf("Trying to receive a message...");
if ((numbytes_received = recvfrom(receiving_socket, receiving_message, size_of_receiving_message, 0,
received_from, &len_recv_from)) == -1) {
perror("Receiving message failed:");
printf("\n");
}
else
{
printf("%i Bytes an Daten erhalten\n", numbytes_received);
}
}
int main()
{
struct sockaddr received_from;
int socketfd;
unsigned char sending_message[1472], receiving_message[1472];
const char* destination_ipaddress = "192.168.178.35"; //Laptop
const char* multicast_ipaddress = "224.0.1.14"; //Multicast
const char* broadcast_ipaddress = "192.168.178.255"; //Broadcast
uint16_t destination_port = 3300;
uint16_t port = 3300;
uint16_t messageid = 0;
double altitude = 0;
double longitude = 0;
double lattitude = 0;
// Clean message buffer
memset(sending_message, '\0', sizeof(sending_message));
memset(receiving_message, '\0', sizeof(receiving_message));
// Create a Socket
socketfd = createIPv4MulticastSocket(port, 1);
// join the multicast group
joinMulticastGroup(multicast_ipaddress, "", socketfd);
// Send UDP message.
sendUDP(socketfd, broadcast_ipaddress, destination_port, sending_message, sizeof(sending_message));
/// Receive messages and read Data
while (1)
{
receiveUDP(socketfd, &received_from, receiving_message, sizeof(receiving_message));
messageid = unpackunsignedint16(receiving_message, 1);
altitude = unpackdouble(receiving_message, 3);
lattitude = unpackdouble(receiving_message, 11);
longitude = unpackdouble(receiving_message, 19);
printf("actual altitude is: %lf \n", altitude);
printf("actual lattitude is: %lf \n", lattitude);
printf("actual longitude is: %lf \n", longitude);
}
close(socketfd);
}
If i now send unicast messages to the linux program, everything works as it should and the message is received and the sent values are inserted correct into the printf() functions. Sending unicast messages also works without problems. However, if I want to receive broadcast or multicast messages, the program stops in the recvfrom() line. If I check the connected port with tcpdump port 3300 for incoming messages, they arrive at the linux system. If I try to send broadcast or multicast messages, this does not work and no outgoing messages are displayed in tcpdump.
If I try to receive broadcast or multicast messages and then go back to try again to receive unicast messages, this also does not work anymore. I do not get any error messages during the showed errorchecking.
Thanks in advance for your help.
Edit: Maybe I forgot to mention something because I thought it shouldn't be that big of a deal, but I've also read now that this could be a problem. The application is deployed to the system using a docker container
You're not correctly setting the incoming interface for multicast traffic, and you're not setting the outgoing interface at all.
When you call joinMulticastGroup, you pass an empty string for the second argument which is supposed to contain the IP address of the incoming multicast interface as a string. So if for example the machine's IP is 192.168.178.34, then you pass "192.168.178.34" for that argument.
If you don't set the outgoing multicast interface explicitly, the OS will choose whichever interface is the "default". You should use the IP_MULTICAST_IF socket option, passing the address of a struct in_addr specifying the IP address.

Recreate and send packet captured by nfqueue

I capture all the packets in one side with help of nfqueue, "record" them (all the data: ip info, next protocol info etc) with nfq_get_payload and deliver them into another side with help of udp. How can I restore this packet on another side and then send to myself(2 side) like there is no udp-encapsulation between? Should I use some nfqueue API or I have to implement all the protocols packet creation (UDP, ICMP, TCP, etc)? And how should I send this restored packet?
Ok, I successfully recreated and sent forward my packet encapsulated in UDP. After recreation I needed to send this packet to another IP, but you can use original destination address. So the code snippet:
char *full_packet;
int size;
// some actions to get full_packet and size from UDP packet
// assume you recreated this: int size = nfq_get_payload(nfa, &full_packet);
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
// also optional string needed in my case:
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, "wlan0", strlen("wlan0"));
if (sock == -1) {
perror("socket() failed");
return 1;
}
struct sockaddr_in to;
struct ip *iph = (struct ip *)full_packet;
to.sin_addr.s_addr = inet_addr("192.168.0.107"); // here you can set IP address where you need send this packet
to.sin_family = AF_INET;
int bytes = sendto(sock, full_packet, size, 0, (struct sockaddr*) &to, sizeof(to));
if (bytes == -1) {
perror("send() failed");
return 1;
}
I hope this will help somebody

Win Socket UDP connection-less recvfrom() Error

I'm working on a legacy VC6 application, that uses winsocket to listen to a UDP port for incoming packets. However I am getting the following errors. If I use WSAGetLastError() I get WSAECONNRESET, which if I read the description, doesn't seem to make sense, because its saying that remote host forcibly closed the socket, But I want use UDP connection-less manor, so it shouldn't matter what the other machine is doing... we should just listen. If I check the errno and use sterror() I get the following message. "No such file or directory". (I think this it's enum is EIO, according to http://pubs.opengroup.org/onlinepubs/009695399/functions/recvfrom.html)
I've had some success in narrowing down the issue, it appears if I take out a sendto() call, that calls back on the same port as the recvfrom(), the code seems to work ok. So something with that sendto() is putting in a bad state.
I'm looking for suggestions on why this socket is going bad, and either how to prevent or recover.
Edit
Here is the other weird part, if do the setup again for that socket (after a recvfrom() fails)... it all seems to work, even additional calls to sendto() don't seem trigger a recvfrom() fail, which in turn would call the setup again..
CODE
static VOID SetupSocketAddress( SOCKADDR_U &saRx, int nRTDPort )
{
memset(&saRx.saIPX, 0, sizeof(SOCKADDR_IPX));
saRx.saIPX.sa_family = AF_IPX; // IPX type address
memset(saRx.saIPX.sa_netnum,0x00,4); // we may have to get this number
memset(saRx.saIPX.sa_nodenum,0xff,6); // broadcast address
saRx.saIPX.sa_socket=(unsigned short)nRTDPort; // socket number
}
void CRealTimeData::SetupSocket( CRealTimeData * lpRTD, BOOL &bDone, SOCKADDR_U &saRx, int nRTDPort, SOCKADDR_U &saFrom, int &cbAddr,
DWORD &dwLocalAddress, int &nMaxIpIpxBuf, char * &pbyIpIpxRxBuf, int nFlags, BOOL bDo)
{
char szErrorCode[32];
int nReturn = 0;
if (lpRTD->m_eSourceType == V7_RTD_IPX)
{
// open IPX socket
// packet type = 4
lpRTD->m_Socket=socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX+4);
if (lpRTD->m_Socket == INVALID_SOCKET)
{
nReturn = AddSocketErrorToEventViewer( lpRTD);
bDone = TRUE;
}
// Socket must be bound prior to calling recvfrom()
// setup address
SetupSocketAddress(saRx, nRTDPort);
#ifdef _DEBUG_IPX
// test changing host number to network number
// we can't actually change though, because other programs use it this way
u_short nNetPort=0;
int nRet=WSAHtons(lpRTD->m_Socket, (unsigned short)nRTDPort, &nNetPort);
TRACE(_T("RTDIpxThread: Host Port=%04x Net Port=%04x RTD Input=%d \n"),nRTDPort, nNetPort, lpRTD->GetInputNumber());
#endif
// setup address for Sending Data on RTD
SetupSocketAddress( lpRTD->m_saRTD, nRTDPort );
// copy address - Why are we copying the address just over right later (in recvfrom() )? -NG
memcpy(&saFrom.saIPX, &lpRTD->m_saRTD.saIPX, sizeof(SOCKADDR_IPX));
cbAddr = sizeof(SOCKADDR_IPX);
}
else
{
// open IP socket
lpRTD->m_Socket=socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); // ??? should this use IPPROTO_UDP???
if (lpRTD->m_Socket == INVALID_SOCKET)
{
nReturn = AddSocketErrorToEventViewer( lpRTD);
bDone = TRUE;
}
// Socket must be bound prior to calling recvfrom()
// setup address
memset(&saRx.saIP, 0, sizeof(SOCKADDR_IN));
saRx.saIP.sin_family = AF_INET; // IP type address
saRx.saIP.sin_port=htons((u_short)nRTDPort); // PORT number
saRx.saIP.sin_addr.s_addr=htonl(INADDR_ANY); // ADDRESS number
// setup for Sending Data on RTD port
memset(&lpRTD->m_saRTD.saIP, 0, sizeof(SOCKADDR_IN));
lpRTD->m_saRTD.saIP.sin_family = AF_INET; // IP type address
lpRTD->m_saRTD.saIP.sin_port=htons((u_short)nRTDPort); // PORT number
lpRTD->m_saRTD.saIP.sin_addr.s_addr=htonl(INADDR_BROADCAST); // ADDRESS number
// copy address - Why are we copying the address just over right later (in recvfrom() )? -NG
memcpy(&saFrom.saIP, &lpRTD->m_saRTD.saIP, sizeof(SOCKADDR_IN));
cbAddr = sizeof(SOCKADDR_IN);
char szHostName[MAX_PATH+1];
if (gethostname(szHostName, MAX_PATH)==0)
{
hostent *phe=gethostbyname(szHostName);
dwLocalAddress = *(DWORD*)&phe->h_addr_list[0];
}
} // end IP socket
if (!bDone)
{
// enable broadcasting
BOOL bOptVal=TRUE;
nReturn=setsockopt(lpRTD->m_Socket, SOL_SOCKET, SO_BROADCAST, (char *)&bOptVal, sizeof(BOOL));
if (nReturn == SOCKET_ERROR)
{
nReturn=WSAGetLastError();
}
// enable reuse of address
bOptVal=TRUE;
nReturn=setsockopt(lpRTD->m_Socket, SOL_SOCKET, SO_REUSEADDR, (char *)&bOptVal, sizeof(BOOL));
if (nReturn == SOCKET_ERROR)
{
nReturn=WSAGetLastError();
}
// get the socket's max message size
int nOptSize=sizeof(UINT);
UINT nMaxMsgSize=600;
nReturn=getsockopt(lpRTD->m_Socket, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *)&nMaxMsgSize, &nOptSize);
if (nReturn == SOCKET_ERROR)
{
nReturn=WSAGetLastError();
nMaxMsgSize=600; // default max size
}
nMaxIpIpxBuf=nMaxMsgSize; // always create buffer that is as big as the sockets max message size
pbyIpIpxRxBuf = new char[nMaxIpIpxBuf]; // allocate buffer for receiving data from socket
if (!pbyIpIpxRxBuf)
bDone = TRUE;
else
memset(pbyIpIpxRxBuf,0,nMaxIpIpxBuf*sizeof(char));
// bind to address
nReturn=bind(lpRTD->m_Socket, &saRx.sa, cbAddr);
if (nReturn == SOCKET_ERROR)
{
nReturn = AddSocketErrorToEventViewer(lpRTD);
bDone = TRUE;
}
// send data to indicate startup
if (lpRTD->m_eProtocol == V7_RTD_ENHANCED)
{
int nLen=lpRTD->BuildErrorMsg(V7_ERTD_SERVICE_STARTUP, szErrorCode, sizeof(szErrorCode));
nReturn=sendto(lpRTD->m_Socket,szErrorCode,nLen, nFlags, &lpRTD->m_saRTD.sa, cbAddr);
if (nReturn == SOCKET_ERROR)
{
nReturn=WSAGetLastError();
}
}
} // end if not done
}
Main()
nFromLen = cbAddr;
nReturn=recvfrom(lpRTD->m_Socket, pbyIpIpxRxBuf, nMaxIpIpxBuf, nFlags, &saFrom.sa, &nFromLen);
if(nReturn == SOCKET_ERROR)
{
SetupSocket(lpRTD, bDone, saRx, nRTDPort, saFrom, cbAddr, dwLocalAddress, nMaxIpIpxBuf, pbyIpIpxRxBuf,nFlags, FALSE);
nReturn=recvfrom(lpRTD->m_Socket, pbyIpIpxRxBuf, nMaxIpIpxBuf, nFlags, &saFrom.sa, &nFromLen);
}
// if i take this out no error....
nReturn=sendto(lpRTD->m_Socket, szErrorCode, nLen, nFlags, &saFrom.sa, cbAddr);

bind: Socket operation on non-socket

I writing a server and a client and keep getting 'bind: Socket operation on non-socket'.
I've researched the heck out of this, have other code that runs in another application and have exhausted 8 hours trying to find this bug.
The code is:
void TCPSocket::buildTCPSocket(int port)
{
initializeSocket1();
getSocket();
bindSocket();
listenToSocket();
acceptSocket();
// now you can send() and recv() with the
// connected client via socket connectedTCPSocket
}
void TCPSocket::getSocket()
{
// Get an internet domain socket AF_INET
if(socket1 = socket(AF_INET, SOCK_STREAM,0) == -1)
{
perror("socket");
exit(1);
}
}
void TCPSocket::bindSocket()
{
// Bind to a port on the host
int myAddressSize = sizeof(myAddress);
int bindReturnValue = bind(socket1, (struct sockaddr *) &myAddress, AddressSize);
if (bindReturnValue == -1)
{
perror("bind"); // <== Error message generated here
exit(1);
}
printf("Socket for TCP bound to port %d\n", port);
}
Also, prior to this, I memset the memory block with this function.
void TCPSocket::initializeSocket1()
{
// Fill tcpSocket struct with 0's
memset(&myAddress, '\0', sizeof(myAddress));
myAddress.sin_family = AF_INET;
myAddress.sin_addr.s_addr = INADDR_ANY;
// Conver PORT to big-endian if necessary
myAddress.sin_port = htons(this->port);
}
Variables are declared in the header file of the class.
public:
struct sockaddr_in myAddress, clientAddress;
void buildTCPSocket(int newPort);
private:
int port;
int socket1, socket2;
socklen_t clientAddressLength;
-- Edit the code should be a little more clear now. socket1 is initialized in getSocket().
I've seen where a bunch of guys have missed the parens in the if but I think I eliminated that error by declaring myAddressSize and bindReturnValue.
Any input is appreciated.
Thank you,
Ted S
Ok, problem solved. Of course the problem is never where you are looking are you would have found it. Here is the corrected code. The problem was in a missing set of parens in the call to socket().
void TCPSocket::getSocket()
{
// Get an internet domain socket AF_INET
if((socket1 = socket(AF_INET, SOCK_STREAM,0)) == -1)
{
perror("socket");
exit(1);
}
}
Thanks again!
I can almost guarantee you that you're getting that error because you never initialized socket1.
Typically you have to do something like this:
int socket1 = socket(AF_INET, SOCK_STREAM, 0);
bind(socket1, ...);
I don't see any code anywhere in there for setting up socket1. This is what the error message is telling you, after all. socket1 isn't a socket, so it's failing.
Edit: As a follow up, this is one of the reasons why I try to avoid using the syntax
if ((foo = bar()) == ERROR)
{
// handle me
}
And instead stick with:
void TCPSocket::getSocket()
{
// Get an internet domain socket AF_INET
socket1 = socket(AF_INET, SOCK_STREAM, 0);
if (socket == -1)
{
perror("socket");
exit(1);
}
}

Reopen connected datagram socket

I have a connection protocol that has been defined by our customer. Data are sent between two linux computers using UDP and TCP protocols. The IP addresses and ports are fixed on startup.
We are sending messages at 200 Hz and I have been using connect to save some time on the transmissions.
My problem is that if there is a communication error, I need to tear down the connections and reinitialise.
I have a problem with one of the UDP connections as it will not rebind to the required address and returns errno 22.
The code I am using is something like:
int
doConnect(int& sock, int local_port, char *local_ip, int remote_port, char *remote_ip)
{
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = htons(local_port);
inet_pton(local_ip,&addr.sin_addr.s_addr);
if (0 > bind(sock, (struct sockaddr*)&addr, sizeof(addr)))
{
printf("Bind Error errno = %d\n", errno);
return ERR_BIND;
}
memset(&addr, 0, sizeof(sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = htons(remote_port);
inet_pton(remote_ip,&addr.sin_addr.s_addr);
if (0 > connect(sock, (struct sockaddr*)&addr, sizeof(addr)))
{
printf("Connect Error errno = %d\n", errno);
return ERR_CONNECT;
}
return ERR_OK;
}
The way that this is used is like this:
int s1(-1), s2(-1);
doConnect(s1, 31003, "172.17.21.255", 31006, "172.17.21.1");
doConnect(s2, 31001, "172.17.21.3", 31004, "172.17.21.1");
When an error occurs
close(s1);
close(s2);
doConnect(s1, 31003, "172.17.21.255", 31006, "172.17.21.1");
doConnect(s2, 31001, "172.17.21.3", 31004, "172.17.21.1");
Here the local address is 172.17.21.3 and I am connecting to 172.17.21.1. s1 listens to a broadcast message.
s1 successfully reconnects to the remote machine, but s2 fails with error 22 from the call to bind.
I have tried explicitly calling bind and connect to an AF_UNSPEC address immediately before I close the socket. This doesn't solve the problem.
Are there any options that I should be using?
Perhaps you could try:
int val = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
I also suggest you double check that you're not passing the same socket to the two consecutive doConnect() calls (as errno 22 = EINVAL, which in the case of bind() appears to mean that the socket is already bound to an address).
The underlying socket layer might hold the port & IP address still open, even after your call to close. Try some of the following:
do a sleep(10) (or more) between the close and the call to doConnect again
configure the sockets using setsockopt with the SO_LINGER set to off
This actually happens more commonly with TCP connections, but I see no reason UDP can't have this problem as well.