0

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

Community
  • 1
  • 1
BHZ
  • 83
  • 1
  • 8
  • `Could I call this "get_destination_IP"` There is no function named `get_destination_IP` in the code you've shown. `in the same way as I call "async_receive_from"?` You don't call `async_receive_from` in any way, in the code you've shown. `Is FD_ZERO necessary here?` Is FD_ZERO necessary where? `Is FD_ZERO necessary at every call of the function?` At every call of which function? – Igor Tandetnik Jun 28 '15 at 15:16
  • I have no idea about boost APIs, but normally - anything that could potentially block for I/O can be called in async manner. `select` is one mechanism or you could have newer `epoll` based APIs. It's hard to tell why `recvmsg` returns zero, without looking at other code as the manpage says it means other end closed connection. `FD_ZERO` is required in constructor as you want to shut off your interest in all descriptors except your socket(s) that you creat. In get_destination_IP - I don't think it's needed - in fact `FD_ZERO` and `FD_SET` would make it unnecessarily cumbersome. – gabhijit Jun 28 '15 at 16:31

1 Answers1

0

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.

demeter
  • 92
  • 1