0

I am writing program to use BOOST library for UDP protocol. I have occurred with an error on windows only, it is working correct on CentOS 6.9 (Linux) GCC.

Issue is - When I use send_to function to write data on socket for specific IP or Port and suppose that IP/PORT is not working, then parallel reading socket inform us that it has data available for reading. When I read that data then it has length = -1 using native socket.

Example: Suppose for this UDP, Server PORT is 9000 and client PORT 6000, client port is not working, and forcefully send datagram packets (UDP packets) from 9000 (Server) to 6000 (client). Here, on read socket we have data and its length = -1

Here, question: why 9000 (Server) socket have data for reading just after write to socket, but during read it has -1 length.

So, if anyone have solution of this issue then please discuss.

Below is the sample code:

#include "stdafx.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPCRECATED

#include "WinSock2.h"

#include <boost/asio.hpp>
using boost::asio::ip::udp;

boost::asio::io_service m_ioService;

bool DoesSocketHaveAnyData(udp::socket *m_lpSocket)
{

    // set the timeout to UDP_MILLISEC_WAIT_FOR_DATA seconds
    struct timeval tv;
    tv.tv_sec = 0;
    //tv.tv_usec = 1000 * 1000 * 20;    // UDP_MILLISEC_WAIT_FOR_DATA;
    tv.tv_usec = 1;                     // UDP_MILLISEC_WAIT_FOR_DATA;

    // We'll need to get the underlying native socket for this select call, in order to add a simple timeout on the read:
    int nativeSocket = (int)m_lpSocket->native_handle();

    fd_set fileDescriptorSet;
    FD_ZERO(&fileDescriptorSet);
    FD_SET(nativeSocket, &fileDescriptorSet);

    bool m_blnCheck = false;

    //Wait for message until timeout expires
    if (select(nativeSocket + 1, &fileDescriptorSet, NULL, NULL, &tv) == 0)
    {
        m_blnCheck = false;
    }
    else
    {
        if (!FD_ISSET(nativeSocket, &fileDescriptorSet)) 
        {
            m_blnCheck = false;
        }
        else
        {
            //Issue arise here -> Receice data here, upon checking length -1 (initially, sending data buffer to specific remote endpoint).


            //==> Way 1
            /*//boost::system::error_code ee;
            //size_t tt = m_lpSocket->available(ee);
            size_t m_availableNoOfBytes = m_lpSocket->available();
            if (m_availableNoOfBytes >= 2) { m_blnCheck = true; }*/

            //==> Way 2
            struct sockaddr_in src_addr;    /* Used to receive (addr,port) of sender */
            int src_addr_len;               /* Length of src_addr */
            int len;                        /* Length of result from nativeSocket */
            char line[BUFSIZ * 2] = { 0 };

            src_addr_len = sizeof(src_addr);

            len = recvfrom(nativeSocket, line, BUFSIZ * 2, MSG_PEEK /* flags */, (struct sockaddr *) &src_addr, &src_addr_len);
            /*printf("Msg from (%u,%u): `%s' (%u bytes)\n", src_addr.sin_addr.s_addr, src_addr.sin_port, line, len);*/

            if (len > 0)
            {
                m_blnCheck = true;
            }
            else
            {
                len = recvfrom(nativeSocket, line, BUFSIZ * 2, 0 /* flags */, (struct sockaddr *) &src_addr, &src_addr_len);
            }
        }
    }

    return m_blnCheck;
}


int main()
{
    int m_uiMyPortNumber = 9000;

    try {
        //boost::asio::ip::udp::endpoint boostEndPoint(boost::asio::ip::udp::v4(), m_uiMyPortNumber);
        udp::endpoint boostEndPoint(boost::asio::ip::address::from_string("192.168.1.117"), m_uiMyPortNumber);
        udp::socket *m_lpSocket = new udp::socket(m_ioService, boostEndPoint);


        bool blnCheck = false;
        do {

            m_lpSocket->set_option(boost::asio::socket_base::reuse_address(true));
            m_lpSocket->set_option(boost::asio::socket_base::broadcast(true));
            m_lpSocket->set_option(boost::asio::socket_base::do_not_route(true));

            boost::system::error_code error_obj;
            boost::asio::ip::udp::endpoint remote_endpoint(boost::asio::ip::address::from_string("192.168.1.121"), 6000);


            /////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //Issue arise here -> Sending data buffer to specific remote endpoint. Also, "remote endpoint" is not having opened UDP port.

            //=> Way 1: using boost 
            size_t  m_sendto = m_lpSocket->send_to(boost::asio::buffer((char *)"TEST", 4), remote_endpoint, 0, error_obj);
            if (error_obj) { return false; }


            //=> Way 2: using native socket
            /*struct sockaddr_in si_other;

            si_other.sin_family = AF_INET;
            si_other.sin_port = htons(6000);            

            #ifdef _WIN32_WINNT 0x0501
                        si_other.sin_addr.s_addr = inet_addr("192.168.1.121"); //for XP
            #else
                        inet_pton(AF_INET, "192.168.1.121", &inaddr.sin_addr.s_addr); //for Vista or higher
            #endif

            size_t m_sendto = sendto(m_lpSocket->native_handle(), (char *)"TEST", 4, 0, (struct sockaddr*) &si_other, sizeof(si_other));*/

            blnCheck = DoesSocketHaveAnyData(m_lpSocket);

        } while (blnCheck == false);

        printf("success\n");

    }
    catch (boost::system::system_error const &e) 
    {
        printf("%s\n", e.what());
    }

    getchar();
    return 0;
}

1 Answers1

1

If an UDP packet is send to a destination which has no socket to handle this packet then (usually) a ICMP unreachable message will be send to the original source IP. If received there it will set an flag on the sender socket so that the problem will be delivered to the application with the next socket operation, i.e. the next send or recv will fail.

In practice the target might not send the ICMP unreachable (disabled or rate limited) or a firewall on the target, on the destination or somewhere in between might block the ICMP unreachable to be delivered - it is actually not uncommon to block ICMP in general. In these cases the sender will not receive the ICMP unreachable message and cannot propagate the error to the application.

The difference in your case is thus likely that in some cases ICMP unreachable gets blocked before it can reach the original sender and in other cases not.

For more information see also boost::asio error for UDP async_receive and UDP socket fail to receive ECONNREFUSED.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172