parseUrl_multi:识别IPv6地址格式(如[2001:db8::1]:80)。将sockaddr_in替换为sockaddr_storage。loadParseIntfAndURL:调用tr143_initSockAddrV6或通用地址初始化函数。从接口获取IPv6地址(需新增字段)。具体解释一下如何升级好吗 我给你相应的代码
/*
* fn static LOAD_PROTO parseUrl_multi(char *pUrl, LOAD_MULTI_CFG *pCfg)
* brief
* details
*
* param[in] pUrl
* param[out] pCfg
*
* return LOAD_PROTO
* retval LOAD_PROTO_HTTP/LOAD_PROTO_FTP/LOAD_PROTO_UNKNOWN
*
* note
*/
/*
* fn static LOAD_PROTO parseUrl_multi(char *pUrl, LOAD_MULTI_CFG *pCfg)
* brief 解析URL(支持IPv4/IPv6),提取协议、主机、端口、路径
* details 兼容IPv6格式(方括号包裹地址),处理HTTP/FTP协议
*
* param[in] pUrl 输入URL字符串(如http://[2001:db8::1]:8080/path)
* param[out] pCfg 输出解析结果的结构体
*
* return LOAD_PROTO 协议类型(HTTP/FTP/UNKNOWN)
* retval LOAD_PROTO_HTTP/LOAD_PROTO_FTP/LOAD_PROTO_UNKNOWN
*
* note 1. IPv6 URL需符合RFC3986标准(方括号包裹地址);
* 2. 保留原IPv4解析逻辑,兼容旧版本。
*/
LOAD_PROTO parseUrl_multi(const char *pUrl, LOAD_MULTI_CFG *pCfg)
{
char *pStr = NULL; // 临时指针(用于找路径/端口)
char *pHost = NULL; // 主机起始指针(协议后的部分)
char *hostEnd = NULL; // IPv6主机结束指针(']'的位置)
char *portStart = NULL; // 端口起始指针
UINT16 port = 0; // 端口号(默认值由协议决定)
// 初始化:清空关键字段,避免脏数据
memset(pCfg, 0, sizeof(LOAD_MULTI_CFG));
#ifdef INCLUDE_REALTEK_TR143_SPEEDUP
CUTIL_STR_STRNCPY(pCfg->downLoadUrl, pUrl, DEV2_DIAG_DOWNLOAD_DOWNLOADURL_L);
#endif
// 1. 参数合法性检查(避免崩溃)
if (NULL == pUrl || NULL == pCfg) {
TR143_ERROR("parseUrl_multi: 无效参数(pUrl=%p, pCfg=%p)", pUrl, pCfg);
return LOAD_PROTO_UNKNOWN;
}
// 2. 解析协议类型(HTTP/FTP),初始化默认端口
if (0 == strncasecmp(pUrl, "http://", 7)) {
pCfg->proto = LOAD_PROTO_HTTP;
pHost = (char *)pUrl + 7; // 跳过"http://",指向主机起始
port = DEFAULT_HTTP_PORT; // HTTP默认端口:80
} else if (0 == strncasecmp(pUrl, "ftp://", 6)) {
pCfg->proto = LOAD_PROTO_FTP;
pHost = (char *)pUrl + 6; // 跳过"ftp://",指向主机起始
port = DEFAULT_FTP_CTRL_PORT; // FTP默认端口:21
} else {
TR143_ERROR("parseUrl_multi: 未知协议(URL=%s)", pUrl);
return LOAD_PROTO_UNKNOWN;
}
// 3. 提取URL中的用户名和密码(如http://user:pass@host/path)
if (FALSE == tr143_cutUserPasswdFromURL(pHost, pCfg->username, pCfg->password)) {
TR143_DEBUG("parseUrl_multi: URL无用户名密码");
}
// 4. 区分IPv4/IPv6,解析主机和端口
if (*pHost == '[') { // 4.1 处理IPv6地址(方括号包裹)
pCfg->isIPv6 = 1; // 标记为IPv6
pHost++; // 跳过'[',指向IPv6地址起始
hostEnd = strchr(pHost, ']'); // 找']'(IPv6地址结束符)
if (NULL == hostEnd) { // 缺少']',URL无效
TR143_ERROR("parseUrl_multi: IPv6 URL格式错误(缺少']')");
return LOAD_PROTO_UNKNOWN;
}
*hostEnd = '\0'; // 截断主机部分(pHost~hostEnd-1为纯IPv6地址)
// 4.1.1 解析IPv6端口(']'后接':'+端口)
portStart = hostEnd + 1; // 指向']'后的字符
if (*portStart == ':') { // 存在端口
portStart++; // 跳过':',指向端口起始
if (sscanf(portStart, "%hu", &port) != 1) { // 端口不是有效数字
TR143_ERROR("parseUrl_multi: IPv6端口无效(port=%s)", portStart);
return LOAD_PROTO_UNKNOWN;
}
// 找路径起始符'/'(截断端口部分)
pStr = strchr(portStart, '/');
if (pStr != NULL) {
*pStr = '\0'; // 截断端口,保留路径
}
}
} else { // 4.2 处理IPv4/域名(无方括号)
pCfg->isIPv6 = 0; // 标记为IPv4
// 找端口分隔符':'或路径起始符'/'
pStr = strpbrk(pHost, ":/");
if (pStr != NULL) {
if (*pStr == ':') { // 存在端口
// 提取端口(如host:port/path → 解析port)
if (sscanf(pStr + 1, "%hu", &port) != 1) {
TR143_ERROR("parseUrl_multi: IPv4端口无效(port=%s)", pStr + 1);
return LOAD_PROTO_UNKNOWN;
}
// 找路径起始符'/'(截断端口部分)
char *slash = strchr(pStr + 1, '/');
if (slash != NULL) {
*slash = '\0'; // 截断端口,保留路径
pStr = slash; // 指向路径起始
} else {
pStr = pStr + 1 + strlen(pStr + 1); // 无路径,指向字符串末尾
}
} else { // 无端口,直接截断路径
*pStr = '\0'; // 截断主机部分,保留路径
}
}
}
// 5. 填充主机地址到结构体(复制到内部缓冲区,避免原URL被修改)
CUTIL_STR_STRNCPY(pCfg->_buf, pHost, DEV2_DIAG_DOWNLOAD_DOWNLOADURL_L);
pCfg->pHost = pCfg->_buf; // pHost指向复制后的主机地址(IPv4/IPv6)
// 6. 填充端口到结构体(区分IPv4/IPv6)
if (pCfg->isIPv6) {
pCfg->dstAddrV6.sin6_port = htons(port); // IPv6端口(网络字节序)
if (portStart != NULL) { // 调整端口指针到复制后的缓冲区
pCfg->pPort = portStart + (pCfg->_buf - pHost);
*(pCfg->pPort - 1) = '\0'; // 截断主机与端口(同原逻辑)
}
} else {
pCfg->dstAddr.sin_port = htons(port); // IPv4端口(网络字节序)
if (pStr != NULL && *pStr == '/') { // 调整端口指针位置
pCfg->pPort = pStr - strlen(pStr) + 1;
pCfg->pPort += (pCfg->_buf - pHost);
*(pCfg->pPort - 1) = '\0'; // 截断主机与端口
}
}
// 7. 解析路径(区分HTTP/FTP)
if (pStr != NULL && *pStr == '/') { // 存在路径(以'/'开头)
if (LOAD_PROTO_HTTP == pCfg->proto) {
// HTTP:保存绝对路径(如/path/file.txt)
CUTIL_STR_STRNCPY(pCfg->pAbsPath, pStr, sizeof(pCfg->pAbsPath));
} else { // FTP
// FTP:保存路径(如/path/)
CUTIL_STR_STRNCPY(pCfg->pPathName, pStr, sizeof(pCfg->pPathName));
if ('u' == pCfg->doru) { // 上传场景:提取文件名(如file.txt)
char *fileNameStart = strrchr(pCfg->pPathName, '/');
if (fileNameStart != NULL) {
CUTIL_STR_STRNCPY(pCfg->pFileName, fileNameStart + 1, sizeof(pCfg->pFileName));
*fileNameStart = '\0'; // 截断路径(仅保留目录)
}
}
}
*pStr = '/'; // 恢复路径起始符(避免原URL被破坏)
}
// 8. 调试日志(验证解析结果)
TR143_DEBUG("parseUrl_multi: 解析结果→ proto=%d, isIPv6=%d, host=%s, port=%d, path=%s",
pCfg->proto, pCfg->isIPv6, pCfg->pHost, port,
(LOAD_PROTO_HTTP == pCfg->proto) ? pCfg->pAbsPath : pCfg->pPathName);
return pCfg->proto; // 返回协议类型
}
/*
* fn static BOOL loadParseIntfAndURL(LOAD_MULTI_CFG *pCfg, char *pDiagSt, size_t diagLen,
* char *pIntf, size_t intfLen, const char *loadURL)
* brief Parse Download/Upload URL/PROTO to config.
* details
*
* param[in]
* param[out] pCfg Download/Upload config.
* pDiagSt DiagnosticsState.
* load_diag_obj DIAG_DOWNLOAD_OBJ/DIAG_UPLOAD_OBJ
*
* return
* retval T/F
*
* note
*/
/*
* fn static BOOL loadParseIntfAndURL(LOAD_MULTI_CFG *pCfg, char *pDiagSt, size_t diagLen,
* char *pIntf, size_t intfLen, const char *loadURL)
* brief 解析下载/上传的URL和接口(支持IPv4+IPv6)
* details 1. 获取接口名和DNS;2. 从WAN接口获取IPv4/IPv6地址;3. 解析URL;4. 初始化socket地址
*
* param[in] pIntf 接口路径(如Device.IP.Interface.1);loadURL 测速URL(如http://[2001:db8::1]:8080/path)
* param[out] pCfg 解析后的测速配置;pDiagSt 错误状态(如TR143_ERESOVHOSTFAIL)
*
* return TRUE=成功;FALSE=失败
*/
static BOOL loadParseIntfAndURL(LOAD_MULTI_CFG *pCfg, char *pDiagSt, size_t diagLen,
char *pIntf, size_t intfLen, const char *loadURL)
{
DEV2_ADT_WAN_OBJ adtWanObj; // WAN接口信息
DM_NUM_STACK stackAdt = EMPTY_STACK_NUM; // WAN接口遍历指针
char tmpinterface[MAX_TR143_INTF_LEN + 1] = {0}; // 临时接口路径
char dns[64] = {0}; // DNS服务器地址
CMM_RET ret = CMM_ERROR; // RDP函数返回值
#ifdef INCLUDE_ECONET_TR143_SPEEDUP
DEV2_X_TP_EASYMESH_OBJ easymeshObj = {0}; // 易展模式信息
DM_NUM_STACK stackMode = EMPTY_STACK_NUM; // 易展模式遍历指针
// IPv4地址结构体(保留原逻辑)
DEV2_IP_INTF_V4ADDR_OBJ ipIntfV4AddrObj = {0};
DM_NUM_STACK ipIntfV4AddrStack = EMPTY_STACK_NUM;
// IPv6新增:IP接口IPv6地址结构体
DEV2_IP_INTF_V6ADDR_OBJ ipIntfV6AddrObj = {0};
DM_NUM_STACK ipIntfV6AddrStack = EMPTY_STACK_NUM;
// 通用IP接口结构体(保留原逻辑)
DEV2_IP_INTF_OBJ ipIntfObj = {0};
DM_NUM_STACK ipIntfStack = EMPTY_STACK_NUM;
#endif /* INCLUDE_ECONET_TR143_SPEEDUP */
// 1. 参数合法性检查(原逻辑不变)
if (NULL == pCfg || NULL == pDiagSt || NULL == pIntf || NULL == loadURL)
{
TR143_ERROR("pCfg=(%p), pDiagSt=(%p), pIntf=(%p), loadURL=(%p)", pCfg, pDiagSt, pIntf, loadURL);
return FALSE;
}
memset(&adtWanObj, 0, sizeof(DEV2_ADT_WAN_OBJ)); // 清空WAN接口结构体
// 2. 获取默认接口(原逻辑不变:无接口时从默认网关获取)
if (CUTIL_EMPTY_STR(pIntf))
{
// Get interface from default gateway
tr143_getDefaultIntfName(pIntf, intfLen);
}
TR143_DEBUG("multi load interface:%s", pIntf);
// 3. 兼容接口路径格式(原逻辑不变:AgileACS→TAUC格式)
CUTIL_STR_STRNCPY(tmpinterface, pIntf, sizeof(tmpinterface));
/*
** The interface delivered by Current AgileACS is not consistent with TAUC.
** The form of AgileACS is standard, But in order to be compatible with
** old software and TAUC, a dot '.' needs to be added at the end,
**
** example Device.IP.Interface.1 (AgileACS/standard) -> Device.IP.Interface.1. (TAUC and old software)
*/
if (!tr143_isAppropriateInterfacePath(tmpinterface, sizeof(tmpinterface)))
{
if (CMM_OK != tr143_changeInterfacePathFormat(tmpinterface, sizeof(tmpinterface)))
{
TR143_ERROR("changeInterfacePathFormat failed.");
CUTIL_STR_STRNCPY(pDiagSt, TR143_EINTERNAL, diagLen);
return FALSE;
}
TR143_DEBUG("interface path is unAppropriate, change to %s", tmpinterface);
}
// 4. 提取接口名和DNS(原逻辑不变:从接口路径获取实际接口名如eth0)
if (CUTIL_NOT_EMPTY_STR(tmpinterface))
{
if (CMM_OK != getIntfNameAndDns(tmpinterface, sizeof(tmpinterface),
pCfg->ifName, sizeof(pCfg->ifName),
dns, sizeof(dns)))
{
TR143_ERROR("getIntfNameAndDns failed.");
CUTIL_STR_STRNCPY(pDiagSt, TR143_EINTERNAL, diagLen);
return FALSE;
}
}
TR143_DEBUG("multi load ifName %s,DNS:%s", pCfg->ifName, dns);
#ifdef INCLUDE_ECONET_TR143_SPEEDUP //Bug 671009 - pppoe拨号下,样机无法使用tr098节点进行tr143测速
CUTIL_STR_STRNCPY(pIntf, tmpinterface, intfLen); // 同步调整后的接口路径
#endif
// 5. 遍历WAN接口,获取IPv4/IPv6地址
while (CMM_OK == (ret = rdp_getNextObjStruct(CMM_UI_TR69, DEV2_ADT_WAN, &stackAdt,
sizeof(DEV2_ADT_WAN_OBJ), &adtWanObj)))
{
if (CUTIL_SAME_STR(adtWanObj.ifName, pCfg->ifName))
{ // 匹配当前接口
// 5.1 处理IPv4地址(原逻辑不变)
if (CUTIL_SAME_STR(adtWanObj.connStatusV4, "Connected"))
{
CUTIL_STR_STRNCPY(pCfg->ipUsed, adtWanObj.connIPv4Address, sizeof(pCfg->ipUsed));
#ifdef INCLUDE_ECONET_TR143_SPEEDUP
CUTIL_STR_STRNCPY(pCfg->wanIP, adtWanObj.connIPv4Address, sizeof(pCfg->wanIP));
CUTIL_STR_STRNCPY(pCfg->gateway, adtWanObj.connIPv4Gateway, sizeof(pCfg->gateway));
CUTIL_STR_STRNCPY(pCfg->mask, adtWanObj.connIPv4SubnetMask, sizeof(pCfg->mask));
pCfg->isADSLType = (CUTIL_SAME_STR(adtWanObj.accessMode, DMVS_ADSL));
#endif
}
// 5.2 新增:处理IPv6地址
if (CUTIL_SAME_STR(adtWanObj.connStatusV6, "Connected"))
{
CUTIL_STR_STRNCPY(pCfg->ipUsedV6, adtWanObj.connIPv6Address, sizeof(pCfg->ipUsedV6));
#ifdef INCLUDE_ECONET_TR143_SPEEDUP
CUTIL_STR_STRNCPY(pCfg->wanIPV6, adtWanObj.connIPv6Address, sizeof(pCfg->wanIPV6));
CUTIL_STR_STRNCPY(pCfg->gatewayV6, adtWanObj.connIPv6Gateway, sizeof(pCfg->gatewayV6));
CUTIL_STR_STRNCPY(pCfg->maskV6, adtWanObj.connIPv6SubnetMask, sizeof(pCfg->maskV6));
#endif
}
}
}
#ifdef INCLUDE_ECONET_TR143_SPEEDUP
// 6. 易展模式(ConfAgent)处理:新增IPv6地址获取
if (CMM_OK != rdp_getObjStruct(CMM_UI_NULL, DEV2_X_TP_EASYMESH, &stackMode,
sizeof(DEV2_X_TP_EASYMESH_OBJ), &easymeshObj)) {
TR143_ERROR("获取易展模式失败");
}
if (CUTIL_SAME_STR(easymeshObj.workMode, "ConfAgent")) {
if (CMM_OK == RDP_WRAP(CMM_UI_INTERNAL, OID_DEV2, rsl_util_getObjFromFullpath(pIntf, OID_DEV2_IP_INTF,
sizeof(DEV2_IP_INTF_OBJ), &ipIntfStack, &ipIntfObj))) {
// 6.1 处理IPv4地址(原逻辑不变)
while (CMM_OK == rdp_getNextObjSubStruct(CMM_UI_NULL, DEV2_IP_INTF_V4ADDR, &ipIntfStack, &ipIntfV4AddrStack,
sizeof(DEV2_IP_INTF_V4ADDR_OBJ), &ipIntfV4AddrObj)) {
if (CUTIL_SAME_STR(ipIntfV4AddrObj.status, "Enabled") &&
CUTIL_NOT_SAME_STR(ipIntfV4AddrObj.IPAddress, "0.0.0.0")) {
CUTIL_STR_STRNCPY(pCfg->ipUsed, ipIntfV4AddrObj.IPAddress, sizeof(pCfg->ipUsed));
CUTIL_STR_STRNCPY(pCfg->wanIP, ipIntfV4AddrObj.IPAddress, sizeof(pCfg->wanIP));
CUTIL_STR_STRNCPY(pCfg->gateway, dns, sizeof(pCfg->gateway));
CUTIL_STR_STRNCPY(pCfg->mask, ipIntfV4AddrObj.subnetMask, sizeof(pCfg->mask));
pCfg->isADSLType = 0;
break;
}
}
// 6.2 新增:处理IPv6地址
while (CMM_OK == rdp_getNextObjSubStruct(CMM_UI_NULL, DEV2_IP_INTF_V6ADDR, &ipIntfStack, &ipIntfV6AddrStack,
sizeof(DEV2_IP_INTF_V6ADDR_OBJ), &ipIntfV6AddrObj)) {
if (CUTIL_SAME_STR(ipIntfV6AddrObj.status, "Enabled") &&
CUTIL_NOT_SAME_STR(ipIntfV6AddrObj.IPAddress, "::")) { // 排除无效IPv6地址
CUTIL_STR_STRNCPY(pCfg->ipUsedV6, ipIntfV6AddrObj.IPAddress, sizeof(pCfg->ipUsedV6));
CUTIL_STR_STRNCPY(pCfg->wanIPV6, ipIntfV6AddrObj.IPAddress, sizeof(pCfg->wanIPV6));
CUTIL_STR_STRNCPY(pCfg->gatewayV6, dns, sizeof(pCfg->gatewayV6));
CUTIL_STR_STRNCPY(pCfg->maskV6, ipIntfV6AddrObj.subnetMask, sizeof(pCfg->maskV6));
pCfg->isADSLType = 0;
break;
}
}
}
}
#endif /* INCLUDE_ECONET_TR143_SPEEDUP */
// 7. 解析URL(调用修改后的parseUrl_multi,支持IPv6)
/* parseUrl will change url ':' to '\0:' */
if (LOAD_PROTO_UNKNOWN == parseUrl_multi(loadURL, pCfg))
{
TR143_ERROR("URL解析失败:%s", loadURL);
CUTIL_STR_STRNCPY(pDiagSt, TR143_EINTERNAL, diagLen);
return FALSE;
}
// 8. 初始化socket地址:区分IPv4/IPv6
if (LOAD_PROTO_HTTP == pCfg->proto)
{
if (pCfg->isIPv6) { // 8.1 新增:IPv6 HTTP初始化
if (!tr143_initSockAddrV6(pCfg->pHost, dns,
pCfg->pPort ? atoi(pCfg->pPort) : DEFAULT_HTTP_PORT,
&(pCfg->dstAddrV6), pCfg->ifName)) {
TR143_ERROR("IPv6 HTTP socket tr143_initSockAddrV6 failed");
CUTIL_STR_STRNCPY(pDiagSt, TR143_ERESOVHOSTFAIL, diagLen);
return FALSE;
}
} else { // 8.2 原逻辑:IPv4 HTTP初始化
if (!tr143_initSockAddrV4(pCfg->pHost, dns,
pCfg->pPort ? atoi(pCfg->pPort) : DEFAULT_HTTP_PORT,
&(pCfg->dstAddr), pCfg->ifName)) {
TR143_ERROR("pCfg->proto = LOAD_PROTO_HTTP, tr143_initSockAddrV4 failed.");
CUTIL_STR_STRNCPY(pDiagSt, TR143_ERESOVHOSTFAIL, diagLen);
return FALSE;
}
}
// 恢复URL中的':'(原逻辑不变:parseUrl_multi会将':'替换为'\0')
/* change url '\0' to ':' */
if (NULL != pCfg->pPort) {
*(pCfg->pPort - 1) = /* see parseUrl_multi() */
}
} else { // FTP协议
if (pCfg->isIPv6) { // 8.3 新增:IPv6 FTP初始化
if (!tr143_initSockAddrV6(pCfg->pHost, dns,
pCfg->pPort ? atoi(pCfg->pPort) : DEFAULT_FTP_CTRL_PORT,
&(pCfg->dstAddrV6), pCfg->ifName)) {
TR143_ERROR("tr143_initSockAddrV6 failed.");
CUTIL_STR_STRNCPY(pDiagSt, TR143_ERESOVHOSTFAIL, diagLen);
return FALSE;
}
} else { // 8.4 原逻辑:IPv4 FTP初始化
if (!tr143_initSockAddrV4(pCfg->pHost, dns,
pCfg->pPort ? atoi(pCfg->pPort) : DEFAULT_FTP_CTRL_PORT,
&(pCfg->dstAddr), pCfg->ifName)) {
TR143_ERROR("tr143_initSockAddrV4 failed.");
CUTIL_STR_STRNCPY(pDiagSt, TR143_ERESOVHOSTFAIL, diagLen);
return FALSE;
}
}
}
return TRUE;
}