Getting the destination address of UDP packet

1.2k Views Asked by At

I have been using the following example posted in this same site. This is my version of it. (Please excuse my lack of experience with C socket programming:)

In constructor:

    server::server(io_service& io_service, const int port) : 
       udpsocket_(io_service, udp::endpoint(udp::v4(), port))) {

       int sock = udpsocket_.native();
       fd_set fdset;
       FD_ZERO(&fdset);
       FD_SET(sock, &fdset);
       int opt = 1;
       setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt));
    }

Where "udpsocket_" is actually a boost asio udp socket. This is very convenient since on one hand I can have a function which gets the destination IP from the incoming UDP message without the need for using a raw socket:

void get_destination_IP() {

    int sock = udpsocket_.native();
    char cmbuf[0x100];
    struct sockaddr_in peeraddr;
    struct msghdr mh;
    mh.msg_name = &peeraddr;
    mh.msg_namelen = sizeof(peeraddr);
    mh.msg_control = cmbuf;
    mh.msg_controllen = sizeof(cmbuf);
    int received = recvmsg(sock, &mh, 0);
    for ( // iterate through all the control headers
            struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
            cmsg != NULL;
            cmsg = CMSG_NXTHDR(&mh, cmsg))
    {
        if (cmsg->cmsg_level != IPPROTO_IP ||
                cmsg->cmsg_type != IP_PKTINFO)
        {
            continue;
        }
        struct in_pktinfo *pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
        char* destAddr = (char*) calloc(4, sizeof(char));
        destAddr = inet_ntoa(pi->ipi_spec_dst);

        stored_UDP_dest_ip_ = ip::address::from_string(destAddr);
    }
}

Now here come the problems:

  • Could I call this "get_destination_IP" asynchronously, in a non-blocking way in the same way as I call "async_receive_from"?

As in:

  udpsocket_.async_receive_from(
        boost::asio::buffer(msg_),
        udp_endpoint_,
        boost::bind(&server::UDP_recv_handler,
                this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred,
                handler
        )
  );
  • Function "recvmsg" stores the right destination IP info, but returns 0. In theory according to the man page, the "size_t numbytes" is returned there. Can I still read the datagram with "recvmsg"?

  • Is FD_ZERO necessary in the constructor?

  • Is FD_ZERO necessary at every call of "get_destination_IP"?

Thank you beforehand for your help

1

There are 1 best solutions below

0
On

See boost:asio::null_buffers() feature. If you pass boost::asio::null_buffers() to boost::asio async_*() functions then the handler is invoked when data is just available and you can (need to) receive it by yourself (eg, by recvmsg() in your case).

fdset is unused and useless there. Socket pooling is done by boost::asio for you.