Not able to get poco 1.6.1 or 1.7.6 to bind to ipv6 with Net::DatagramSocket

370 views Asked by At

Using the following code I can bind to an ipv4 address but not to a scope global ipv6 address that is also bound to this same machine. I am compiling the code like this:

g++ -lPocoFoundation -lPocoXML -lPocoUtil -lPocoNet -lcrypto -lssl -I/usr/include/Poco -o pocoudpipv6 pocoudpipv6.cpp

When I execute ./pocoudpipv6 10.X.X.X, it holds open the socket and cycles on "Waiting..." until I hit ctrl-c, which is expected. ss reports the socket:

# ss -nelup |grep 20000 UNCONN 0 0 10.X.X.X:20000 *:* users:(("pocoudpipv6",pid=2444,fd=3)) uid:1000 ino:14526705 sk:2a <->

But when I execute with ./pocoudpipv6 2001:X:X:X::X:X, this occurs:

We're resetting the ipaddress from ::1 to 2001:X:X:X::X:X Address family is ipv6 Failure launching. Error was Net Exception: Address family not supported

This problem occurs with 1.7.6 on Slackware64 14.2 as well as with 1.6.1 on Debian 8 jessie amd64. As far as I've read, ipv6 being enabled in Poco is supposed to be the default. Is there something else I need to do in order to get this test-case to work with ipv6?

And I do have at least one daemon that is binding to an ipv6 socket on this machine:

udp UNCONN 0 0 2001:X:X:X::X:X:123 :::* users:(("ntpd",pid=2133,fd=22)) ino:5247 sk:19 v6only:1 <->

Thanks in advance!

Code as follows:

#include <iostream>
#include <Net/DatagramSocket.h>
#include <Net/SocketAddress.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>

struct sigaction sigact = { 0 };

struct io_handling {
        uint8_t exit_value;
};

struct io_handling io_handler = { 0 };

static void sigint_signal_handler(int sig)
{
    if(sig == SIGINT) {
        std::cout << std::endl << "Commencing shutdown in 5...  4...  3...  2...  1..." << std::endl;
        io_handler.exit_value = 1;
    }
}

static void cleanup(void)
{
    sigemptyset(&sigact.sa_mask);
}

int main(int argc, char **argv)
{
    Poco::Net::DatagramSocket *pSocket = new Poco::Net::DatagramSocket();
    Poco::UInt16 port = 20000;
    Poco::Net::IPAddress *ipAddress = new Poco::Net::IPAddress("::1");

    if(argc == 2) {
        delete ipAddress;
        ipAddress = new Poco::Net::IPAddress(argv[1]);
        std::cout << std::endl << "We're resetting the ipaddress from ::1 to " << argv[1];
    }

    std::cout << std::endl << "Address family is ";

    if(ipAddress->family() == static_cast<Poco::Net::IPAddress::Family>(Poco::Net::Impl::IPAddressImpl::IPv6)) {
        std::cout << "ipv6 ";
    } else if(ipAddress->family() == static_cast<Poco::Net::IPAddress::Family>(Poco::Net::Impl::IPAddressImpl::IPv4)) {
        std::cout << "ipv4 ";
    } else {
        std::cout << "something else, something very wrong.";
    }

    try {
        sigact.sa_handler = sigint_signal_handler;
        sigemptyset(&sigact.sa_mask);
        sigact.sa_flags = 0;
        sigaction(SIGINT, &sigact, (struct sigaction *)NULL);

        pSocket->bind(Poco::Net::SocketAddress(*ipAddress, port));
        while(!io_handler.exit_value) {
            sleep(1);
            std::cout << std::endl << "Waiting...";
        }
    } catch(Poco::Exception& ex) {
        std::cout << std::endl << "Failure launching.  Error was " << ex.displayText() << std::endl;
    }

    delete pSocket;
    delete ipAddress;

    return 0;
}
1

There are 1 answers

0
Mishehu Mashehu On

Self-resolved. The lib I was working with was only calling up Poco::Net::DatagramSocket's default ctor, which then gives an ipv4-only socket. Calls to ::bind() will not reset that based upon the input ip address.

The solution is to not new pSocket until handling ipAddress in the example above, and then passing that and the port casted as Poco::Net::SocketAddress to the ctor, and it will create the proper socket type and automatically bind it.