# 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 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 p; telux::data::IpFamilyType ipFamilyType = telux::data::IpFamilyType::IPV4; dataConnMgr->startDataCall( profileId, ipFamilyType, [&](const std::shared_ptr &dataCall, telux::common::ErrorCode errorCode) { std::cout << "startCallResponse: errorCode: " << static_cast(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 &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 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: Jun 24, 2026 [Previous Topic Get roaming status and indication](https://docs.qualcomm.com/bundle/publicresource/80-PF458-1/topics/get_roaming_status_and_indication.md) [Next Topic Enable IP Passthrough](https://docs.qualcomm.com/bundle/publicresource/80-PF458-1/topics/enable_ip_passthrough.md)