# Establish on-demand PDN connectivity

For on-demand PDNs connectivity:

- The DNS servers are not updated in resolv.conf and routines like gethostbyname would fail
- The default routes are not setup and socket connection without binding to an interface would fail

The purpose of the section is to provide information about:

- DNS resolution using dig
- Binding to an interface to enable connectivity

1. Get Data Connection Manager and wait for service availability

Get the data factory, data connection manager and wait until the service is available.

auto &dataFactory = telux::data::DataFactory::getInstance();
    {
         std::promise<telux::common::ServiceStatus> p;
         dataConnMgr = dataFactory.getDataConnectionManager(
             slotId, [&](telux::common::ServiceStatus status) { p.set_value(status); });
         if (dataConnMgr) {
             std::cout << "\n\nInitializing Data connection manager subsystem on slot " << slotId
                       << ", Please wait ..." << std::endl;
             subSystemStatus = p.get_future().get();
         }
         if (subSystemStatus == telux::common::ServiceStatus::SERVICE_AVAILABLE) {
             std::cout << "Data sub-system is ready" << std::endl;
         } else {
             std::cerr << "Unable to initialize data subsystem. Exiting..." << std::endl;
             exit(1);
         }
    }
    Copy to clipboard

2. Register listener

Register the listener with the data connection manager for listening to data call status.

dataConnMgr->registerListener(dataListener);
    Copy to clipboard

3. Start data call on the mentioned slot Id and profile id and operation type

{
     std::promise<telux::common::ErrorCode> p;
     telux::data::IpFamilyType ipFamilyType = telux::data::IpFamilyType::IPV4;
     dataConnMgr->startDataCall(
            profileId, ipFamilyType,
            [&](const std::shared_ptr<telux::data::IDataCall> &dataCall,
                telux::common::ErrorCode errorCode) {
                std::cout << "startCallResponse: errorCode: " << static_cast<int>(errorCode)
                          << std::endl;
                p.set_value(errorCode);
            },
            opType);
    
     telux::common::ErrorCode errorCode = p.get_future().get();
     if (errorCode != telux::common::ErrorCode::SUCCESS) {
         std::cerr << "Failed to start data call. Exiting..." << std::endl;
         exit(1);
     }
    }
    Copy to clipboard

4. Wait for the data call to get connected

When the data call is connected, obtain a reference to the data call that was brought up. This
information would be sent to the listener.

// In the listener
    void onDataCallInfoChanged(const std::shared_ptr<telux::data::IDataCall> &dataCall) override {
         std::cout << "\n onDataCallInfoChanged";
         logDataCallDetails(dataCall);
         if (dataCall->getDataCallStatus() == telux::data::DataCallStatus::NET_CONNECTED) {
             p_.set_value(dataCall);
         }
    }
    
    // In the main method
    std::shared_ptr<telux::data::IDataCall> dataCall = dataCallFuture.get();
    if (dataCall == nullptr) {
         std::cerr << "Could not get data call object. Exiting..." << std::endl;
         exit(1);
    }
    Copy to clipboard

5. Resolve the remote host using the DNS address provided by the data call

Use the DNS address (Ex: primaryDnsAddress) information from the data call object to resolve the
domain using dig (Domain Information Groper). dig has multiple modes and accepts a variety of
parameters, however, for the purpose of name resolution, we use the “+short” mode where detailed
answers are not output by dig, but only the IP addresses are provided. We parse the IP addresses
provided by dig to see if it is a valid IP address.

// The resolve method
    std::string resolve(std::string domain, std::string dnsAddress) {
         std::cout << "Resolving " << domain << " using DNS server at " << dnsAddress << std::endl;
         FILE *cmd;
         std::string ipAddress;
         char cipAddress[SIZE_IP_ADDR_BUF] = {0};
    
         // Use the provided DNS address to request dig for name resolution
         std::string command = "/usr/bin/dig @" + dnsAddress + " " + domain + " +short";
         std::cout << "Command: " << command << std::endl;
         cmd = popen(command.c_str(), "r");
         if (cmd) {
             sockaddr_in address;
             // Get all the answers from the DNS server
             while (NULL != fgets(cipAddress, SIZE_IP_ADDR_BUF, cmd)) {
                 cipAddress[strlen(cipAddress) - 1] = '\0';
    
                 // If the received answer is verified as a valid IP address, return the address
                 if (inet_pton(AF_INET, cipAddress, &address.sin_addr) == 1) {
                     ipAddress = cipAddress;
                     std::cout << ipAddress;
                     ipAddress.erase(
                         std::remove(ipAddress.begin(), ipAddress.end(), '\n'), ipAddress.end());
                     break;
                 }
             }
         }
         std::cout << "\n\n";  // Declutters output from dig
         return ipAddress;
    }
    
    // In the main method
    std::string remoteIp = resolve(domain, dataCall->getIpv4Info().addr.primaryDnsAddress);
    if (remoteIp == "") {
        std::cerr << "Could not resolve " << domain << ". Exiting..." << std::endl;
        exit(1);
    }
    std::cout << "Resolved " << domain << " to " << remoteIp << std::endl;
    Copy to clipboard

6. Connect to the remote host

In addition to the usual connection routine on the client side, we additionally would need to
bind to the interface that would allow us to reach the remote host. This is done here by using the
setsockopt method.

// The connect method
     int connect(std::string ipAddress, std::string outBoundIf, std::string portNumber) {
         std::cout << "Connecting to " << ipAddress << " on port " << portNumber << " via " << outBoundIf
                 << std::endl;
         int sockfd = 0;
         sockaddr_in serverIpAddress;
         serverIpAddress.sin_family = AF_INET;
         serverIpAddress.sin_port = htons(stoi(portNumber));
    
         if (inet_pton(AF_INET, ipAddress.c_str(), &serverIpAddress.sin_addr) <= 0) {
             std::cerr << "Cannot parse IP address" << std::endl;
             return -1;
         }
         // Create the socket
         if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
             std::cerr << "Socket creation failed" << std::endl;
             return -1;
         }
    
         // Bind the socket to the interface
         ifreq ifr;
         g_strlcpy(ifr.ifr_name, outBoundIf.c_str(), outBoundIf.length());
         if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
             std::cerr << "Socket bind failed with " << strerror(errno) << std::endl;
             close(sockfd);
             return -1;
         }
    
         // Connect to the remote host
         if (connect(sockfd, (sockaddr *)&serverIpAddress, sizeof(serverIpAddress)) < 0) {
             std::cerr << "Connect failed: " << strerror(errno) << std::endl;
             close(sockfd);
             return -1;
         }
         return sockfd;
     }
    
     // In the main method
     int sockfd = connect(remoteIp, dataCall->getInterfaceName(), portNumber);
     if (sockfd < 0) {
         std::cerr << "Could not connect to " << domain << ". Exiting..." << std::endl;
         exit(1);
     }
     std::cout << "Connected to " << domain << std::endl;
    Copy to clipboard

7. Clean-up

std::cout << "Cleaning up" << std::endl;
    close(sockfd);
    dataConnMgr->deregisterListener(dataListener);
    dataConnMgr = nullptr;
    Copy to clipboard

Last Published: Mar 31, 2026

[Previous Topic
Get roaming status and indication](https://docs.qualcomm.com/bundle/publicresource/80-PF458-9/topics/get_roaming_status_and_indication.md) [Next Topic
Enable IP Passthrough](https://docs.qualcomm.com/bundle/publicresource/80-PF458-9/topics/enable_ip_passthrough.md)