Qualcomm 远程信息处理 SDK - 用户指南(13)
4.4.14 启用/禁用袜子
此示例应用程序演示了如何启用/禁用袜子。
1.实现初始化回调并获取DataFactory实例
或者,可以通过获取管理器实例提供初始化回调。当管理器初始化完成时,数据工厂将调用回调。
auto initCb = [&](telux::common::ServiceStatus status) {
std::lock_guard<std::mutex> lock(mtx);
status_ = status;
initCv.notify_all();
};
auto &dataFactory = telux::data::DataFactory::getInstance();
- 获取SocksManager实例
std::unique_lock<std::mutex> lck(mtx);
auto dataSocksMgr = dataFactory.getSocksManager(opType, initCb);
3.等待DataConnectionManager初始化完成
initCv.wait(lck);
3.1 检查SocksManager初始化状态
如果SocksManager初始化失败,可以通过调用步骤2来完成新的初始化尝试。如果SocksManager初始化成功,则继续执行步骤4。
if (status_ == telux::common::ServiceStatus::SERVICE_AVAILABLE) {
// Go to step 4
}
else {
//Go to step 2 for another initialization attempt
}
4.可选地,实例化启用Socks回调实例
auto respCb = [](telux::common::ErrorCode error) {
std::cout << std::endl << std::endl;
std::cout << "CALLBACK: "
<< "enableSocks Response"
<< (error == telux::common::ErrorCode::SUCCESS ? " is successful" : " failed")
<< ". ErrorCode: " << static_cast<int>(error) << "\n";
promise.set_value(1);
};
- 使用enableSocks()启用/禁用socks
dataSocksMgr->enableSocks(enable, respCb);
现在,将为 setFirewall 响应调用响应回调。
4.4.15 获取专用无线电承载状态和指示
此示例应用程序演示了如何获取专用无线电承载状态和指示。
1.实现IServingSystemListener监听类
class ServingSystemListener : public telux::data::IServingSystemListener {
public:
ServingSystemListener(SlotId slotId) : slotId_(slotId) {}
void onDrbStatusChanged(telux::data::DrbStatus status) override {
std::cout << "\n onDrbStatusChanged on SlotId: "
<< static_cast<int>(slotId_) << std::endl;
switch(status) {
case telux::data::DrbStatus::ACTIVE:
std::cout << "Current Drb Status is Active" << std::endl;
break;
case telux::data::DrbStatus::DORMANT:
std::cout << "Current Drb Status is Dormant" << std::endl;
break;
case telux::data::DrbStatus::UNKNOWN:
std::cout << "Current Drb Status is Unknown" << std::endl;
break;
default:
std::cout << "Error: Unexpected Drb Status is reported" << std::endl;
break;
}
}
private:
SlotId slotId_;
};
2.可选地,实例化初始化回调
auto initCb = [&](telux::common::ServiceStatus status) {
subSystemStatus = status;
subSystemStatusUpdated = true;
cv_.notify_all();
};
- 获取DataFactory和数据服务系统管理器实例并检查数据服务系统管理器是否准备就绪
auto &dataFactory = telux::data::DataFactory::getInstance();
do {
subSystemStatusUpdated = false;
std::unique_lock<std::mutex> lck(mtx_);
dataServingSystemMgr = dataFactory.getServingSystemManager(slotId, initCb);
if (dataServingSystemMgr) {
std::cout << "\n\nInitializing Data Serving System manager subsystem on slot " <<
slotId << ", Please wait ..." << std::endl;
cv_.wait(lck, [&]{return subSystemStatusUpdated;});
subSystemStatus = dataServingSystemMgr->getServiceStatus();
}
if (subSystemStatus == telux::common::ServiceStatus::SERVICE_AVAILABLE) {
std::cout << " *** DATA Serving System is Ready *** " << std::endl;
break;
}
else {
std::cout << " *** Unable to initialize data Serving System *** " << std::endl;
}
} while (1);
- 注册服务系统监听器
dataServingSystemMgr->registerListener(dataListener);
- 获取专用无线承载状态
telux::data::DrbStatus drbStatus = dataServingSystemMgr->getDrbStatus();
switch(drbStatus) {
case telux::data::DrbStatus::ACTIVE:
std::cout << "Current Drb Status is Active" << std::endl;
break;
case telux::data::DrbStatus::DORMANT:
std::cout << "Current Drb Status is Dormant" << std::endl;
break;
case telux::data::DrbStatus::UNKNOWN:
std::cout << "Current Drb Status is Unknown" << std::endl;
break;
default:
std::cout << "Error: Unexpected Drb Status is reported" << std::endl;
break;
}
现在,等待专用无线电承载通知。
4.4.16 获取服务状态和指示
此示例应用程序演示了如何获取服务状态和指示。
1.实现IServingSystemListener监听类
class ServingSystemListener : public telux::data::IServingSystemListener {
public:
ServingSystemListener(SlotId slotId) : slotId_(slotId) {}
void onServiceStateChanged(telux::data::ServiceStatus status) {
std::cout << "\n onServiceStateChanged on SlotId: " << static_cast<int>(slotId_);
if(status.serviceState == telux::data::DataServiceState::OUT_OF_SERVICE) {
std::cout << "Current Status is Out Of Service" << std::endl;
} else {
std::cout << "Current Status is In Service" << std::endl;
}
}
private:
SlotId slotId_;
};
- (可选)实例化初始化回调
auto initCb = [&](telux::common::ServiceStatus status) {
subSystemStatus = status;
subSystemStatusUpdated = true;
cv_.notify_all();
};
- 获取数据工厂和数据服务系统管理器实例以及数据服务系统管理器是否准备就绪
auto &dataFactory = telux::data::DataFactory::getInstance();
do {
subSystemStatusUpdated = false;
std::unique_lock<std::mutex> lck(mtx_);
dataServingSystemMgr = dataFactory.getServingSystemManager(slotId, initCb);
if (dataServingSystemMgr) {
std::cout << "\n\nInitializing Data Serving System manager subsystem on slot " <<
slotId << ", Please wait ..." << std::endl;
cv_.wait(lck, [&]{return subSystemStatusUpdated;});
subSystemStatus = dataServingSystemMgr->getServiceStatus();
}
if (subSystemStatus == telux::common::ServiceStatus::SERVICE_AVAILABLE) {
std::cout << " *** DATA Serving System is Ready *** " << std::endl;
break;
}
else {
std::cout << " *** Unable to initialize data Serving System *** " << std::endl;
}
} while (1);
- 注册服务系统监听器
dataServingSystemMgr->registerListener(dataListener);
- 获取当前服务状态
// Callback
auto respCb = [&slotId](
telux::data::ServiceStatus serviceStatus, telux::common::ErrorCode error) {
std::cout << std::endl << std::endl;
std::cout << "CALLBACK: "
<< "requestServiceStatus Response on slotid " << static_cast<int>(slotId);
if(error == telux::common::ErrorCode::SUCCESS) {
std::cout << " is successful" << std::endl;
logServiceStatusDetails(serviceStatus);
}
else {
std::cout << " failed"
<< ". ErrorCode: " << static_cast<int>(error) << std::endl;
}
};
dataServingSystemMgr->requestServiceStatus(respCb);
现在,等待请求响应和通知。
4.4.17 获取漫游状态和指示
此示例应用程序演示了如何获取漫游状态和指示。
1.实现IServingSystemListener监听类
class ServingSystemListener : public telux::data::IServingSystemListener {
public:
ServingSystemListener(SlotId slotId) : slotId_(slotId) {}
void onRoamingStatusChanged(telux::data::RoamingStatus status) {
std::cout << "\n onRoamingStatusChanged on SlotId: "
<< static_cast<int>(slotId_) << std::endl;
bool isRoaming = status.isRoaming;
if(isRoaming) {
std::cout << "System is in Roaming State" << std::endl;
} else {
std::cout << "System is not in Roaming State" << std::endl;
}
}
private:
SlotId slotId_;
};
- (可选)实例化初始化回调
auto initCb = [&](telux::common::ServiceStatus status) {
subSystemStatus = status;
subSystemStatusUpdated = true;
cv_.notify_all();
};
- 获取数据工厂和数据服务系统管理器实例以及数据服务系统管理器是否准备就绪
auto &dataFactory = telux::data::DataFactory::getInstance();
do {
subSystemStatusUpdated = false;
std::unique_lock<std::mutex> lck(mtx_);
dataServingSystemMgr = dataFactory.getServingSystemManager(slotId, initCb);
if (dataServingSystemMgr) {
std::cout << "\n\nInitializing Data Serving System manager subsystem on slot " <<
slotId << ", Please wait ..." << std::endl;
cv_.wait(lck, [&]{return subSystemStatusUpdated;});
subSystemStatus = dataServingSystemMgr->getServiceStatus();
}
if (subSystemStatus == telux::common::ServiceStatus::SERVICE_AVAILABLE) {
std::cout << " *** DATA Serving System is Ready *** " << std::endl;
break;
}
else {
std::cout << " *** Unable to initialize data Serving System *** " << std::endl;
}
} while (1);
- 注册服务系统监听器
dataServingSystemMgr->registerListener(dataListener);
- 获取当前服务状态
// Callback
auto respCb = [&slotId](
telux::data::RoamingStatus roamingStatus, telux::common::ErrorCode error) {
std::cout << std::endl << std::endl;
std::cout << "CALLBACK: "
<< "requestRoamingStatus Response on slotid " << static_cast<int>(slotId);
if(error == telux::common::ErrorCode::SUCCESS) {
std::cout << " is successful" << std::endl;
logRoamingStatusDetails(roamingStatus);
}
else {
std::cout << " failed"
<< ". ErrorCode: " << static_cast<int>(error) << std::endl;
}
};
dataServingSystemMgr->requestRoamingStatus(respCb);
现在,等待请求响应和通知。
4.4.18 建立按需 PDN 连接
对于按需 PDN 连接:
- DNS 服务器未在 resolv.conf 中更新,并且 gethostbyname 等例程将失败
- 默认路由未设置,并且未绑定到接口的套接字连接将失败本节的目的是提供以下信息:
- 使用 dig 进行 DNS 解析
- 绑定到接口以启用连接
- 获取数据连接管理器并等待服务可用
获取数据工厂、数据连接管理器并等待服务可用。
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);
}
}
2.注册监听器
向数据连接管理器注册监听器,用于监听数据调用状态。
dataConnMgr->registerListener(dataListener);
- 在上述槽位 ID 和配置文件 ID 以及操作类型上启动数据调用
{
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);
}
}
4.等待数据通话连接
连接数据调用后,获取对所发起的数据调用的引用。该信息将被发送给侦听器。
// 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);
}
5.使用数据调用提供的DNS地址解析远程主机
使用数据调用对象中的 DNS 地址(例如:primaryDnsAddress)信息来使用 dig(域信息探查器)解析域。dig 有多种模式并接受多种参数,但是,出于名称解析的目的,我们使用“+short”模式,其中 dig 不输出详细答案,而仅提供 IP 地址。我们解析 dig 提供的 IP 地址,看看它是否是有效的 IP 地址。
// 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;
6.连接远程主机
除了客户端的常规连接例程之外,我们还需要绑定到允许我们访问远程主机的接口。这是通过使用setsockopt 方法完成的。
// 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;
- 清理
std::cout << "Cleaning up" << std::endl;
close(sockfd);
dataConnMgr->deregisterListener(dataListener);
dataConnMgr = nullptr;