feat: sync httpdns sdk/platform updates without large binaries

This commit is contained in:
robin
2026-03-04 17:59:14 +08:00
parent 853897a6f8
commit 532891fad0
700 changed files with 6096 additions and 2712 deletions

View File

@@ -0,0 +1,129 @@
plugins {
id 'com.android.library'
id 'maven-publish'
}
apply from: 'version.gradle'
android {
compileSdk 33
defaultConfig {
minSdkVersion 19
targetSdkVersion 33
versionCode 1
versionName httpdnsDebugVersion
setProperty("archivesBaseName", "new-android-httpdns-$versionName")
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
buildConfigField "String", "VERSION_NAME", "\"${httpdnsDebugVersion}\""
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile("proguard-android.txt"), 'proguard-rules.pro'
}
forTest {
initWith release
debuggable true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-for-test.pro'
}
}
flavorDimensions += "version"
productFlavors {
normal {
}
intl {
}
end2end {
}
}
variantFilter { variant ->
def names = variant.flavors*.name
def type = variant.buildType.name
// To check for a certain build type, use variant.buildType.name == "<buildType>"
if ((names.contains("normal") && type.contains("forTest"))
|| (names.contains("intl") && type.contains("forTest"))
|| (names.contains("end2end") && type.contains("release"))
|| (names.contains("end2end") && type.contains("debug"))
) {
// Gradle ignores any variants that satisfy the conditions above.
setIgnore(true)
}
}
testOptions {
unitTests {
all {
jvmArgs '-noverify'
systemProperty 'robolectric.logging.enable', true
}
}
}
lintOptions {
abortOnError false
}
}
android.libraryVariants.all { variant ->
if (variant.name == "normalRelease") {
def sdkVersion = variant.mergedFlavor.versionName ?: httpdnsDebugVersion
variant.outputs.all { output ->
outputFileName = "new--android-httpdns-v${sdkVersion}.aar"
}
}
}
dependencies {
//noinspection GradleDependency 高版本 jdk和androidx有一些依赖暂时不升级
testEnd2endImplementation "org.robolectric:robolectric:3.8"
//noinspection GradleDependency
testEnd2endImplementation 'junit:junit:4.12'
//noinspection GradleDependency
testEnd2endImplementation 'org.mockito:mockito-core:2.15.0'
testEnd2endImplementation 'com.squareup.okhttp3:mockwebserver:3.9.0'
implementation "com.newsdk.ams:new-android-logger:${loggerVersion}"
implementation "com.newsdk.ams:new-android-crashdefend:${crashDefendVersion}"
implementation "com.newsdk.ams:new-android-ipdetector:${ipdetectorVersion}"
}
ext.getIntlVersion = { version ->
if (version.endsWith("-SNAPSHOT")) {
return version.replace("-SNAPSHOT", "-intl-SNAPSHOT");
} else {
return version + "-intl";
}
}
task copyDependencies {
doLast {
def config = configurations.findByName("normalReleaseRuntimeClasspath")
if (config != null) {
config.resolvedConfiguration.resolvedArtifacts.each { artifact ->
def file = artifact.file
if (file.name.contains("new-android")) {
copy {
from file
into 'build/outputs/dependencies'
}
}
}
}
}
}

View File

@@ -0,0 +1,50 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/ryan/Downloads/adt-bundle-mac-x86_64-20131030/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-optimizationpasses 3
-dontoptimize
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
-overloadaggressively
#-allowaccessmodification
-useuniqueclassmembernames
-keeppackagenames com.newsdk.sdk.android.httpdns
-keep class com.newsdk.sdk.android.httpdns.HttpDns{*;}
-keep class com.newsdk.sdk.android.httpdns.HttpDnsService{*;}
-keep class com.newsdk.sdk.android.httpdns.SyncService{*;}
-keep class com.newsdk.sdk.android.httpdns.RequestIpType{*;}
-keep class com.newsdk.sdk.android.httpdns.net64.Net64Service{*;}
-keep class com.newsdk.sdk.android.httpdns.DegradationFilter{*;}
-keep class com.newsdk.sdk.android.httpdns.ranking.IPRankingBean{*;}
-keep class com.newsdk.sdk.android.httpdns.ILogger{*;}
-keepclasseswithmembers class com.newsdk.sdk.android.httpdns.log.HttpDnsLog {
public static *** setLogger(***);
public static *** removeLogger(***);
public static *** enable(***);
}
-keep class com.newsdk.sdk.android.httpdns.HTTPDNSResult{*;}
-keep class com.newsdk.sdk.android.httpdns.ApiForTest{*;}
-keep class com.newsdk.sdk.android.httpdns.test.** {*;}
-keep class com.newsdk.sdk.android.httpdns.resolve.ResolveHostResponse{*;}
-keep class com.newsdk.sdk.android.httpdns.utils.CommonUtil{
public <methods>;
public <fields>;
}

View File

@@ -0,0 +1,70 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/ryan/Downloads/adt-bundle-mac-x86_64-20131030/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-optimizationpasses 3
-dontoptimize
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
-overloadaggressively
#-allowaccessmodification
-useuniqueclassmembernames
-dontwarn com.newsdk.sdk.android.httpdns.net.HttpDnsNetworkDetector
-keeppackagenames com.newsdk.sdk.android.httpdns
-flattenpackagehierarchy com.newsdk.sdk.android.httpdns
-keep class com.newsdk.sdk.android.httpdns.HttpDns{*;}
-keep interface com.newsdk.sdk.android.httpdns.HttpDnsService{*;}
-keep class com.newsdk.sdk.android.httpdns.impl.ErrorImpl{*;}
-keep interface com.newsdk.sdk.android.httpdns.SyncService{*;}
-keep class com.newsdk.sdk.android.httpdns.InitConfig{*;}
-keep class com.newsdk.sdk.android.httpdns.InitConfig$Builder{*;}
-keep class com.newsdk.sdk.android.httpdns.RequestIpType{*;}
-keep interface com.newsdk.sdk.android.httpdns.DegradationFilter{*;}
-keep interface com.newsdk.sdk.android.httpdns.NotUseHttpDnsFilter{*;}
-keep interface com.newsdk.sdk.android.httpdns.HttpDnsCallback{*;}
-keep class com.newsdk.sdk.android.httpdns.ranking.IPRankingBean{*;}
-keep interface com.newsdk.sdk.android.httpdns.ILogger{*;}
-keep interface com.newsdk.sdk.android.httpdns.CacheTtlChanger{*;}
-keep class com.newsdk.sdk.android.httpdns.NetType{*;}
-keepclasseswithmembers class com.newsdk.sdk.android.httpdns.log.HttpDnsLog {
public static *** setLogger(***);
public static *** removeLogger(***);
public static *** enable(***);
}
-keep class com.newsdk.sdk.android.httpdns.HTTPDNSResult{*;}
-keepclasseswithmembers class com.newsdk.sdk.android.httpdns.HttpDnsSettings {
public static *** setDailyReport(***);
public static *** setNetworkChecker(***);
}
-keep class com.newsdk.sdk.android.httpdns.net.HttpDnsNetworkDetector {
public <methods>;
public <fields>;
}
-keep class com.newsdk.sdk.android.httpdns.network.**{*;}
-keep interface com.newsdk.sdk.android.httpdns.HttpDnsSettings$NetworkChecker{*;}
-keep interface com.newsdk.sdk.android.httpdns.HttpDnsSettings$NetworkDetector{*;}
-keep class com.newsdk.sdk.android.httpdns.utils.CommonUtil{
public <methods>;
public <fields>;
}
-keep enum com.newsdk.sdk.android.httpdns.Region {*;}
-keep class com.newsdk.sdk.android.httpdns.exception.InitException{*;}

View File

@@ -0,0 +1,78 @@
package com.newsdk.sdk.android.httpdns;
import com.newsdk.sdk.android.httpdns.ranking.IPRankingTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
/**
* @author zonglin.nzl
* @date 2020/10/15
*/
public interface ApiForTest {
/**
* 鎸囧畾鍒濆鏈嶅姟ip
* @param region
* @param ips
* @param ports
* @param ipv6s
* @param v6Ports
*/
void setInitServer(String region, String[] ips, int[] ports, String[] ipv6s, int[] v6Ports);
/**
* 鎸囧畾httpdns浣跨敤鐨勭嚎绋嬫睜
* @param scheduledExecutorService
*/
void setThread(ScheduledExecutorService scheduledExecutorService);
/**
* 鎸囧畾 娴嬭瘯浣跨敤鐨剆ocket factory
* @param speedTestSocketFactory
*/
void setSocketFactory(IPRankingTask.SpeedTestSocketFactory speedTestSocketFactory);
/**
* 鎸囧畾璋冨害鎺ュ彛鐨勮皟鐢ㄩ棿姝囷紝閬垮厤姝e父鐨勯棿姝囪繃闀挎棤娉曟祴璇?
* @param timeInterval
*/
void setUpdateServerTimeInterval(int timeInterval);
/**
* 鎸囧畾 sniff妯″紡鐨?璇锋眰闂存瓏
* @param timeInterval
*/
void setSniffTimeInterval(int timeInterval);
/**
* 鑾峰彇httpdns鐨勭嚎绋嬫睜鐢ㄤ簬鎺у埗寮傚父鎿嶄綔
*
* @return
*/
ExecutorService getWorker();
/**
* 璁剧疆鍏滃簳鐨勮皟搴p
*
* @param defaultServerIps
* @param ports
*/
void setDefaultUpdateServer(String[] defaultServerIps, int[] ports);
/**
* 璁剧疆ipv6鐨勫厹搴曡皟搴P
*
* @param defaultServerIps
* @param ports
*/
void setDefaultUpdateServerIpv6(String[] defaultServerIps, int[] ports);
/**
* 璁剧疆娴嬭瘯鐢ㄧ殑缃戠粶detector
*
* @param networkDetector
*/
void setNetworkDetector(HttpDnsSettings.NetworkDetector networkDetector);
}

View File

@@ -0,0 +1,12 @@
package com.newsdk.sdk.android.httpdns;
/**
* 娴嬭瘯鐢ㄧ殑鍒濆鍖栨帴鍙?
* @author zonglin.nzl
* @date 1/14/22
*/
public interface BeforeHttpDnsServiceInit {
void beforeInit(HttpDnsService service);
}

View File

@@ -0,0 +1,86 @@
package com.newsdk.sdk.android.httpdns;
import android.content.Context;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsInstanceHolder;
import com.newsdk.sdk.android.httpdns.impl.InstanceCreator;
import com.newsdk.sdk.android.httpdns.net.NetworkStateManager;
import com.newsdk.sdk.android.httpdns.network.HttpDnsAdapterOptions;
import com.newsdk.sdk.android.httpdns.network.HttpDnsHttpAdapter;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
/**
* Httpdns瀹炰緥绠
*/
public class HttpDns {
private static HttpDnsInstanceHolder sHolder = new HttpDnsInstanceHolder(new InstanceCreator());
/**
* 鑾峰彇HttpDnsService瀵硅薄
*
* @param applicationContext 褰撳墠APP鐨凜ontext
* @param accountID HttpDns鎺у埗鍙板垎閰嶇殑AccountID
* @return
*/
public synchronized static HttpDnsService getService(final Context applicationContext, final String accountID) {
return sHolder.get(applicationContext, accountID, null);
}
/**
* 鑾峰彇HttpDnsService瀵硅薄锛屽苟鍚敤閴存潈鍔熻兘
*
* @param applicationContext 褰撳墠APP鐨凜ontext
* @param accountID HttpDns鎺у埗鍙板垎閰嶇殑AccountID
* @param secretKey 鐢ㄦ埛閴存潈绉侀挜
* @return
*/
public synchronized static HttpDnsService getService(final Context applicationContext, final String accountID, final String secretKey) {
return sHolder.get(applicationContext, accountID, secretKey);
}
/**
* 鑾峰彇HttpDnsService瀵硅薄锛屽垵濮嬪寲鏃朵笉浼犲叆浠讳綍鍙傛暟锛岄潬缁熶竴鎺ュ叆鏈嶅姟鑾峰彇鐩稿叧鍙傛暟
*
* @param applicationContext 褰撳墠APP鐨凜ontext
* @return
*/
public synchronized static HttpDnsService getService(final Context applicationContext) {
return sHolder.get(applicationContext, CommonUtil.getAccountId(applicationContext), CommonUtil.getSecretKey(applicationContext));
}
/**
* 鍚敤鎴栬€呯鐢╤ttpdns锛岀悊璁轰笂杩欎釜鏄唴閮ㄦ帴鍙紝涓嶇粰澶栭儴浣跨敤鐨?
* 浣嗘槸宸茬粡瀵瑰鏆撮湶锛屾墍浠ヤ繚鐣?
*
* @param enabled
* @deprecated 鍚敤绂佺敤搴旇璋冪敤瀹炰緥鐨勬柟娉曪紝鑰屼笉鏄帶鍒跺叏閮ㄥ疄渚嬬殑鏂规硶
*/
@Deprecated
public synchronized static void switchDnsService(boolean enabled) {
// do nothing as deprecated
}
/**
* 閲嶇疆httpdns锛岀敤浜庝竴浜涙ā鎷熷簲鐢ㄩ噸鍚殑鍦烘櫙
*/
public static void resetInstance() {
sHolder = new HttpDnsInstanceHolder(new InstanceCreator());
NetworkStateManager.getInstance().reset();
}
/**
* Build official IP-direct + empty-SNI adapter.
*/
public static HttpDnsHttpAdapter buildHttpClientAdapter(HttpDnsService service) {
return new HttpDnsHttpAdapter(service);
}
/**
* Build official IP-direct + empty-SNI adapter with options.
*/
public static HttpDnsHttpAdapter buildHttpClientAdapter(HttpDnsService service, HttpDnsAdapterOptions options) {
return new HttpDnsHttpAdapter(service, options);
}
}

View File

@@ -0,0 +1,35 @@
package com.newsdk.sdk.android.httpdns;
import java.util.HashMap;
/**
* 澧炲姞鍒濆鍖栭€昏緫鐨勫崟渚?
* 鐢ㄤ簬鍦ㄦ祴璇曠敤鐨刪ttpdns瀹炰緥涓鍔犳祴璇曢渶瑕佺殑鍒濆鍖栭€昏緫
* @author zonglin.nzl
* @date 1/14/22
*/
public class InitManager {
private static class Holder {
private static final InitManager instance = new InitManager();
}
public static InitManager getInstance() {
return Holder.instance;
}
private InitManager() {
}
private HashMap<String, BeforeHttpDnsServiceInit> initThings = new HashMap<>();
public void add(String accountId, BeforeHttpDnsServiceInit beforeHttpDnsServiceInit) {
initThings.put(accountId, beforeHttpDnsServiceInit);
}
public BeforeHttpDnsServiceInit getAndRemove(String accountId) {
return initThings.remove(accountId);
}
}

View File

@@ -0,0 +1,87 @@
package com.newsdk.sdk.android.httpdns.impl;
import android.content.Context;
import com.newsdk.sdk.android.httpdns.ApiForTest;
import com.newsdk.sdk.android.httpdns.BeforeHttpDnsServiceInit;
import com.newsdk.sdk.android.httpdns.HttpDnsSettings;
import com.newsdk.sdk.android.httpdns.InitManager;
import com.newsdk.sdk.android.httpdns.ranking.IPRankingTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
/**
* 娴嬭瘯鏃?浣跨敤鐨刪ttpdns 瀹炰緥
* 澧炲姞浜嗕竴浜涚敤浜庢祴璇曠殑api鍜屾満鍒?
* @author zonglin.nzl
* @date 2020/10/16
*/
public class HttpDnsServiceTestImpl extends HttpDnsServiceImpl implements ApiForTest {
public HttpDnsServiceTestImpl(Context context, String accountId, String secret) {
super(context, accountId, secret);
}
@Override
protected void beforeInit() {
super.beforeInit();
// 閫氳繃InitManager 鍦╤ttpdns鍒濆鍖栦箣鍓?杩涜涓€浜涙祴璇曢渶瑕佸墠缃伐浣?
BeforeHttpDnsServiceInit init = InitManager.getInstance().getAndRemove(mHttpDnsConfig.getAccountId());
if (init != null) {
init.beforeInit(this);
}
}
@Override
protected void initCrashDefend(Context context, HttpDnsConfig config) {
// do nothing for test
mHttpDnsConfig.crashDefend(false);
}
@Override
public void setInitServer(String region, String[] ips, int[] ports, String[] ipv6s, int[] v6Ports) {
mHttpDnsConfig.setInitServers(region, ips, ports, ipv6s, v6Ports);
}
@Override
public void setThread(ScheduledExecutorService scheduledExecutorService) {
mHttpDnsConfig.setWorker(scheduledExecutorService);
}
@Override
public void setSocketFactory(IPRankingTask.SpeedTestSocketFactory speedTestSocketFactory) {
mIpIPRankingService.setSocketFactory(speedTestSocketFactory);
}
@Override
public void setUpdateServerTimeInterval(int timeInterval) {
mScheduleService.setTimeInterval(timeInterval);
}
@Override
public void setSniffTimeInterval(int timeInterval) {
mRequestHandler.setSniffTimeInterval(timeInterval);
}
@Override
public ExecutorService getWorker() {
return mHttpDnsConfig.mWorker;
}
@Override
public void setDefaultUpdateServer(String[] defaultServerIps, int[] ports) {
mHttpDnsConfig.setDefaultUpdateServer(defaultServerIps, ports);
}
@Override
public void setDefaultUpdateServerIpv6(String[] defaultServerIps, int[] ports) {
mHttpDnsConfig.setDefaultUpdateServerIpv6(defaultServerIps, ports);
}
@Override
public void setNetworkDetector(HttpDnsSettings.NetworkDetector networkDetector) {
mHttpDnsConfig.setNetworkDetector(networkDetector);
}
}

View File

@@ -0,0 +1,18 @@
package com.newsdk.sdk.android.httpdns.impl;
import android.content.Context;
import com.newsdk.sdk.android.httpdns.HttpDnsService;
/**
* 鏀逛负浣跨敤娴嬭瘯瀹炰緥
* @author zonglin.nzl
* @date 2020/12/4
*/
public class InstanceCreator implements HttpDnsCreator {
@Override
public HttpDnsService create(Context context, String accountId, String secretKey) {
return new HttpDnsServiceTestImpl(context.getApplicationContext(), accountId, secretKey);
}
}

View File

@@ -0,0 +1,104 @@
package com.newsdk.sdk.android.httpdns;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsInstanceHolder;
import com.newsdk.sdk.android.httpdns.impl.InstanceCreator;
import com.newsdk.sdk.android.httpdns.network.HttpDnsAdapterOptions;
import com.newsdk.sdk.android.httpdns.network.HttpDnsHttpAdapter;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
import android.content.Context;
/**
* Httpdns瀹炰緥绠
*/
public class HttpDns {
private static final HttpDnsInstanceHolder HOLDER = new HttpDnsInstanceHolder(
new InstanceCreator());
/**
* 鑾峰彇HttpDnsService瀵硅薄
* @param accountId HttpDns鎺у埗鍙板垎閰嶇殑AccountID
* @return
*/
public synchronized static HttpDnsService getService(final String accountId) {
return HOLDER.get(null, accountId, null);
}
/**
* 鑾峰彇HttpDnsService瀵硅薄
* 璇ユ柟娉曞凡寮冪敤锛屽缓璁娇鐢▄@link HttpDns#getService(String)}鏂规硶
* @param applicationContext 褰撳墠APP鐨凜ontext
* @param accountID HttpDns鎺у埗鍙板垎閰嶇殑AccountID
* @return
*/
@Deprecated
public synchronized static HttpDnsService getService(final Context applicationContext,
final String accountID) {
return HOLDER.get(applicationContext, accountID, null);
}
/**
* 鑾峰彇HttpDnsService瀵硅薄锛屽苟鍚敤閴存潈鍔熻兘
* 璇ユ柟娉曞凡寮冪敤锛屽缓璁娇鐢▄@link HttpDns#getService(String)}鏂规硶
* @param applicationContext 褰撳墠APP鐨凜ontext
* @param accountID HttpDns鎺у埗鍙板垎閰嶇殑AccountID
* @param secretKey 鐢ㄦ埛閴存潈绉侀挜
* @return
*/
@Deprecated
public synchronized static HttpDnsService getService(final Context applicationContext,
final String accountID,
final String secretKey) {
return HOLDER.get(applicationContext, accountID, secretKey);
}
/**
* 鑾峰彇HttpDnsService瀵硅薄锛屽垵濮嬪寲鏃朵笉浼犲叆浠讳綍鍙傛暟锛岄潬缁熶竴鎺ュ叆鏈嶅姟鑾峰彇鐩稿叧鍙傛暟
* 璇ユ柟娉曞凡寮冪敤锛屽缓璁娇鐢▄@link HttpDns#getService(String)}鏂规硶
* @param applicationContext 褰撳墠APP鐨凜ontext
* @return
*/
@Deprecated
public synchronized static HttpDnsService getService(final Context applicationContext) {
return HOLDER.get(applicationContext, CommonUtil.getAccountId(applicationContext),
CommonUtil.getSecretKey(applicationContext));
}
/**
* 鍒濆鍖栨柟娉曪紝璇ユ柟娉曚富瑕佹槸淇濆瓨{@link InitConfig}锛屼笉浼氱湡姝h繘琛屽垵濮嬪寲銆傜湡姝e垵濮嬪寲鏄湪{@link HttpDns#getService(Context, String, String)}涓?
* 杩欎箞瀹炵幇涓昏鏄负浜嗗吋瀹箋@link InitConfig.Builder#buildFor(String)}鏂规硶锛屾柊瀹㈡埛浣跨敤璇ユ柟娉曞拰鏃х殑鏂规硶鍔熻兘涓€鑷?
* @param accountId HttpDns鎺у埗鍙板垎閰嶇殑AccountID
* @param config {@link InitConfig}
*/
public static void init(String accountId, InitConfig config) {
InitConfig.addConfig(accountId, config);
}
/**
* Build official IP-direct + empty-SNI adapter.
*/
public static HttpDnsHttpAdapter buildHttpClientAdapter(HttpDnsService service) {
return new HttpDnsHttpAdapter(service);
}
/**
* Build official IP-direct + empty-SNI adapter with options.
*/
public static HttpDnsHttpAdapter buildHttpClientAdapter(HttpDnsService service, HttpDnsAdapterOptions options) {
return new HttpDnsHttpAdapter(service, options);
}
/**
* 鍚敤鎴栬€呯鐢╤ttpdns锛岀悊璁轰笂杩欎釜鏄唴閮ㄦ帴鍙紝涓嶇粰澶栭儴浣跨敤鐨?
* 浣嗘槸宸茬粡瀵瑰鏆撮湶锛屾墍浠ヤ繚鐣?
*
* @param enabled
* @deprecated 鍚敤绂佺敤搴旇璋冪敤瀹炰緥鐨勬柟娉曪紝鑰屼笉鏄帶鍒跺叏閮ㄥ疄渚嬬殑鏂规硶
*/
@Deprecated
public synchronized static void switchDnsService(boolean enabled) {
// do nothing as deprecated
}
}

View File

@@ -0,0 +1,13 @@
package com.newsdk.sdk.android.httpdns.impl;
import com.newsdk.sdk.android.httpdns.HttpDnsService;
import android.content.Context;
public class InstanceCreator implements HttpDnsCreator {
@Override
public HttpDnsService create(Context context, String accountId, String secretKey) {
return new IntlImpl(context, accountId, secretKey);
}
}

View File

@@ -0,0 +1,10 @@
package com.newsdk.sdk.android.httpdns.impl;
import android.content.Context;
public class IntlImpl extends HttpDnsServiceImpl {
public IntlImpl(Context context, String accountId, String secret) {
super(context, accountId, secret);
}
}

View File

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.newsdk.sdk.android.httpdns">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@@ -0,0 +1,19 @@
package com.newsdk.sdk.android.httpdns;
/**
* 淇敼ttl鏃堕暱鐨勬帴鍙?
* 鐢ㄤ簬鐢ㄦ埛瀹氬埗ttl锛屼互鎺у埗缂撳瓨鐨勬椂闀?
*/
public interface CacheTtlChanger {
/**
* 鏍规嵁 鍩熷悕 ip绫诲瀷 鍜?鏈嶅姟鐨則tl 杩斿洖 瀹氬埗鐨則tl
*
* @param host 鍩熷悕
* @param type ip绫诲瀷
* @param ttl 鏈嶅姟涓嬪彂鐨則tl 鍗曚綅绉?
* @return 瀹氬埗鐨則tl 鍗曚綅绉?
*/
int changeCacheTtl(String host, RequestIpType type, int ttl);
}

View File

@@ -0,0 +1,14 @@
package com.newsdk.sdk.android.httpdns;
/**
* 闄嶇骇鍒ゆ柇寮€鍏虫帴鍙?
*/
@Deprecated
public interface DegradationFilter {
/**
* 鏄惁搴旇涓嶄娇鐢╤ttpdns
*
*/
boolean shouldDegradeHttpDNS(String hostName);
}

View File

@@ -0,0 +1,151 @@
package com.newsdk.sdk.android.httpdns;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.cache.HostRecord;
import com.newsdk.sdk.android.httpdns.utils.Constants;
import java.util.Arrays;
import java.util.List;
/**
* sdns鐨勮В鏋愮粨鏋?
*/
public class HTTPDNSResult {
String host;
String[] ips;
String[] ipv6s;
String extra;
long queryTime;
int ttl;
boolean fromDB;
boolean fromLocalDns;
public HTTPDNSResult(String host) {
this.host = host;
this.ips = Constants.NO_IPS;
this.ipv6s = Constants.NO_IPS;
this.extra = "";
queryTime = 0;
ttl = 0;
fromDB = false;
fromLocalDns = false;
}
public HTTPDNSResult(String host, String[] ips, String[] ipv6s, String extra, boolean expired, boolean isFromDB) {
this.host = host;
this.ips = ips;
this.ipv6s = ipv6s;
this.extra = extra;
this.queryTime = System.currentTimeMillis();
this.ttl = 60;
this.fromDB = isFromDB;
fromLocalDns = false;
}
public HTTPDNSResult (String host, String[] ips, String[] ipv6s, String extra, boolean expired, boolean isFromDB, boolean isFromLocalDns) {
this(host, ips, ipv6s, extra, expired, isFromDB);
fromLocalDns = isFromLocalDns;
}
public static HTTPDNSResult empty(String host) {
return new HTTPDNSResult(host, new String[0], new String[0], "", false, false);
}
public void update(HostRecord record) {
if (record.getHost().equals(host)) {
if (record.getType() == RequestIpType.v4.ordinal()) {
ips = record.getIps();
} else if (record.getType() == RequestIpType.v6.ordinal()) {
ipv6s = record.getIps();
}
extra = TextUtils.isEmpty(record.getExtra()) ? "" : record.getExtra();
queryTime = record.getQueryTime();
ttl = record.getTtl();
fromDB = record.isFromDB();
}
}
public void update(List<HostRecord> records) {
String extra = null;
long queryTime = System.currentTimeMillis();
int ttl = Integer.MAX_VALUE;
boolean fromDB = false;
for (HostRecord record : records) {
if (record.getHost().equals(host)) {
if (record.getType() == RequestIpType.v4.ordinal()) {
ips = record.getIps();
} else if (record.getType() == RequestIpType.v6.ordinal()) {
ipv6s = record.getIps();
}
if (record.getExtra() != null && !record.getExtra().isEmpty()) {
extra = record.getExtra();
}
if (queryTime > record.getQueryTime()) {
queryTime = record.getQueryTime();
}
if (ttl > record.getTtl()) {
ttl = record.getTtl();
}
fromDB |= record.isFromDB();
}
}
this.extra = TextUtils.isEmpty(extra) ? "" : extra;
this.queryTime = queryTime;
this.ttl = ttl;
this.fromDB = fromDB;
}
@Override
public String toString() {
String sb = "host:"
+ host
+ ", ips:"
+ Arrays.toString(ips)
+ ", ipv6s:"
+ Arrays.toString(ipv6s)
+ ", extras:"
+ extra
+ ", expired:"
+ isExpired()
+ ", fromDB:"
+ fromDB
+ ", from Local Dns:"
+ fromLocalDns;
return sb;
}
public String getHost() {
return host;
}
public String[] getIps() {
return ips;
}
public String[] getIpv6s() {
return ipv6s;
}
public String getExtras() {
return extra;
}
public int getTtl() {
return ttl;
}
public boolean isExpired() {
return !fromLocalDns && Math.abs(System.currentTimeMillis() - queryTime) > ttl * 1000L;
}
public boolean isFromDB() {
return fromDB;
}
public boolean isFromLocalDns() {
return fromLocalDns;
}
}

View File

@@ -0,0 +1,62 @@
package com.newsdk.sdk.android.httpdns;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.cache.HostRecord;
import java.util.List;
/**
* 瀵硅В鏋愮粨鏋滆繘琛屽皝瑁咃紝鐢ㄤ簬鍙娴嬫暟鎹殑涓€浜涜В鏋愭暟鎹惡甯︼紝涓嶅澶栭€忓嚭
*/
public class HTTPDNSResultWrapper {
private final HTTPDNSResult mHTTPDNSResult;
private String mServerIp;
public HTTPDNSResultWrapper(String host) {
mHTTPDNSResult = new HTTPDNSResult(host);
}
public HTTPDNSResult getHTTPDNSResult() {
return mHTTPDNSResult;
}
public void update(HostRecord record) {
mHTTPDNSResult.update(record);
mServerIp = record.getServerIp();
}
public void update(List<HostRecord> records) {
mHTTPDNSResult.update(records);
for (HostRecord record : records) {
if (record.getHost().equals(mHTTPDNSResult.getHost())) {
if (!TextUtils.isEmpty(record.getServerIp())) {
mServerIp = record.getServerIp();
}
}
}
}
public boolean isExpired() {
return mHTTPDNSResult.isExpired();
}
public String[] getIps() {
return mHTTPDNSResult.getIps();
}
public String[] getIpv6s() {
return mHTTPDNSResult.getIpv6s();
}
public String getServerIp() {
return mServerIp;
}
@Override
public String toString() {
return mHTTPDNSResult.toString();
}
}

View File

@@ -0,0 +1,6 @@
package com.newsdk.sdk.android.httpdns;
public interface HttpDnsCallback {
void onHttpDnsCompleted(HTTPDNSResult result);
}

View File

@@ -0,0 +1,316 @@
package com.newsdk.sdk.android.httpdns;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* HttpDns鏈嶅姟鎺ュ彛
*/
public interface HttpDnsService {
/**
* 璁剧疆棰勮В鏋愬煙鍚嶅垪琛紝榛樿瑙瀽ipv4
*
* @param hostList 棰勮В鏋愮殑host鍩熷悕鍒楄〃
*/
void setPreResolveHosts(List<String> hostList);
/**
* 璁剧疆棰勮В鏋愬煙鍚嶅垪琛ㄥ拰瑙瀽鐨刬p绫诲瀷
*
* @param hostList 棰勮В鏋愮殑host鍒楄〃
* @param requestIpType {@link RequestIpType} 缃戠粶鏍堢被鍨嬶紝v4,v6,both,auto(鏍规嵁褰撳墠璁惧鎵€杩炵殑缃戠粶鑷姩鍒ゆ柇缃戠粶鏍?
*/
void setPreResolveHosts(List<String> hostList, RequestIpType requestIpType);
/**
* 寮傛瑙f瀽鎺ュ彛, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
*
* @param host 濡倃emo.cloudxdr.com
* @return 杩斿洖ip, 濡傛灉娌″緱鍒拌В鏋愮粨鏋? 鍒欒繑鍥瀗ull
* @deprecated 璇ユ帴鍙e凡搴熷純锛屽悗缁増鏈彲鑳戒細琚垹闄わ紝璇蜂娇鐢▄@link #getIPv4ForHostAsync(String)}
*/
@Deprecated
String getIpByHostAsync(String host);
/**
* 寮傛瑙瀽鎺ュ彛锛屽彧鏌ヨv4鍦板潃锛岄鍏堟煡璇㈢紦瀛? 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @return 杩斿洖v4鍦板潃
*/
@Deprecated
String getIPv4ForHostAsync(String host);
/**
* 寮傛瑙f瀽鎺ュ彛, 鑾峰彇ipv4鍒楄〃
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @return 杩斿洖v4鍦板潃鐨凷tring 鏁扮粍, 濡傛灉娌″緱鍒拌В鏋愮粨鏋? 鍒橲tring 鏁扮粍鐨勯暱搴︿负0
* @deprecated 璇ユ帴鍙e凡搴熷純锛屽悗缁増鏈彲鑳戒細琚垹闄わ紝璇蜂娇鐢▄@link #getIPv4ListForHostAsync(String)}
*/
@Deprecated
String[] getIpsByHostAsync(String host);
/**
* 寮傛瑙f瀽鎺ュ彛, 鑾峰彇ipv4鍒楄〃
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @return 杩斿洖v4鍦板潃鍒楄〃
*/
@Deprecated
String[] getIPv4ListForHostAsync(String host);
/**
* 寮傛瑙瀽鎺ュ彛锛岃幏鍙栧崟涓猧pv6, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @return 杩斿洖v6鍦板潃
* @deprecated 璇ユ帴鍙e凡搴熷純锛屽悗缁増鏈彲鑳戒細琚垹闄わ紝璇蜂娇鐢▄@link #getIPv6ForHostAsync(String)}
*/
@Deprecated
String getIPv6ByHostAsync(String host);
/**
* 寮傛瑙瀽鎺ュ彛锛岃幏鍙栧崟涓猧pv6, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @return 杩斿洖v6鍦板潃
*/
@Deprecated
String getIPv6ForHostAsync(String host);
/**
* 寮傛瑙瀽鎺ュ彛锛岃幏鍙杋pv6鍒楄〃, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @return 杩斿洖v6鍦板潃鐨凷tring 鏁扮粍, 濡傛灉娌″緱鍒拌В鏋愮粨鏋? 鍒橲tring 鏁扮粍鐨勯暱搴︿负0
* @deprecated 璇ユ帴鍙e凡搴熷純锛屽悗缁増鏈彲鑳戒細琚垹闄わ紝璇蜂娇鐢▄@link #getIPv6ListForHostASync(String)}
*/
@Deprecated
String[] getIPv6sByHostAsync(String host);
/**
* 寮傛瑙瀽鎺ュ彛锛岃幏鍙杋pv6鍒楄〃, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @return 杩斿洖v6鍦板潃鐨凷tring 鏁扮粍, 濡傛灉娌″緱鍒拌В鏋愮粨鏋? 鍒橲tring 鏁扮粍鐨勯暱搴︿负0
*/
@Deprecated
String[] getIPv6ListForHostASync(String host);
/**
* 寮傛瑙瀽鎺ュ彛锛岃幏鍙杋pv4ipv6鍒楄〃
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @return {@link HTTPDNSResult}
* @deprecated 璇ユ帴鍙e凡搴熷純锛屽悗缁増鏈彲鑳戒細琚垹闄わ紝璇蜂娇鐢▄@link #getHttpDnsResultForHostAsync(String)}
*/
@Deprecated
HTTPDNSResult getAllByHostAsync(String host);
/**
* 寮傛瑙瀽鎺ュ彛锛岃幏鍙杋pv4 + ipv6鍒楄〃, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @return {@link HTTPDNSResult}
*/
@Deprecated
HTTPDNSResult getHttpDnsResultForHostAsync(String host);
/**
* 寮傛瑙瀽鎺ュ彛锛岃幏鍙杋pv4 + ipv6鍒楄〃, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
* 鏀寔 鎸囧畾瑙瀽IP绫诲瀷
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @param type {@link RequestIpType} 缃戠粶鏍堢被鍨嬶紝v4,v6,both,auto(鏍规嵁褰撳墠璁惧鎵€杩炵殑缃戠粶鑷姩鍒ゆ柇缃戠粶鏍?
* @return {@link HTTPDNSResult}
* @deprecated 璇ユ帴鍙e凡搴熷純锛屽悗缁増鏈彲鑳戒細琚垹闄わ紝璇蜂娇鐢▄@link #getHttpDnsResultForHostAsync(String, RequestIpType)}
*/
@Deprecated
HTTPDNSResult getIpsByHostAsync(String host, RequestIpType type);
/**
* 寮傛瑙瀽鎺ュ彛锛岃幏鍙杋pv4 + ipv6鍒楄〃, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
* 鏀寔 鎸囧畾瑙瀽IP绫诲瀷
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @param type {@link RequestIpType} 缃戠粶鏍堢被鍨嬶紝v4,v6,both,auto(鏍规嵁褰撳墠璁惧鎵€杩炵殑缃戠粶鑷姩鍒ゆ柇缃戠粶鏍?
* @return {@link HTTPDNSResult}
*/
@Deprecated
HTTPDNSResult getHttpDnsResultForHostAsync(String host, RequestIpType type);
/***
* 鏍℃App绛惧悕鏃堕棿
* @param time time涓篹poch鏃堕棿鎴筹紝1970骞?鏈?鏃ヤ互鏉ョ殑绉掓暟
*/
void setAuthCurrentTime(long time);
/**
* 鑾峰彇浼氳瘽id
*
* @return sid
*/
String getSessionId();
//浠ヤ笅閽堝SDNS
/**
* 寮傛瑙f瀽鎺ュ彛, 鑾峰彇ipv4 + ipv6 鍒楄〃,棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
* 鏀寔閰嶇疆sdns鍙傛暟
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @return {@link HTTPDNSResult}
* @deprecated 璇ユ帴鍙e凡搴熷純锛屽悗缁増鏈彲鑳戒細琚垹闄わ紝璇蜂娇鐢▄@link #getHttpDnsResultForHostAsync(String, Map, String)}
*/
@Deprecated
HTTPDNSResult getIpsByHostAsync(String host, Map<String, String> params, String cacheKey);
/**
* 寮傛瑙f瀽鎺ュ彛, 鑾峰彇ipv4 + ipv6鍒楄〃, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
* 鏀寔閰嶇疆sdns鍙傛暟
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @param params
* @param cacheKey
* @return {@link HTTPDNSResult}
*/
@Deprecated
HTTPDNSResult getHttpDnsResultForHostAsync(String host, Map<String, String> params,
String cacheKey);
/**
* 寮傛瑙f瀽鎺ュ彛, 鑾峰彇ipv4 + ipv6鍒楄〃, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
* 鏀寔閰嶇疆sdns鍙傛暟
* 鏀寔鎸囧畾瑙f瀽绫诲瀷
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @param type {@link RequestIpType} 缃戠粶鏍堢被鍨嬶紝v4,v6,both,auto(鏍规嵁褰撳墠璁惧鎵€杩炵殑缃戠粶鑷姩鍒ゆ柇缃戠粶鏍?
* @param params
* @param cacheKey
* @return {@link HTTPDNSResult}
* @deprecated 璇ユ帴鍙e凡搴熷純锛屽悗缁増鏈彲鑳戒細琚垹闄わ紝璇蜂娇鐢▄@link #getHttpDnsResultForHostAsync(String, RequestIpType,
* Map, String)}
*/
@Deprecated
HTTPDNSResult getIpsByHostAsync(String host, RequestIpType type, Map<String, String> params,
String cacheKey);
/**
* 寮傛瑙f瀽鎺ュ彛, 鑾峰彇ipv4 + ipv6鍒楄〃, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
* 鏀寔閰嶇疆sdns鍙傛暟
* 鏀寔鎸囧畾瑙f瀽绫诲瀷
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @param type {@link RequestIpType} 缃戠粶鏍堢被鍨嬶紝v4,v6,both,auto(鏍规嵁褰撳墠璁惧鎵€杩炵殑缃戠粶鑷姩鍒ゆ柇缃戠粶鏍?
* @param params 鑷畾涔夎В鏋愬弬鏁?
* @param cacheKey 缂撳瓨鐨刱ey
* @return {@link HTTPDNSResult}
*/
@Deprecated
HTTPDNSResult getHttpDnsResultForHostAsync(String host, RequestIpType type, Map<String,
String> params, String cacheKey);
/**
* 鍚屾瑙f瀽鎺ュ彛锛屾敮鎸佹寚瀹氳В鏋愮被鍨?
* 鏀寔閰嶇疆sdns鍙傛暟
* 闇€瑕佹敞鎰忕殑鍦版柟:
* 1. 璇ユ柟娉曞繀椤诲湪瀛愮嚎绋嬩腑鎵ц锛屽鏋滃湪涓荤嚎绋嬩腑璋冪敤璇ユ柟娉曪紝鏂规硶鍐呴儴浼氳嚜鍔ㄥ垏鎹㈡垚寮傛鎵ц
* 2. 鍚屾鎺ュ彛浼氶樆濉炲綋鍓嶅瓙绾跨▼锛岄樆濉炴椂闀垮彲浠ラ€氳繃{@link InitConfig.Builder#setTimeout(int)}璁剧疆锛?
* 涓嶈繃闃诲鏃堕暱鐨勪笂闄愭槸5s锛屽鏋滆缃殑瓒呮椂鏃堕暱瓒呰繃5s鍒欐棤鏁?
*
* @param host 瑕佽В鏋愮殑host鍩熷悕鍒楄〃
* @param type {@link RequestIpType}
* @param params 鑷畾涔夎В鏋愬弬鏁?
* @param cacheKey 缂撳瓨鐨刱ey
* @return {@link HTTPDNSResult}
*/
HTTPDNSResult getHttpDnsResultForHostSync(String host, RequestIpType type, Map<String,
String> params, String cacheKey);
/**
* 寮傛瑙f瀽鎺ュ彛, 鑾峰彇ipv4 + ipv6鍒楄〃, 閫氳繃鍥炶皟杩斿洖瑙f瀽缁撴灉锛岄鍏堟煡璇㈢紦瀛? 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
* 鏀寔閰嶇疆sdns鍙傛暟
* 鏀寔鎸囧畾瑙f瀽绫诲瀷
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @param type {@link RequestIpType} 缃戠粶鏍堢被鍨嬶紝v4,v6,both,auto(鏍规嵁褰撳墠璁惧鎵€杩炵殑缃戠粶鑷姩鍒ゆ柇缃戠粶鏍?
* @param params 鑷畾涔夎В鏋愬弬鏁?
* @param cacheKey 缂撳瓨鐨刱ey
*/
void getHttpDnsResultForHostAsync(String host, RequestIpType type, Map<String,
String> params, String cacheKey, HttpDnsCallback callback);
/**
* 寮傛瑙f瀽鎺ュ彛, 鑾峰彇ipv4 + ipv6鍒楄〃, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
* 鏀寔閰嶇疆sdns鍙傛暟
* 鏀寔鎸囧畾瑙f瀽绫诲瀷
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @param type {@link RequestIpType} 缃戠粶鏍堢被鍨嬶紝v4,v6,both,auto(鏍规嵁褰撳墠璁惧鎵€杩炵殑缃戠粶鑷姩鍒ゆ柇缃戠粶鏍?
* @param params 鑷畾涔夎В鏋愬弬鏁?
* @param cacheKey 缂撳瓨鐨刱ey
*/
HTTPDNSResult getHttpDnsResultForHostSyncNonBlocking(String host, RequestIpType type, Map<String,
String> params, String cacheKey);
//浠ヤ笂閽堝SDNS
/**
* 璁剧疆region锛屾捣澶栬妭鐐?
* 鍥藉唴鐗堥粯璁ゆ槸涓浗澶ч檰鑺傜偣锛屽浗闄呯増榛樿鏄柊鍔犲潯鑺傜偣
*
* @param region sg(鏂板鍧?, hk(涓浗棣欐腐), ""(涓浗澶ч檰), de(寰峰浗), us(缇庡浗)
*/
@Deprecated
void setRegion(String region);
/**
* 璁剧疆region
* 鍥藉唴鐗堥粯璁ゆ槸涓浗澶ч檰鑺傜偣
*
* @param region {@link Region}
*/
void setRegion(Region region);
/**
* 绔嬪嵆娓呴櫎鍩熷悕绔晶鍐呭瓨鍜屾湰鍦扮紦瀛樸€?
* 鍚庣画璋冪敤寮傛鎺ュ彛锛屼細鍏堣繑鍥炵┖锛岃Е鍙戝煙鍚嶈В鏋?
*
* @param hosts host鍩熷悕鍒楄〃
*/
void cleanHostCache(ArrayList<String> hosts);
/**
* 鍚屾瑙f瀽鎺ュ彛锛屾敮鎸佹寚瀹氳В鏋愮被鍨?
* 闇€瑕佹敞鎰忕殑鍦版柟:
* 1. 璇ユ柟娉曞繀椤诲湪瀛愮嚎绋嬩腑鎵ц锛屽鏋滃湪涓荤嚎绋嬩腑璋冪敤璇ユ柟娉曪紝鏂规硶鍐呴儴浼氳嚜鍔ㄥ垏鎹㈡垚寮傛鎵ц
* 2. 鍚屾鎺ュ彛浼氶樆濉炲綋鍓嶅瓙绾跨▼锛岄樆濉炴椂闀垮彲浠ラ€氳繃{@link InitConfig.Builder#setTimeout(int)}璁剧疆锛?
* 涓嶈繃闃诲鏃堕暱鐨勪笂闄愭槸5s锛屽鏋滆缃殑瓒呮椂鏃堕暱瓒呰繃5s鍒欐棤鏁?
*
* @param host 瑕佽В鏋愮殑host鍩熷悕鍒楄〃
* @param type {@link RequestIpType}
* @return {@link HTTPDNSResult}
*/
HTTPDNSResult getHttpDnsResultForHostSync(String host, RequestIpType type);
/**
* 寮傛瑙瀽鎺ュ彛锛屾牴鎹畉ype鑾峰彇ip, 閫氳繃鍥炶皟杩斿洖瑙f瀽缁撴灉锛岄鍏堟煡璇㈢紦瀛? 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰
* 鏀寔 鎸囧畾瑙瀽IP绫诲瀷
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @param type {@link RequestIpType} 缃戠粶鏍堢被鍨嬶紝v4,v6,both,auto(鏍规嵁褰撳墠璁惧鎵€杩炵殑缃戠粶鑷姩鍒ゆ柇缃戠粶鏍?
*/
void getHttpDnsResultForHostAsync(String host, RequestIpType type, HttpDnsCallback callback);
/**
* 寮傛瑙瀽鎺ュ彛锛屾牴鎹畉ype鑾峰彇ip, 棣栧厛鏌ヨ缂撳瓨, 鑻ュ瓨鍦ㄥ垯杩斿洖缁撴灉, 鑻ヤ笉瀛樺湪杩斿洖null 骞朵笖杩涜寮傛鍩熷悕瑙f瀽璇锋眰锛堜笉浼氶€氳繃鍥炶皟缁欒皟鐢ㄦ柟锛?
* 鏀寔 鎸囧畾瑙瀽IP绫诲瀷
*
* @param host 瑕佽В鏋愮殑host鍩熷悕
* @param type {@link RequestIpType} 缃戠粶鏍堢被鍨嬶紝v4,v6,both,auto(鏍规嵁褰撳墠璁惧鎵€杩炵殑缃戠粶鑷姩鍒ゆ柇缃戠粶鏍?
* @return {@link HTTPDNSResult}
*/
HTTPDNSResult getHttpDnsResultForHostSyncNonBlocking(String host, RequestIpType type);
}

View File

@@ -0,0 +1,48 @@
package com.newsdk.sdk.android.httpdns;
import android.content.Context;
public class HttpDnsSettings {
private static boolean sDailyReport = true;
public static void setDailyReport(boolean dailyReport) {
HttpDnsSettings.sDailyReport = dailyReport;
}
public static boolean isDailyReport() {
return sDailyReport;
}
private static NetworkChecker checker = new NetworkChecker() {
@Override
public boolean isIpv6Only() {
return false;
}
};
@Deprecated
public static void setNetworkChecker(NetworkChecker checker) {
HttpDnsSettings.checker = checker;
}
@Deprecated
public static NetworkChecker getChecker() {
return checker;
}
/**
* 闇€瑕佸閮ㄦ敞鍏ョ殑涓€浜涚綉缁滅幆澧冨垽鏂?
*/
public interface NetworkChecker {
boolean isIpv6Only();
}
/**
* 鑾峰彇缃戠粶绫诲瀷鐨勬帴鍙?
*/
public interface NetworkDetector {
NetType getNetType(Context context);
}
}

View File

@@ -0,0 +1,91 @@
package com.newsdk.sdk.android.httpdns;
import android.content.Context;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.network.HttpDnsAdapterOptions;
import com.newsdk.sdk.android.httpdns.network.HttpDnsHttpAdapter;
import java.util.HashMap;
import java.util.Map;
public final class HttpDnsV1Client {
private HttpDnsV1Client() {
}
public static HttpDnsService init(Context context,
String appId,
String serviceUrl,
String signSecret) {
InitConfig.Builder builder = new InitConfig.Builder()
.setContext(context)
.setServiceUrl(serviceUrl);
if (!TextUtils.isEmpty(signSecret)) {
builder.setSecretKey(signSecret);
}
builder.buildFor(appId);
if (!TextUtils.isEmpty(signSecret)) {
return HttpDns.getService(context, appId, signSecret);
}
return HttpDns.getService(context, appId);
}
public static HttpDnsService init(Context context,
String appId,
String primaryServiceHost,
String backupServiceHost,
int servicePort,
String signSecret) {
InitConfig.Builder builder = new InitConfig.Builder()
.setContext(context)
.setEnableHttps(true)
.setPrimaryServiceHost(primaryServiceHost)
.setServicePort(servicePort > 0 ? servicePort : 443);
if (!TextUtils.isEmpty(backupServiceHost)) {
builder.setBackupServiceHost(backupServiceHost);
}
if (!TextUtils.isEmpty(signSecret)) {
builder.setSecretKey(signSecret);
}
builder.buildFor(appId);
if (!TextUtils.isEmpty(signSecret)) {
return HttpDns.getService(context, appId, signSecret);
}
return HttpDns.getService(context, appId);
}
public static HTTPDNSResult resolveHost(HttpDnsService service,
String host,
String qtype,
String cip) {
if (service == null) {
return HTTPDNSResult.empty(host);
}
RequestIpType requestIpType = RequestIpType.auto;
if ("AAAA".equalsIgnoreCase(qtype)) {
requestIpType = RequestIpType.v6;
}
Map<String, String> params = null;
if (!TextUtils.isEmpty(cip)) {
params = new HashMap<>();
params.put("cip", cip);
}
return service.getHttpDnsResultForHostSyncNonBlocking(host, requestIpType, params, host);
}
public static HttpDnsHttpAdapter buildHttpClientAdapter(HttpDnsService service) {
return HttpDns.buildHttpClientAdapter(service);
}
public static HttpDnsHttpAdapter buildHttpClientAdapter(HttpDnsService service,
HttpDnsAdapterOptions options) {
return HttpDns.buildHttpClientAdapter(service, options);
}
}

View File

@@ -0,0 +1,13 @@
package com.newsdk.sdk.android.httpdns;
/**
* 鏃ュ織鎺ュ彛
*/
public interface ILogger {
/**
* 鏃ュ織杈撳嚭
*/
void log(String msg);
}

View File

@@ -0,0 +1,552 @@
package com.newsdk.sdk.android.httpdns;
import android.app.Application;
import android.content.Context;
import android.text.TextUtils;
import android.text.format.DateUtils;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.newsdk.sdk.android.httpdns.exception.InitException;
import com.newsdk.sdk.android.httpdns.ranking.IPRankingBean;
import com.newsdk.sdk.android.httpdns.utils.Constants;
/**
* 鍒濆鍖栭厤缃?
* 涔嬪墠鐨勫垵濮嬪寲鏂瑰紡锛屾瘡涓厤缃兘鏄崟鐙缃殑锛屾湁鍙兘閫犳垚涓€浜涙椂搴忎笂鐨勯棶棰?
* 鎵€浠ュ鍔犵粺涓€鍒濆鍖栭厤缃殑鏂规硶锛岀敱鍐呴儴鍥哄畾鍒濆鍖栭€昏緫锛岄伩鍏嶆椂搴忛棶棰?
*/
public class InitConfig {
private static final Map<String, InitConfig> configs = new ConcurrentHashMap<>();
static void addConfig(String accountId, InitConfig config) {
configs.put(accountId, config);
}
public static final String NOT_SET = null;
public static InitConfig getInitConfig(String accountId) {
return configs.get(accountId);
}
public static void removeConfig(String accountId) {
if (accountId == null || accountId.isEmpty()) {
configs.clear();
} else {
configs.remove(accountId);
}
}
private final boolean mEnableExpiredIp;
private final boolean mEnableCacheIp;
private final long mExpiredThresholdMillis;
private final int mTimeout;
private final boolean mEnableHttps;
private final List<IPRankingBean> mIPRankingList;
private final String mRegion;
private final CacheTtlChanger mCacheTtlChanger;
private final List<String> mHostListWithFixedIp;
private final boolean mResolveAfterNetworkChange;
private final DegradationFilter mDegradationFilter;
private final NotUseHttpDnsFilter mNotUseHttpDnsFilter;
private final boolean mEnableCrashDefend;
private final Map<String, String> mSdnsGlobalParams;
private final boolean mEnableDegradationLocalDns;
private final boolean mEnableObservable;
private final String mBizTags;
private final String aesSecretKey;
private final String secretKey;
private final String primaryServiceHost;
private final String backupServiceHost;
private final int servicePort;
private final Context context;
private InitConfig(Builder builder) {
mEnableExpiredIp = builder.enableExpiredIp;
mEnableCacheIp = builder.enableCacheIp;
mExpiredThresholdMillis = builder.expiredThresholdMillis;
mTimeout = builder.timeout;
mEnableHttps = builder.enableHttps;
mIPRankingList = builder.ipRankingList;
mRegion = builder.region;
mCacheTtlChanger = builder.cacheTtlChanger;
mHostListWithFixedIp = builder.hostListWithFixedIp;
mResolveAfterNetworkChange = builder.resolveAfterNetworkChange;
mDegradationFilter = builder.degradationFilter;
mNotUseHttpDnsFilter = builder.notUseHttpDnsFilter;
mEnableCrashDefend = builder.enableCrashDefend;
mSdnsGlobalParams = builder.sdnsGlobalParams;
mEnableDegradationLocalDns = builder.enableDegradationLocalDns;
mEnableObservable = builder.enableObservable;
mBizTags = builder.bizTags;
aesSecretKey = builder.aesSecretKey;
primaryServiceHost = builder.primaryServiceHost;
backupServiceHost = builder.backupServiceHost;
servicePort = builder.servicePort;
context = builder.context;
secretKey = builder.secretKey;
}
public boolean isEnableExpiredIp() {
return mEnableExpiredIp;
}
public boolean isEnableCacheIp() {
return mEnableCacheIp;
}
public long getExpiredThresholdMillis() {
return mExpiredThresholdMillis;
}
public boolean isResolveAfterNetworkChange() {
return mResolveAfterNetworkChange;
}
public int getTimeout() {
return mTimeout;
}
public boolean isEnableHttps() {
return mEnableHttps;
}
public boolean isEnableDegradationLocalDns() {
return mEnableDegradationLocalDns;
}
public List<IPRankingBean> getIPRankingList() {
return mIPRankingList;
}
public String getRegion() {
return mRegion;
}
public CacheTtlChanger getCacheTtlChanger() {
return mCacheTtlChanger;
}
public List<String> getHostListWithFixedIp() {
return mHostListWithFixedIp;
}
@Deprecated
public DegradationFilter getDegradationFilter() {
return mDegradationFilter;
}
public NotUseHttpDnsFilter getNotUseHttpDnsFilter() {
return mNotUseHttpDnsFilter;
}
public boolean isEnableCrashDefend() {
return mEnableCrashDefend;
}
public Map<String, String> getSdnsGlobalParams() {
return mSdnsGlobalParams;
}
public boolean isEnableObservable() {
return mEnableObservable;
}
public String getBizTags() {
return mBizTags;
}
public String getAesSecretKey() {
return aesSecretKey;
}
public String getPrimaryServiceHost() {
return primaryServiceHost;
}
public String getBackupServiceHost() {
return backupServiceHost;
}
public int getServicePort() {
return servicePort;
}
public Context getContext() {return context;}
public String getSecretKey() {
return secretKey;
}
public static class Builder {
private boolean enableExpiredIp = Constants.DEFAULT_ENABLE_EXPIRE_IP;
private boolean enableCacheIp = Constants.DEFAULT_ENABLE_CACHE_IP;
private long expiredThresholdMillis = 0L;
private int timeout = Constants.DEFAULT_TIMEOUT;
private boolean enableDegradationLocalDns = Constants.DEFAULT_ENABLE_DEGRADATION_LOCAL_DNS;
private boolean enableHttps = Constants.DEFAULT_ENABLE_HTTPS;
private List<IPRankingBean> ipRankingList = null;
private String region = NOT_SET;
private CacheTtlChanger cacheTtlChanger = null;
private List<String> hostListWithFixedIp = null;
private boolean resolveAfterNetworkChange = true;
private DegradationFilter degradationFilter = null;
private NotUseHttpDnsFilter notUseHttpDnsFilter = null;
private boolean enableCrashDefend = false;
private boolean enableObservable = true;
private Map<String, String> sdnsGlobalParams = null;
private String bizTags = null;
private String aesSecretKey = null;
private String primaryServiceHost = null;
private String backupServiceHost = null;
private int servicePort = -1;
private Context context = null;
private String secretKey = null;
/**
* 璁剧疆鏄惁鍏佽杩斿洖瓒呰繃ttl 鐨刬p
* @param enableExpiredIp 鏄惁鍏佽杩斿洖瓒呰繃ttl 鐨刬p
* @return {@link Builder}
*/
public Builder setEnableExpiredIp(boolean enableExpiredIp) {
this.enableExpiredIp = enableExpiredIp;
return this;
}
/**
* 璁剧疆鏄惁鍏佽浣跨敤DB缂撳瓨锛岄粯璁や笉鍏佽
* @param enableCacheIp 鏄惁鍏佽浣跨敤DB缂撳瓨
* @return {@link Builder}
*/
public Builder setEnableCacheIp(boolean enableCacheIp) {
this.enableCacheIp = enableCacheIp;
return this;
}
public Builder setEnableCacheIp(boolean enableCacheIp, long expiredThresholdMillis) {
this.enableCacheIp = enableCacheIp;
if (expiredThresholdMillis >= 0 && expiredThresholdMillis <= DateUtils.YEAR_IN_MILLIS) {
this.expiredThresholdMillis = expiredThresholdMillis;
}
return this;
}
/**
* 璁剧疆璇锋眰瓒呮椂鏃堕棿,鍗曚綅ms,榛樿涓?s
* @param timeoutMillis 瓒呮椂鏃堕棿锛屽崟浣峬s
* @return {@link Builder}
*/
public Builder setTimeoutMillis(int timeoutMillis) {
timeout = timeoutMillis;
return this;
}
/**
* 璁剧疆璇锋眰瓒呮椂鏃堕棿,鍗曚綅ms,榛樿涓?s
* @param timeout 瓒呮椂鏃堕棿锛屽崟浣峬s
* @return {@link Builder}
*/
@Deprecated
public Builder setTimeout(int timeout) {
this.timeout = timeout;
return this;
}
/**
* 璁剧疆寮€鍚?鍏抽棴闄嶇骇鍒癓ocal Dns锛屽湪httpdns瑙瀽澶辫触鎴栬€呭煙鍚嶈杩囨护涓嶈蛋httpdns鐨勬椂鍊欙紝寮€鍚檷绾т細璧發ocal dns瑙
* @param enableDegradation true, 寮€鍚?锝?false, 鍏抽棴
* @return {@link Builder}
*/
public Builder setEnableDegradationLocalDns(boolean enableDegradation) {
enableDegradationLocalDns = enableDegradation;
return this;
}
/**
* 璁剧疆HTTPDNS鍩熷悕瑙瀽璇锋眰绫诲瀷(HTTP/HTTPS)锛岃嫢涓嶈皟鐢ㄨ鎺ュ彛锛岄粯璁や负HTTP璇锋眰
* @param enableHttps 鏄惁浣跨敤https
* @return {@link Builder}
*/
public Builder setEnableHttps(boolean enableHttps) {
this.enableHttps = enableHttps;
return this;
}
/**
* 璁剧疆瑕佹帰娴嬬殑鍩熷悕鍒楄〃,榛樿鍙細瀵筰pv4鐨勫湴鍧€杩涜ip浼橀€?
* @param ipRankingList {@link IPRankingBean}
* @return {@link Builder}
*/
public Builder setIPRankingList(List<IPRankingBean> ipRankingList) {
this.ipRankingList = ipRankingList;
return this;
}
@Deprecated
public Builder setRegion(String region) {
this.region = region;
return this;
}
public Builder setRegion(Region region) {
if (region != null) {
this.region = region.getRegion();
}
return this;
}
/**
* 閰嶇疆鑷畾涔塼tl鐨勯€昏緫
*
* @param cacheTtlChanger 淇敼ttl鐨勬帴鍙?
*/
public Builder configCacheTtlChanger(CacheTtlChanger cacheTtlChanger) {
this.cacheTtlChanger = cacheTtlChanger;
return this;
}
/**
* 閰嶇疆涓荤珯鍩熷悕鍒楄〃
*
* @param hostListWithFixedIp 涓荤珯鍩熷悕鍒楄〃
*/
public Builder configHostWithFixedIp(List<String> hostListWithFixedIp) {
this.hostListWithFixedIp = hostListWithFixedIp;
return this;
}
/**
* 璁剧疆缃戠粶鍒囨崲鏃舵槸鍚﹁嚜鍔ㄥ埛鏂版墍鏈夊煙鍚嶈В鏋愮粨鏋滐紝榛樿鑷姩鍒锋柊
* @param enable 鏄惁鍏佽鑷姩鍒锋柊鍩熷悕瑙f瀽缁撴灉
* @return {@link Builder}
*/
public Builder setPreResolveAfterNetworkChanged(boolean enable) {
resolveAfterNetworkChange = enable;
return this;
}
/**
* 璁剧疆闄嶇骇绛栫暐, 鐢ㄦ埛鍙畾鍒惰鍒欓檷绾т负鍘熺敓DNS瑙瀽鏂瑰紡
* @param filter {@link DegradationFilter}
* @return {@link Builder}
*/
@Deprecated
public Builder setDegradationFilter(DegradationFilter filter) {
degradationFilter = filter;
return this;
}
/**
* 璁剧疆涓嶄娇鐢℉ttpDns鐨勭瓥鐣? 鐢ㄦ埛鍙畾鍒惰鍒欐寚瀹氫笉璧癶ttpdns鐨勫煙鍚?
* @param filter {@link NotUseHttpDnsFilter}
* @return {@link Builder}
*/
public Builder setNotUseHttpDnsFilter(NotUseHttpDnsFilter filter) {
notUseHttpDnsFilter = filter;
return this;
}
/**
* 鏄惁寮€鍚痵dk鍐呴儴鐨勫穿婧冧繚鎶ゆ満鍒讹紝榛樿鏄叧闂殑
* @param enabled 寮€鍚?鍏抽棴
* @return {@link Builder}
*/
public Builder enableCrashDefend(boolean enabled) {
enableCrashDefend = enabled;
return this;
}
/**
* 璁剧疆sdns鍏ㄥ眬鍙傛暟锛堣鍏ㄥ眬鍙傛暟涓嶅奖鍝嶅紓姝ヨВ鏋愪换鍔★紝鍙敤浜庤В鏋愭帴鍙皟鐢ㄦ椂杩涜鍙傛暟鍚堝苟锛?
* @param params sdn鐨勫叏灞€鍙傛暟
* @return {@link Builder}
*/
public Builder setSdnsGlobalParams(Map<String, String> params) {
sdnsGlobalParams = params;
return this;
}
public Builder enableObservable(boolean enabled) {
enableObservable = enabled;
return this;
}
public Builder setBizTags(List<String> tags) {
if (tags == null) {
return this;
}
if (tags.size() > 5) {
throw new InitException("The number of tags cannot be greater than 5");
}
Pattern p = Pattern.compile("[^a-zA-Z0-9-]");
Matcher matcher;
StringBuilder tmpTag = new StringBuilder();
for (int i = 0; i != tags.size(); ++i) {
String tag = tags.get(i);
if (TextUtils.isEmpty(tag)) {
continue;
}
matcher = p.matcher(tag);
if (matcher.find()) {
throw new InitException("tag can only contain a-z and A-Z and 0-9 and -");
}
if (tmpTag.indexOf(tag) != -1) {
//鍘婚噸
continue;
}
tmpTag.append(tag);
if (i != tags.size() - 1) {
tmpTag.append(",");
}
}
int lastCommaIndex = tmpTag.lastIndexOf(",");
//鏈€鍚庝竴浣嶉€楀彿瑕佸幓鎺?
if (lastCommaIndex == tmpTag.length() - 1) {
tmpTag.deleteCharAt(lastCommaIndex);
}
if (tmpTag.length() > 64) {
throw new InitException("The length of all tags cannot be greater than 64");
}
bizTags = tmpTag.toString();
return this;
}
/**
* 璁剧疆aes鍔犲瘑瀵嗛挜
* @param aesSecretKey 鍔犲瘑瀵嗛挜
* @return {@link Builder}
*/
public Builder setAesSecretKey(String aesSecretKey) {
this.aesSecretKey = aesSecretKey;
return this;
}
/**
* 璁剧疆涓绘湇鍔″煙鍚嶃€? */
public Builder setPrimaryServiceHost(String host) {
this.primaryServiceHost = host;
return this;
}
/**
* 璁剧疆澶囨湇鍔″煙鍚嶃€? */
public Builder setBackupServiceHost(String host) {
this.backupServiceHost = host;
return this;
}
/**
* Configure HTTPDNS endpoint with URL, e.g. "https://example.com:8445".
* This sets scheme/host/port in one call and clears backup host.
*/
public Builder setServiceUrl(String serviceUrl) {
if (TextUtils.isEmpty(serviceUrl)) {
throw new InitException("serviceUrl should not be empty");
}
String raw = serviceUrl.trim();
if (raw.isEmpty()) {
throw new InitException("serviceUrl should not be empty");
}
String normalized = raw;
if (!raw.startsWith("http://") && !raw.startsWith("https://")) {
normalized = "https://" + raw;
}
try {
URI uri = new URI(normalized);
String host = uri.getHost();
if (TextUtils.isEmpty(host)) {
throw new InitException("invalid serviceUrl host: " + serviceUrl);
}
this.primaryServiceHost = host;
this.backupServiceHost = null;
if (uri.getPort() > 0) {
this.servicePort = uri.getPort();
}
String scheme = uri.getScheme();
this.enableHttps = !"http".equalsIgnoreCase(scheme);
} catch (URISyntaxException e) {
throw new InitException("invalid serviceUrl: " + serviceUrl);
}
return this;
}
/**
* 鎵归噺璁剧疆鏈嶅姟鍩熷悕锛屾敮鎸佷富澶囦袱涓€? */
public Builder setServiceHosts(List<String> hosts) {
if (hosts != null && hosts.size() > 0) {
this.primaryServiceHost = hosts.get(0);
}
if (hosts != null && hosts.size() > 1) {
this.backupServiceHost = hosts.get(1);
}
return this;
}
/**
* 璁剧疆鏈嶅姟绔彛锛岄粯璁?-1 琛ㄧず浣跨敤鍗忚榛樿绔彛銆? */
public Builder setServicePort(int port) {
this.servicePort = port;
return this;
}
/**
* 璁剧疆context
* @param context 涓婁笅鏂?
* @return {@link Builder}
*/
public Builder setContext(Context context) {
if (context instanceof Application) {
this.context = context;
} else {
if (context != null) {
this.context = context.getApplicationContext();
}
}
return this;
}
/**
* 璁剧疆鍔犵瀵嗛挜
* @param secretKey 鍔犵瀵嗛挜
* @return {@link Builder}
*/
public Builder setSecretKey(String secretKey) {
this.secretKey = secretKey;
return this;
}
public InitConfig build() {
return new InitConfig(this);
}
public InitConfig buildFor(String accountId) {
InitConfig config = new InitConfig(this);
addConfig(accountId, config);
return config;
}
}
}

View File

@@ -0,0 +1,12 @@
package com.newsdk.sdk.android.httpdns;
/**
* 缃戠粶绫诲瀷
*/
public enum NetType {
none,
v4,
v6,
both
}

View File

@@ -0,0 +1,15 @@
package com.newsdk.sdk.android.httpdns;
/**
* 涓嶄娇鐢℉ttpDns鐨勯厤缃帴鍙?
*/
public interface NotUseHttpDnsFilter {
/**
* 鏄惁搴旇涓嶄娇鐢╤ttpdns
* @param hostName 鍩熷悕
* @return true 涓嶈蛋httpdns瑙瀽 锝?false 璧癶ttpdns瑙
*
*/
boolean notUseHttpDns(String hostName);
}

View File

@@ -0,0 +1,21 @@
package com.newsdk.sdk.android.httpdns;
import com.newsdk.sdk.android.httpdns.utils.Constants;
public enum Region {
DEFAULT(""),
HK(Constants.REGION_HK),
SG(Constants.REGION_SG),
DE(Constants.REGION_DE),
US(Constants.REGION_US);
private final String region;
Region(String region) {
this.region = region;
}
public String getRegion() {
return region;
}
}

View File

@@ -0,0 +1,18 @@
package com.newsdk.sdk.android.httpdns;
/**
* 璇锋眰鐨刬p绫诲瀷
*/
public enum RequestIpType {
v4,
v6,
/**
* 琛ㄧず 涓や釜閮借
*/
both,
/**
* 琛ㄧず鏍规嵁缃戠粶鎯呭喌鑷姩鍒ゆ柇
*/
auto
}

View File

@@ -0,0 +1,14 @@
package com.newsdk.sdk.android.httpdns;
public interface SyncService {
/**
* 鍚屾瑙f瀽鎺ュ彛锛屽繀椤诲湪瀛愮嚎绋嬩腑鎵ц锛屽惁鍒欐病鏈夋晥鏋?
*
* @deprecated 璇ユ帴鍙e凡搴熷純锛屽悗缁増鏈彲鑳戒細鍒犻櫎锛岃浣跨敤
* {@link HttpDnsService#getHttpDnsResultForHostSync(String, RequestIpType)}
*/
@Deprecated
HTTPDNSResult getByHost(String host, RequestIpType type);
}

View File

@@ -0,0 +1,184 @@
package com.newsdk.sdk.android.httpdns.cache;
import java.util.Arrays;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
/**
* ip瑙瀽缁撴灉璁板綍
* 娉ㄦ剰璁畻hash 鍜?equal瀹炵幇锛屾病鏈変娇鐢╢romDB瀛楁
*/
public class HostRecord {
private long id = -1;
private String region;
private String host;
private String[] ips;
private int type;
private int ttl;
private long queryTime;
private String extra;
private String cacheKey;
private boolean fromDB = false;
private String serverIp;
private String noIpCode;
public static HostRecord create(String region, String host, RequestIpType type, String extra,
String cacheKey, String[] ips, int ttl, String serverIp, String noIpCode) {
HostRecord record = new HostRecord();
record.region = region;
record.host = host;
record.type = type.ordinal();
record.ips = ips;
record.ttl = ttl;
record.queryTime = System.currentTimeMillis();
record.extra = extra;
record.cacheKey = cacheKey;
record.serverIp = serverIp;
record.noIpCode = noIpCode;
return record;
}
public boolean isExpired() {
return System.currentTimeMillis() > queryTime + ttl * 1000L;
}
public void setFromDB(boolean fromDB) {
this.fromDB = fromDB;
}
public boolean isFromDB() {
return fromDB;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String[] getIps() {
return ips;
}
public void setIps(String[] ips) {
this.ips = ips;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getTtl() {
return ttl;
}
public void setTtl(int ttl) {
this.ttl = ttl;
}
public long getQueryTime() {
return queryTime;
}
public void setQueryTime(long queryTime) {
this.queryTime = queryTime;
}
public String getExtra() {
return extra;
}
public void setExtra(String extra) {
this.extra = extra;
}
public String getCacheKey() {
return cacheKey;
}
public void setCacheKey(String cacheKey) {
this.cacheKey = cacheKey;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public void setServerIp(String ip) {
serverIp = ip;
}
public String getServerIp() {
return serverIp;
}
public void setNoIpCode(String noIpCode) {
this.noIpCode = noIpCode;
}
public String getNoIpCode() {
return noIpCode;
}
@Override
public boolean equals(Object o) {
if (this == o) {return true;}
if (o == null || getClass() != o.getClass()) {return false;}
HostRecord that = (HostRecord)o;
return id == that.id &&
type == that.type &&
ttl == that.ttl &&
queryTime == that.queryTime &&
region.equals(that.region) &&
host.equals(that.host) &&
Arrays.equals(ips, that.ips) &&
CommonUtil.equals(extra, that.extra) &&
CommonUtil.equals(cacheKey, that.cacheKey) &&
CommonUtil.equals(noIpCode, that.noIpCode);
}
@Override
public int hashCode() {
int result = Arrays.hashCode(
new Object[] {id, region, host, type, ttl, queryTime, extra, cacheKey, noIpCode});
result = 31 * result + Arrays.hashCode(ips);
return result;
}
@Override
public String toString() {
return "HostRecord{" +
"id=" + id +
", region='" + region + '\'' +
", host='" + host + '\'' +
", ips=" + Arrays.toString(ips) +
", type=" + type +
", ttl=" + ttl +
", queryTime=" + queryTime +
", extra='" + extra + '\'' +
", cacheKey='" + cacheKey + '\'' +
", fromDB=" + fromDB +
", noIpCode=" + noIpCode +
'}';
}
}

View File

@@ -0,0 +1,261 @@
package com.newsdk.sdk.android.httpdns.cache;
import java.util.ArrayList;
import java.util.List;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* 鏁版嵁搴撳瓨鍙栨搷浣?
*/
public class RecordDBHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "aliclound_httpdns_v3_";
private static final int DB_VERSION = 0x03;
static class HOST {
static final String TABLE_NAME = "host";
static final String COL_ID = "id";
static final String COL_REGION = "region";
static final String COL_HOST = "host";
static final String COL_IPS = "ips";
static final String COL_TYPE = "type";
static final String COL_TIME = "time";
static final String COL_TTL = "ttl";
static final String COL_EXTRA = "extra";
static final String COL_CACHE_KEY = "cache_key";
// 鏃х増鏈?鐢ㄤ簬瀛樺偍缃戠粶鏍囪瘑鐨勫瓧娈碉紝鐢变簬鍚堣鐨勫奖鍝嶏紝鍒犻櫎浜嗙浉鍏充唬鐮侊紝姝ゅ瓧娈靛彉涓哄浐瀹氬瓧娈碉紝鐩墠宸茬粡娌℃湁鎰忎箟
static final String COL_SP = "sp";
static final String COL_NO_IP_CODE = "no_ip_code";
static final String CREATE_HOST_TABLE_SQL = "CREATE TABLE " + TABLE_NAME + " ("
+ COL_ID + " INTEGER PRIMARY KEY,"
+ COL_REGION + " TEXT,"
+ COL_HOST + " TEXT,"
+ COL_IPS + " TEXT,"
+ COL_TYPE + " INTEGER,"
+ COL_TIME + " INTEGER,"
+ COL_TTL + " INTEGER,"
+ COL_EXTRA + " TEXT,"
+ COL_CACHE_KEY + " TEXT,"
+ COL_SP + " TEXT,"
+ COL_NO_IP_CODE + " TEXT"
+ ");";
}
private final String mAccountId;
private final Object mLock = new Object();
private SQLiteDatabase mDb;
public RecordDBHelper(Context context, String accountId) {
super(context, DB_NAME + accountId + ".db", null, DB_VERSION);
this.mAccountId = accountId;
}
private SQLiteDatabase getDB() {
if (mDb == null) {
try {
mDb = getWritableDatabase();
} catch (Exception e) {
}
}
return mDb;
}
@Override
protected void finalize() throws Throwable {
if (mDb != null) {
try {
mDb.close();
} catch (Exception ignored) {
}
}
super.finalize();
}
/**
* 浠庢暟鎹簱鑾峰彇鍏ㄩ儴鏁版嵁
*
* @param region
* @return
*/
public List<HostRecord> readFromDb(String region) {
synchronized (mLock) {
ArrayList<HostRecord> hosts = new ArrayList<>();
SQLiteDatabase db = null;
Cursor cursor = null;
try {
db = getDB();
cursor = db.query(HOST.TABLE_NAME, null, HOST.COL_REGION + " = ?",
new String[] {region}, null, null, null);
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
do {
HostRecord hostRecord = new HostRecord();
hostRecord.setId(cursor.getLong(cursor.getColumnIndex(HOST.COL_ID)));
hostRecord.setRegion(
cursor.getString(cursor.getColumnIndex(HOST.COL_REGION)));
hostRecord.setHost(cursor.getString(cursor.getColumnIndex(HOST.COL_HOST)));
hostRecord.setIps(CommonUtil.parseStringArray(
cursor.getString(cursor.getColumnIndex(HOST.COL_IPS))));
hostRecord.setType(cursor.getInt(cursor.getColumnIndex(HOST.COL_TYPE)));
hostRecord.setTtl(cursor.getInt(cursor.getColumnIndex(HOST.COL_TTL)));
hostRecord.setQueryTime(
cursor.getLong(cursor.getColumnIndex(HOST.COL_TIME)));
hostRecord.setExtra(
cursor.getString(cursor.getColumnIndex(HOST.COL_EXTRA)));
hostRecord.setCacheKey(
cursor.getString(cursor.getColumnIndex(HOST.COL_CACHE_KEY)));
hostRecord.setFromDB(true);
hostRecord.setNoIpCode(cursor.getString(cursor.getColumnIndex(HOST.COL_NO_IP_CODE)));
hosts.add(hostRecord);
} while (cursor.moveToNext());
}
} catch (Exception e) {
HttpDnsLog.w("read from db fail " + mAccountId, e);
} finally {
try {
if (cursor != null) {
cursor.close();
}
} catch (Exception ignored) {
}
}
return hosts;
}
}
/**
* 浠庢暟鎹簱鍒犻櫎鏁版嵁
*/
public void delete(List<HostRecord> records) {
if (records == null || records.isEmpty()) {
return;
}
synchronized (mLock) {
SQLiteDatabase db = null;
try {
db = getDB();
db.beginTransaction();
for (HostRecord record : records) {
db.delete(HOST.TABLE_NAME, HOST.COL_ID + " = ? ",
new String[] {String.valueOf(record.getId())});
}
db.setTransactionSuccessful();
} catch (Exception e) {
HttpDnsLog.w("delete record fail " + mAccountId, e);
} finally {
if (db != null) {
try {
db.endTransaction();
} catch (Exception ignored) {
}
}
}
}
}
/**
* 鏇存柊鏁版嵁
*/
public void insertOrUpdate(List<HostRecord> records) {
synchronized (mLock) {
SQLiteDatabase db = null;
try {
db = getDB();
db.beginTransaction();
for (HostRecord record : records) {
ContentValues cv = new ContentValues();
cv.put(HOST.COL_REGION, record.getRegion());
cv.put(HOST.COL_HOST, record.getHost());
cv.put(HOST.COL_IPS, CommonUtil.translateStringArray(record.getIps()));
cv.put(HOST.COL_CACHE_KEY, record.getCacheKey());
cv.put(HOST.COL_EXTRA, record.getExtra());
cv.put(HOST.COL_TIME, record.getQueryTime());
cv.put(HOST.COL_TYPE, record.getType());
cv.put(HOST.COL_TTL, record.getTtl());
cv.put(HOST.COL_NO_IP_CODE, record.getNoIpCode());
if (record.getId() != -1) {
db.update(HOST.TABLE_NAME, cv, HOST.COL_ID + " = ?",
new String[] {String.valueOf(record.getId())});
} else {
long id = db.insert(HOST.TABLE_NAME, null, cv);
record.setId(id);
}
}
db.setTransactionSuccessful();
} catch (Exception e) {
HttpDnsLog.w("insertOrUpdate record fail " + mAccountId, e);
} finally {
if (db != null) {
try {
db.endTransaction();
} catch (Exception ignored) {
}
}
}
}
}
@Override
public void onCreate(SQLiteDatabase db) {
try {
db.execSQL(HOST.CREATE_HOST_TABLE_SQL);
} catch (Exception e) {
HttpDnsLog.w("create db fail " + mAccountId, e);
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion != newVersion) {
try {
db.beginTransaction();
db.execSQL("DROP TABLE IF EXISTS " + HOST.TABLE_NAME + ";");
db.setTransactionSuccessful();
db.endTransaction();
onCreate(db);
} catch (Exception e) {
HttpDnsLog.w("upgrade db fail " + mAccountId, e);
}
}
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion != newVersion) {
try {
db.beginTransaction();
db.execSQL("DROP TABLE IF EXISTS " + HOST.TABLE_NAME + ";");
db.setTransactionSuccessful();
db.endTransaction();
onCreate(db);
} catch (Exception e) {
HttpDnsLog.w("downgrade db fail " + mAccountId, e);
}
}
}
}

View File

@@ -0,0 +1,66 @@
package com.newsdk.sdk.android.httpdns.config;
import java.util.concurrent.atomic.AtomicBoolean;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsConfig;
import com.newsdk.sdk.android.httpdns.utils.Constants;
import android.content.Context;
import android.content.SharedPreferences;
/**
* 杈呭姪閰嶇疆鐨勭紦瀛樺啓鍏ュ拰璇诲彇
*/
public class ConfigCacheHelper {
private final AtomicBoolean mSaving = new AtomicBoolean(false);
public void restoreFromCache(Context context, HttpDnsConfig config) {
SharedPreferences sp = context.getSharedPreferences(
Constants.CONFIG_CACHE_PREFIX + config.getAccountId(), Context.MODE_PRIVATE);
SpCacheItem[] items = config.getCacheItem();
for (SpCacheItem item : items) {
item.restoreFromCache(sp);
}
}
public void saveConfigToCache(Context context, HttpDnsConfig config) {
if (mSaving.compareAndSet(false, true)) {
try {
config.getWorker().execute(new WriteCacheTask(context, config, this));
} catch (Exception ignored) {
mSaving.set(false);
}
}
}
static class WriteCacheTask implements Runnable {
private final Context mContext;
private final HttpDnsConfig mHttpDnsConfig;
private final ConfigCacheHelper mCacheHelper;
public WriteCacheTask(Context context, HttpDnsConfig config, ConfigCacheHelper helper) {
this.mContext = context;
this.mHttpDnsConfig = config;
this.mCacheHelper = helper;
}
@Override
public void run() {
mCacheHelper.mSaving.set(false);
SharedPreferences.Editor editor = mContext.getSharedPreferences(
Constants.CONFIG_CACHE_PREFIX + mHttpDnsConfig.getAccountId(),
Context.MODE_PRIVATE)
.edit();
SpCacheItem[] items = mHttpDnsConfig.getCacheItem();
for (SpCacheItem item : items) {
item.saveToCache(editor);
}
// 铏界劧鎻愮ず寤鸿浣跨敤apply锛屼絾鏄疄璺佃瘉鏄庯紝apply鏄妸鍐欐枃浠舵搷浣滄帹杩熷埌浜嗕竴浜涚晫闈㈠垏鎹㈢瓑鏃舵満锛屽弽鑰屽奖鍝嶄簡UI绾跨▼銆備笉濡傜洿鎺ュ湪瀛愮嚎绋嬪啓鏂囦欢
editor.commit();
}
}
}

View File

@@ -0,0 +1,118 @@
package com.newsdk.sdk.android.httpdns.config;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
import java.util.Arrays;
public class RegionServer {
/**
* HttpDns鐨勬湇鍔P
*/
private String[] mServerIps;
/**
* HttpDns鐨勬湇鍔鍙紝绾夸笂閮芥槸榛樿绔彛 80 鎴栬€?443
* 姝ゅ鏄负浜嗘祴璇曞満鏅寚瀹氱鍙?
* 涓嬫爣鍜寋@link #mServerIps} 瀵瑰簲
* 濡傛灉涓簄ull 琛ㄧず娌℃湁鎸囧畾绔彛
*/
private int[] mPorts;
private String mRegion;
private String[] mIpv6ServerIps;
private int[] mIpv6Ports;
public RegionServer(String[] serverIps, int[] ports, String[] ipv6ServerIps, int[] ipv6Ports, String region) {
this.mServerIps = serverIps == null ? new String[0] : serverIps;
this.mPorts = ports;
this.mRegion = region;
this.mIpv6ServerIps = ipv6ServerIps == null ? new String[0] : ipv6ServerIps;
this.mIpv6Ports = ipv6Ports;
}
public String[] getServerIps() {
return mServerIps;
}
public int[] getPorts() {
return mPorts;
}
public String getRegion() {
return mRegion;
}
public String[] getIpv6ServerIps() {
return mIpv6ServerIps;
}
public int[] getIpv6Ports() {
return mIpv6Ports;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RegionServer that = (RegionServer) o;
return Arrays.equals(mServerIps, that.mServerIps) &&
Arrays.equals(mPorts, that.mPorts) &&
Arrays.equals(mIpv6ServerIps, that.mIpv6ServerIps) &&
Arrays.equals(mIpv6Ports, that.mIpv6Ports) &&
CommonUtil.equals(mRegion, that.mRegion);
}
public boolean serverEquals(RegionServer that) {
return Arrays.equals(mServerIps, that.mServerIps) &&
Arrays.equals(mPorts, that.mPorts) &&
Arrays.equals(mIpv6ServerIps, that.mIpv6ServerIps) &&
Arrays.equals(mIpv6Ports, that.mIpv6Ports) &&
CommonUtil.equals(mRegion, that.mRegion);
}
@Override
public int hashCode() {
int result = Arrays.hashCode(new Object[]{mRegion});
result = 31 * result + Arrays.hashCode(mServerIps);
result = 31 * result + Arrays.hashCode(mPorts);
result = 31 * result + Arrays.hashCode(mIpv6ServerIps);
result = 31 * result + Arrays.hashCode(mIpv6Ports);
return result;
}
public boolean updateIpv6(String[] ips, int[] ports) {
boolean same = CommonUtil.isSameServer(this.mIpv6ServerIps, this.mIpv6Ports, ips, ports);
if (same) {
return false;
}
this.mIpv6ServerIps = ips;
this.mIpv6Ports = ports;
return true;
}
public boolean updateRegionAndIpv4(String region, String[] ips, int[] ports) {
boolean same = CommonUtil.isSameServer(this.mServerIps, this.mPorts, ips, ports);
if (same && region.equals(this.mRegion)) {
return false;
}
this.mRegion = region;
this.mServerIps = ips;
this.mPorts = ports;
return true;
}
public boolean updateAll(String region, String[] ips, int[] ports, String[] ipv6s, int[] v6ports) {
boolean same = CommonUtil.isSameServer(this.mServerIps, this.mPorts, ips, ports);
boolean v6same = CommonUtil.isSameServer(this.mIpv6ServerIps, this.mIpv6Ports, ipv6s, v6ports);
if (same && v6same && region.equals(this.mRegion)) {
return false;
}
this.mRegion = region;
this.mServerIps = ips;
this.mPorts = ports;
this.mIpv6ServerIps = ipv6s;
this.mIpv6Ports = v6ports;
return true;
}
}

View File

@@ -0,0 +1,393 @@
package com.newsdk.sdk.android.httpdns.config;
import java.util.Arrays;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsConfig;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
import com.newsdk.sdk.android.httpdns.utils.Constants;
import android.content.SharedPreferences;
import android.text.TextUtils;
/**
* 鏈嶅姟鑺傜偣閰嶇疆
* 缁存姢 鏈嶅姟鑺傜偣鐨勪竴浜涚姸鎬?
*/
public class ServerConfig extends RegionServer implements SpCacheItem {
private final HttpDnsConfig mHttpDnsConfig;
private int mLastOkServerIndex = 0;
private int mCurrentServerIndex = 0;
private long mServerIpsLastUpdatedTime = 0;
private int mLastOkServerIndexForV6 = 0;
private int mCurrentServerIndexForV6 = 0;
public ServerConfig(HttpDnsConfig config, String[] serverIps, int[] ports, String[] ipv6ServerIps, int[] ipv6Ports) {
super(serverIps, ports, ipv6ServerIps, ipv6Ports, config.getRegion());
mHttpDnsConfig = config;
}
/**
* 鑾峰彇褰撳墠浣跨敤鐨勬湇鍔P
*/
public String getServerIp() {
final String[] serverIps = getServerIps();
if (serverIps == null || mCurrentServerIndex >= serverIps.length
|| mCurrentServerIndex < 0) {
return null;
}
return serverIps[mCurrentServerIndex];
}
/**
* 鑾峰彇褰撳墠浣跨敤鐨勬湇鍔P ipv6
*/
public String getServerIpForV6() {
final String[] serverIps = getIpv6ServerIps();
if (serverIps == null || mCurrentServerIndexForV6 >= serverIps.length
|| mCurrentServerIndexForV6 < 0) {
return null;
}
return serverIps[mCurrentServerIndexForV6];
}
/**
* 鑾峰彇褰撳墠浣跨敤鐨勬湇鍔$鍙?
*/
public int getPort() {
final int[] ports = getPorts();
if (ports == null || mCurrentServerIndex >= ports.length || mCurrentServerIndex < 0) {
return CommonUtil.getPort(-1, mHttpDnsConfig.getSchema());
}
return CommonUtil.getPort(ports[mCurrentServerIndex], mHttpDnsConfig.getSchema());
}
/**
* 鑾峰彇褰撳墠浣跨敤鐨勬湇鍔$鍙?
*/
public int getPortForV6() {
final int[] ports = getIpv6Ports();
if (ports == null || mCurrentServerIndexForV6 >= ports.length
|| mCurrentServerIndexForV6 < 0) {
return CommonUtil.getPort(-1, mHttpDnsConfig.getSchema());
}
return CommonUtil.getPort(ports[mCurrentServerIndexForV6], mHttpDnsConfig.getSchema());
}
/**
* 鏄惁搴旇鏇存柊鏈嶅姟IP
*/
public boolean shouldUpdateServerIp() {
return System.currentTimeMillis() - mServerIpsLastUpdatedTime >= 24 * 60 * 60 * 1000;
}
/**
* 璁剧疆鏈嶅姟IP
*
* @return false 琛ㄧず 鍓嶅悗鏈嶅姟涓€鐩达紝娌℃湁鏇存柊
*/
public synchronized boolean setServerIps(String region, String[] serverIps, int[] ports,
String[] serverV6Ips, int[] v6Ports) {
region = CommonUtil.fixRegion(region);
if (serverIps == null || serverIps.length == 0) {
serverIps = mHttpDnsConfig.getInitServer().getServerIps();
ports = mHttpDnsConfig.getInitServer().getPorts();
}
if (serverV6Ips == null || serverV6Ips.length == 0) {
serverV6Ips = mHttpDnsConfig.getInitServer().getIpv6ServerIps();
v6Ports = mHttpDnsConfig.getInitServer().getIpv6Ports();
}
boolean changed = updateRegionAndIpv4(region, serverIps, ports);
boolean v6changed = updateIpv6(serverV6Ips, v6Ports);
if (changed) {
this.mLastOkServerIndex = 0;
this.mCurrentServerIndex = 0;
}
if (v6changed) {
this.mLastOkServerIndexForV6 = 0;
this.mCurrentServerIndexForV6 = 0;
}
if (!CommonUtil.isSameServer(serverIps, ports,
mHttpDnsConfig.getInitServer().getServerIps(),
mHttpDnsConfig.getInitServer().getPorts())
|| !CommonUtil.isSameServer(serverV6Ips, v6Ports,
mHttpDnsConfig.getInitServer().getIpv6ServerIps(),
mHttpDnsConfig.getInitServer().getIpv6Ports())) {
// 闈炲垵濮嬪寲IP锛屾墠璁や负鏄湡姝殑鏇存柊浜嗘湇鍔P
this.mServerIpsLastUpdatedTime = System.currentTimeMillis();
// 闈炲垵濮婭P鎵嶆湁缂撳瓨鐨勫繀瑕?
mHttpDnsConfig.saveToCache();
}
return changed || v6changed;
}
public synchronized void updateServerIpv4sRank(String[] sortedIps, int[] ports) {
String[] serverIps = getServerIps();
int[] serverPorts = getPorts();
String region = getRegion();
//瀵规瘮鍜屽綋鍓嶇殑region server鏄惁鏄悓涓€鎵癸紝閬垮厤娴嬮€熷畬宸茬粡琚洿鏂?
if (serverIps.length != sortedIps.length) {
//ip鏁伴噺涓嶄竴鑷达紝鏁版嵁宸茬粡琚洿鏂?
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("abort rank server ip count changed, current ips: " + Arrays.toString(serverIps)
+ ", sorted ips: " + Arrays.toString(sortedIps));
}
return;
}
boolean contain;
//濡傛灉鎺掑簭鐨刬p閮藉湪褰撳墠Server ip鍒楄〃涓紝璁や负鏄竴鎵规湇鍔p锛宨p鍜岀鍙渶瑕佷竴璧峰垽鏂?
for (int i = 0; i != sortedIps.length; ++i) {
contain = isContainServiceIp(serverIps, serverPorts, sortedIps[i], ports == null ? -1 : ports[i]);
if (!contain) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("abort rank server ip as changed, current ips: " + Arrays.toString(serverIps)
+ ", ports: " + Arrays.toString(serverPorts)
+ ", sorted ips: " + Arrays.toString(sortedIps)
+ ", ports: " + Arrays.toString(ports)
);
}
return;
}
}
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("update ranked server ips: " + Arrays.toString(sortedIps)
+ ", ports: " + Arrays.toString(ports));
}
//浠呮洿鏂板唴瀛?
boolean changed = updateRegionAndIpv4(region, sortedIps, ports);
if (changed) {
this.mLastOkServerIndex = 0;
this.mCurrentServerIndex = 0;
}
}
public synchronized void updateServerIpv6sRank(String[] sortedIps, int[] ports) {
//鍜屽綋鍓峣p杩涜瀵规瘮锛岀湅鐪嬫槸涓嶆槸宸茬粡琚洿鏂颁簡锛屽鏋滆鏇存柊浜嗛偅姝ゆ鎺掑簭缁撴灉涓嶄娇鐢?
String[] serverIps = getIpv6ServerIps();
int[] serverPorts = getIpv6Ports();
//瀵规瘮鍜屽綋鍓嶇殑region server鏄惁鏄悓涓€鎵癸紝閬垮厤娴嬮€熷畬宸茬粡琚洿鏂?
if (serverIps.length != sortedIps.length) {
//ip鏁伴噺涓嶄竴鑷达紝鏁版嵁宸茬粡琚洿鏂?
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("abort rank server ip count changed, current ipv6s: " + Arrays.toString(serverIps)
+ ", sorted ipv6s: " + Arrays.toString(sortedIps));
}
return;
}
boolean contain;
//濡傛灉鎺掑簭鐨刬p閮藉湪褰撳墠Server ip鍒楄〃涓紝璁や负鏄竴鎵规湇鍔p
for (int i = 0; i != sortedIps.length; ++i) {
contain = isContainServiceIp(serverIps, serverPorts, sortedIps[i], ports == null ? -1 : ports[i]);
if (!contain) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("abort rank server ip as changed, current ipv6s: " + Arrays.toString(serverIps)
+ ", ports: " + Arrays.toString(serverPorts)
+ ", sorted ipv6s: " + Arrays.toString(sortedIps)
+ ", ports: " + Arrays.toString(ports)
);
}
return;
}
}
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("update ranked server ipv6s: " + Arrays.toString(sortedIps)
+ ", ports: " + Arrays.toString(ports));
}
//浠呮洿鏂板唴瀛?
boolean v6changed = updateIpv6(sortedIps, ports);
if (v6changed) {
mLastOkServerIndexForV6 = 0;
mCurrentServerIndexForV6 = 0;
}
}
private boolean isContainServiceIp(String[] sourceIps, int[] sourcePorts, String targetIp, int targetPort) {
if (sourceIps == null || sourceIps.length == 0) {
return false;
}
for (int i = 0; i != sourceIps.length; ++i) {
if (TextUtils.equals(sourceIps[i], targetIp)) {
if (sourcePorts == null) {
return targetPort <= 0;
}
if (i < sourcePorts.length) {
if (sourcePorts[i] == targetPort) {
return true;
}
} else {
if (targetPort <= 0) {
return true;
}
}
}
}
return false;
}
/**
* 鍒囨崲鍩熷悕瑙f瀽鏈嶅姟
*
* @param ip 璇锋眰澶辫触鐨勬湇鍔P
* @param port 璇锋眰澶辫触鐨勬湇鍔$鍙?
* @return 鏄惁鍒囨崲鍥炰簡鏈€寮€濮嬬殑鏈嶅姟銆傚綋璇锋眰鍒囨崲鐨刬p鍜宲ort涓嶆槸褰撳墠ip鍜宲ort鏃讹紝璇存槑杩欎釜鍒囨崲璇锋眰鏄棤鏁堢殑锛屼笉鍒囨崲锛岃繑鍥瀎alse 璁や负娌℃湁鍒囨崲鍥炴渶寮€濮嬬殑ip
*/
public boolean shiftServer(String ip, int port) {
return shiftServerV4(ip, port);
}
private boolean shiftServerV4(String ip, int port) {
final String[] serverIps = getServerIps();
final int[] ports = getPorts();
if (serverIps == null) {
return false;
}
if (!(ip.equals(serverIps[mCurrentServerIndex]) && (ports == null
|| ports[mCurrentServerIndex] == port))) {
return false;
}
mCurrentServerIndex++;
if (mCurrentServerIndex >= serverIps.length) {
mCurrentServerIndex = 0;
}
return mCurrentServerIndex == mLastOkServerIndex;
}
public boolean shiftServerV6(String ip, int port) {
final String[] serverIps = getIpv6ServerIps();
final int[] ports = getIpv6Ports();
if (serverIps == null) {
return false;
}
if (!(ip.equals(serverIps[mCurrentServerIndexForV6]) && (ports == null
|| ports[mCurrentServerIndexForV6] == port))) {
return false;
}
mCurrentServerIndexForV6++;
if (mCurrentServerIndexForV6 >= serverIps.length) {
mCurrentServerIndexForV6 = 0;
}
return mCurrentServerIndexForV6 == mLastOkServerIndexForV6;
}
/**
* 鏍囪褰撳墠濂界敤鐨勫煙鍚嶈В鏋愭湇鍔?
*
* @return 鏍囪鎴愬姛涓庡惁
*/
public boolean markOkServer(String serverIp, int port) {
final String[] serverIps = getServerIps();
final int[] ports = getPorts();
if (serverIps == null) {
return false;
}
if (serverIps[mCurrentServerIndex].equals(serverIp) && (ports == null
|| ports[mCurrentServerIndex] == port)) {
if (mLastOkServerIndex != mCurrentServerIndex) {
mLastOkServerIndex = mCurrentServerIndex;
mHttpDnsConfig.saveToCache();
}
return true;
}
return false;
}
/**
* 鏍囪褰撳墠濂界敤鐨勫煙鍚嶈В鏋愭湇鍔?
*
* @return 鏍囪鎴愬姛涓庡惁
*/
public boolean markOkServerV6(String serverIp, int port) {
final String[] serverIps = getIpv6ServerIps();
final int[] ports = getIpv6Ports();
if (serverIps == null) {
return false;
}
if (serverIps[mCurrentServerIndexForV6].equals(serverIp) && (ports == null
|| ports[mCurrentServerIndexForV6] == port)) {
if (mLastOkServerIndexForV6 != mCurrentServerIndexForV6) {
mLastOkServerIndexForV6 = mCurrentServerIndexForV6;
mHttpDnsConfig.saveToCache();
}
return true;
}
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) {return true;}
if (o == null || getClass() != o.getClass()) {return false;}
if (!super.equals(o)) {return false;}
ServerConfig that = (ServerConfig)o;
return mLastOkServerIndex == that.mLastOkServerIndex &&
mCurrentServerIndex == that.mCurrentServerIndex &&
mLastOkServerIndexForV6 == that.mLastOkServerIndexForV6 &&
mCurrentServerIndexForV6 == that.mCurrentServerIndexForV6 &&
mServerIpsLastUpdatedTime == that.mServerIpsLastUpdatedTime &&
mHttpDnsConfig.equals(that.mHttpDnsConfig);
}
@Override
public int hashCode() {
return Arrays.hashCode(
new Object[] {super.hashCode(), mHttpDnsConfig, mLastOkServerIndex,
mCurrentServerIndex,
mLastOkServerIndexForV6, mCurrentServerIndexForV6, mServerIpsLastUpdatedTime});
}
@Override
public void restoreFromCache(SharedPreferences sp) {
String cachedServerRegion = sp.getString(Constants.CONFIG_CURRENT_SERVER_REGION,
getRegion());
//鍒濆鍖杛egion鍜岀紦瀛榮erver region涓€鑷寸殑鎯呭喌锛屼娇鐢ㄧ紦瀛樼殑鏈嶅姟IP銆傚惁鍒欏垵濮嬪寲鐨剅egion浼樺厛绾ф洿楂?
if (CommonUtil.regionEquals(cachedServerRegion, getRegion())) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("restore service ip of " + (TextUtils.isEmpty(cachedServerRegion) ? "default" : cachedServerRegion));
}
String[] serverIps = CommonUtil.parseStringArray(sp.getString(Constants.CONFIG_KEY_SERVERS,
CommonUtil.translateStringArray(getServerIps())));
int[] ports = CommonUtil.parsePorts(
sp.getString(Constants.CONFIG_KEY_PORTS, CommonUtil.translateIntArray(getPorts())));
String[] serverV6Ips = CommonUtil.parseStringArray(
sp.getString(Constants.CONFIG_KEY_SERVERS_IPV6,
CommonUtil.translateStringArray(getIpv6ServerIps())));
int[] v6Ports = CommonUtil.parsePorts(sp.getString(Constants.CONFIG_KEY_PORTS_IPV6,
CommonUtil.translateIntArray(getIpv6Ports())));
updateAll(cachedServerRegion, serverIps, ports, serverV6Ips, v6Ports);
mServerIpsLastUpdatedTime = sp.getLong(Constants.CONFIG_SERVERS_LAST_UPDATED_TIME, 0);
}
}
@Override
public void saveToCache(SharedPreferences.Editor editor) {
editor.putString(Constants.CONFIG_KEY_SERVERS,
CommonUtil.translateStringArray(getServerIps()));
editor.putString(Constants.CONFIG_KEY_PORTS, CommonUtil.translateIntArray(getPorts()));
editor.putInt(Constants.CONFIG_CURRENT_INDEX, mCurrentServerIndex);
editor.putInt(Constants.CONFIG_LAST_INDEX, mLastOkServerIndex);
editor.putString(Constants.CONFIG_KEY_SERVERS_IPV6,
CommonUtil.translateStringArray(getIpv6ServerIps()));
editor.putString(Constants.CONFIG_KEY_PORTS_IPV6,
CommonUtil.translateIntArray(getIpv6Ports()));
editor.putInt(Constants.CONFIG_CURRENT_INDEX_IPV6, mCurrentServerIndexForV6);
editor.putInt(Constants.CONFIG_LAST_INDEX_IPV6, mLastOkServerIndexForV6);
editor.putLong(Constants.CONFIG_SERVERS_LAST_UPDATED_TIME, mServerIpsLastUpdatedTime);
editor.putString(Constants.CONFIG_CURRENT_SERVER_REGION, getRegion());
}
}

View File

@@ -0,0 +1,10 @@
package com.newsdk.sdk.android.httpdns.config;
import android.content.SharedPreferences;
public interface SpCacheItem {
void restoreFromCache(SharedPreferences sp);
void saveToCache(SharedPreferences.Editor editor);
}

View File

@@ -0,0 +1,33 @@
package com.newsdk.sdk.android.httpdns.config.region;
import com.newsdk.sdk.android.httpdns.config.RegionServer;
import com.newsdk.sdk.android.httpdns.utils.Constants;
public class AmericaRegionServer {
private static final String [] SERVER_IPS = new String [] {
"47.246.131.175",
"47.246.131.141"
};
private static final int[] PORTS = null;
private static final String[] IPV6_SERVER_IPS = new String [] {
"2404:2280:4000::2bb",
"2404:2280:4000::23e"
};
private static final int[] IPV6_PORTS = null;
private static final String[] UPDATE_SERVER = new String[] {
"resolvers-us.httpdns.Newcs.com"
};
private static final String[] IPV6_UPDATE_SERVER = new String[] {
"resolvers-us.httpdns.Newcs.com"
};
public static RegionServer getInitServer() {
return new RegionServer(SERVER_IPS, PORTS, IPV6_SERVER_IPS, IPV6_PORTS, Constants.REGION_US);
}
public static RegionServer getUpdateServer() {
return new RegionServer(UPDATE_SERVER, Constants.NO_PORTS, IPV6_UPDATE_SERVER, Constants.NO_PORTS, Constants.REGION_US);
}
}

View File

@@ -0,0 +1,39 @@
package com.newsdk.sdk.android.httpdns.config.region;
import com.newsdk.sdk.android.httpdns.config.RegionServer;
import com.newsdk.sdk.android.httpdns.utils.Constants;
public final class DefaultRegionServer {
private static final String [] SERVER_IPS = new String [] {
"203.107.1.1",
"203.107.1.97",
"203.107.1.100",
"203.119.238.240",
"106.11.25.239",
"59.82.99.47"
};
private static final int[] PORTS = null;
private static final String[] IPV6_SERVER_IPS = new String [] {
"2401:b180:7001::31d",
"2408:4003:1f40::30a",
"2401:b180:2000:20::10",
"2401:b180:2000:30::1c"
};
private static final int[] IPV6_PORTS = null;
private static final String[] UPDATE_SERVER = new String[] {
"resolvers-cn.httpdns.Newcs.com"
};
private static final String[] IPV6_UPDATE_SERVER = new String[] {
"resolvers-cn.httpdns.Newcs.com"
};
public static RegionServer getInitServer() {
return new RegionServer(SERVER_IPS, PORTS, IPV6_SERVER_IPS, IPV6_PORTS, Constants.REGION_DEFAULT);
}
public static RegionServer getUpdateServer() {
return new RegionServer(UPDATE_SERVER, Constants.NO_PORTS, IPV6_UPDATE_SERVER, Constants.NO_PORTS, Constants.REGION_DEFAULT);
}
}

View File

@@ -0,0 +1,34 @@
package com.newsdk.sdk.android.httpdns.config.region;
import com.newsdk.sdk.android.httpdns.config.RegionServer;
import com.newsdk.sdk.android.httpdns.utils.Constants;
public class GermanyRegionServer {
private static final String [] SERVER_IPS = new String [] {
"47.89.80.182",
"47.246.146.77"
};
private static final int[] PORTS = null;
private static final String[] IPV6_SERVER_IPS = new String [] {
"2404:2280:3000::176",
"2404:2280:3000::188"
};
private static final int[] IPV6_PORTS = null;
private static final String[] UPDATE_SERVER = new String[] {
"resolvers-de.httpdns.Newcs.com"
};
private static final String[] IPV6_UPDATE_SERVER = new String[] {
"resolvers-de.httpdns.Newcs.com"
};
public static RegionServer getInitServer() {
return new RegionServer(SERVER_IPS, PORTS, IPV6_SERVER_IPS, IPV6_PORTS, Constants.REGION_DE);
}
public static RegionServer getUpdateServer() {
return new RegionServer(UPDATE_SERVER, Constants.NO_PORTS, IPV6_UPDATE_SERVER, Constants.NO_PORTS, Constants.REGION_DE);
}
}

View File

@@ -0,0 +1,33 @@
package com.newsdk.sdk.android.httpdns.config.region;
import com.newsdk.sdk.android.httpdns.config.RegionServer;
import com.newsdk.sdk.android.httpdns.utils.Constants;
public class HongKongRegionServer {
private static final String[] SERVER_IPS = new String[] {
"47.56.234.194",
"47.56.119.115"
};
private static final int[] PORTS = null;
private static final String[] IPV6_SERVER_IPS = new String[] {
"240b:4000:f10::178",
"240b:4000:f10::188"
};
private static final int[] IPV6_PORTS = null;
private static final String[] UPDATE_SERVER = new String[] {
"resolvers-hk.httpdns.Newcs.com"
};
private static final String[] IPV6_UPDATE_SERVER = new String[] {
"resolvers-hk.httpdns.Newcs.com"
};
public static RegionServer getInitServer() {
return new RegionServer(SERVER_IPS, PORTS, IPV6_SERVER_IPS, IPV6_PORTS, Constants.REGION_HK);
}
public static RegionServer getUpdateServer() {
return new RegionServer(UPDATE_SERVER, Constants.NO_PORTS, IPV6_UPDATE_SERVER, Constants.NO_PORTS, Constants.REGION_HK);
}
}

View File

@@ -0,0 +1,31 @@
package com.newsdk.sdk.android.httpdns.config.region;
import com.newsdk.sdk.android.httpdns.config.RegionServer;
import com.newsdk.sdk.android.httpdns.utils.Constants;
public class PreReleaseRegionServer {
private static final String [] SERVER_IPS = new String [] {
"106.11.190.18"
};
private static final int[] PORTS = null;
private static final String[] IPV6_SERVER_IPS = new String [] {
"resolvers-cn-pre.httpdns.Newcs.com"
};
private static final int[] IPV6_PORTS = null;
private static final String[] UPDATE_SERVER = new String[] {
"resolvers-cn-pre.httpdns.Newcs.com"
};
private static final String[] IPV6_UPDATE_SERVER = new String[] {
"resolvers-cn-pre.httpdns.Newcs.com"
};
public static RegionServer getInitServer() {
return new RegionServer(SERVER_IPS, PORTS, IPV6_SERVER_IPS, IPV6_PORTS, Constants.REGION_DEBUG_PRE);
}
public static RegionServer getUpdateServer() {
return new RegionServer(UPDATE_SERVER, Constants.NO_PORTS, IPV6_UPDATE_SERVER, Constants.NO_PORTS, Constants.REGION_DEBUG_PRE);
}
}

View File

@@ -0,0 +1,77 @@
package com.newsdk.sdk.android.httpdns.config.region;
import com.newsdk.sdk.android.httpdns.config.RegionServer;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.utils.Constants;
public class RegionServerManager {
public static RegionServer getInitServer(String region) {
RegionServer regionServer = null;
switch (region) {
case Constants.REGION_HK:
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("use hk region");
}
regionServer = HongKongRegionServer.getInitServer();
break;
case Constants.REGION_SG:
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("use sg region");
}
regionServer = SingaporeRegionServer.getInitServer();
break;
case Constants.REGION_DE:
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("use de region");
}
regionServer = GermanyRegionServer.getInitServer();
break;
case Constants.REGION_US:
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("use us region");
}
regionServer = AmericaRegionServer.getInitServer();
break;
case Constants.REGION_DEBUG_PRE:
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("use pre region");
}
regionServer = PreReleaseRegionServer.getInitServer();
break;
default:
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("use default region");
}
regionServer = DefaultRegionServer.getInitServer();
break;
}
return regionServer;
}
public static RegionServer getUpdateServer(String region) {
RegionServer regionServer = null;
switch (region) {
case Constants.REGION_HK:
regionServer = HongKongRegionServer.getUpdateServer();
break;
case Constants.REGION_SG:
regionServer = SingaporeRegionServer.getUpdateServer();
break;
case Constants.REGION_DE:
regionServer = GermanyRegionServer.getUpdateServer();
break;
case Constants.REGION_US:
regionServer = AmericaRegionServer.getUpdateServer();
break;
case Constants.REGION_DEBUG_PRE:
regionServer = PreReleaseRegionServer.getUpdateServer();
break;
default:
regionServer = DefaultRegionServer.getUpdateServer();
}
return regionServer;
}
}

View File

@@ -0,0 +1,33 @@
package com.newsdk.sdk.android.httpdns.config.region;
import com.newsdk.sdk.android.httpdns.config.RegionServer;
import com.newsdk.sdk.android.httpdns.utils.Constants;
public class SingaporeRegionServer {
private static final String[] SERVER_IPS = new String[] {
"161.117.200.122",
"47.74.222.190"
};
private static final int[] PORTS = null;
private static final String[] IPV6_SERVER_IPS = new String[] {
"240b:4000:f10::178",
"240b:4000:f10::188"
};
private static final int[] IPV6_PORTS = null;
private static final String[] UPDATE_SERVER = new String[] {
"resolvers-sg.httpdns.Newcs.com"
};
private static final String[] IPV6_UPDATE_SERVER = new String[] {
"resolvers-sg.httpdns.Newcs.com"
};
public static RegionServer getInitServer() {
return new RegionServer(SERVER_IPS, PORTS, IPV6_SERVER_IPS, IPV6_PORTS, Constants.REGION_SG);
}
public static RegionServer getUpdateServer() {
return new RegionServer(UPDATE_SERVER, Constants.NO_PORTS, IPV6_UPDATE_SERVER, Constants.NO_PORTS, Constants.REGION_SG);
}
}

View File

@@ -0,0 +1,22 @@
package com.newsdk.sdk.android.httpdns.exception;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
public class HttpDnsUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
// 澶勭悊鎵€鏈夋湭鎹曡幏寮傚父
public void uncaughtException(Thread thread, Throwable ex) {
try {
HttpDnsLog.e("Catch an uncaught exception, " + thread.getName() + ", error message: "
+ ex.getMessage(), ex);
reportUncaughtError(ex);
ex.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private void reportUncaughtError(Throwable ex) {
}
}

View File

@@ -0,0 +1,9 @@
package com.newsdk.sdk.android.httpdns.exception;
public class InitException extends RuntimeException {
public InitException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,164 @@
package com.newsdk.sdk.android.httpdns.impl;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
/**
* AES 加密解密工具类
* @author renwei
* @date 2025/3/26
*/
public class AESEncryptService {
private static final int GCM_IV_LENGTH = 12;
private static final int CBC_IV_LENGTH = 16;
private static final int GCM_TAG_LENGTH = 128;
private String aesSecretKey;
/**
* 加密方法
*/
public String encrypt(String data, EncryptionMode mode) {
if (EncryptionMode.PLAIN == mode) {
return "";
}
if (TextUtils.isEmpty(aesSecretKey)) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("aesSecretKey为空");
}
return "";
}
if (TextUtils.isEmpty(data)) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("待加密数据为空");
}
return "";
}
// 生成IV
SecureRandom random = new SecureRandom();
byte[] iv = new byte[mode == EncryptionMode.AES_GCM ? GCM_IV_LENGTH : CBC_IV_LENGTH];
random.nextBytes(iv);
String encryptStr = "";
try {
byte[] encrypted = mode == EncryptionMode.AES_GCM ? aesGcmEncrypt(data, iv) : aesCbcEncrypt(data, iv);
// 组合IV和密文
byte[] combined = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
encryptStr = CommonUtil.encodeHexString(combined);
} catch (Exception e) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.e("加密失败, 加密内容:" + data);
}
}
return encryptStr;
}
private byte[] aesGcmEncrypt(String plainText, byte[] iv) throws Exception {
byte[] key = CommonUtil.decodeHex(aesSecretKey);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKey secretKey = new SecretKeySpec(key, "AES");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); // 认证标签长度为 128 位
cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);
return cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
}
private byte[] aesCbcEncrypt(String plainText, byte[] iv) throws Exception {
byte[] key = CommonUtil.decodeHex(aesSecretKey);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //
SecretKey secretKey = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv); // IV 必须为 16 字节
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
return cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
}
/**
* 解密方法
*/
public String decrypt(String encryptData, EncryptionMode mode) {
if (EncryptionMode.PLAIN == mode) {
return encryptData;
}
if (TextUtils.isEmpty(aesSecretKey)) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("aesSecretKey为空");
}
return "";
}
if (TextUtils.isEmpty(encryptData)) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("待解密数据为空");
}
return "";
}
String plainData = "";
try {
byte[] binaryencrypted = CommonUtil.decodeBase64(encryptData);
plainData = EncryptionMode.AES_GCM == mode ? aesGcmDecrypt(binaryencrypted): aesCbcDecrypt(binaryencrypted);
} catch (Exception e) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.e("解密失败, 待解密数据: " + encryptData);
}
}
return plainData;
}
private String aesCbcDecrypt(byte[] binaryencrypted) throws Exception {
byte[] key = CommonUtil.decodeHex(aesSecretKey);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(Arrays.copyOfRange(binaryencrypted, 0, 16));
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decrypted = cipher.doFinal(Arrays.copyOfRange(binaryencrypted, 16, binaryencrypted.length));
return new String(decrypted, StandardCharsets.UTF_8);
}
private String aesGcmDecrypt(byte[] binaryencrypted) throws Exception {
byte[] key = CommonUtil.decodeHex(aesSecretKey);
SecretKey secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, Arrays.copyOfRange(binaryencrypted, 0, 12)); // 认证标签长度为 128 位
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
byte[] decrypted = cipher.doFinal(Arrays.copyOfRange(binaryencrypted, 12, binaryencrypted.length));
return new String(decrypted, StandardCharsets.UTF_8);
}
public Boolean isEncryptionMode(){
return !TextUtils.isEmpty(aesSecretKey);
}
public void setAesSecretKey(String aesSecretKey) {
this.aesSecretKey = aesSecretKey;
}
public enum EncryptionMode {
PLAIN("0"), AES_CBC("1"), AES_GCM("2");
private final String mode;
EncryptionMode(String mode) {
this.mode = mode;
}
public String getMode(){
return mode;
}
}
}

View File

@@ -0,0 +1,179 @@
package com.newsdk.sdk.android.httpdns.impl;
import com.newsdk.sdk.android.httpdns.HTTPDNSResult;
import com.newsdk.sdk.android.httpdns.HttpDnsCallback;
import com.newsdk.sdk.android.httpdns.HttpDnsService;
import com.newsdk.sdk.android.httpdns.Region;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.SyncService;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.utils.Constants;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class ErrorImpl implements HttpDnsService, SyncService {
@Override
public void setPreResolveHosts(List<String> hostList) {
}
@Override
public void setPreResolveHosts(List<String> hostList, RequestIpType requestIpType) {
}
@Override
public String getIpByHostAsync(String host) {
HttpDnsLog.w("init error");
return null;
}
@Override
public String getIPv4ForHostAsync(String host) {
return null;
}
@Override
public String[] getIpsByHostAsync(String host) {
HttpDnsLog.w("init error");
return new String[0];
}
@Override
public String[] getIPv4ListForHostAsync(String host) {
return new String[0];
}
@Override
public String[] getIPv6sByHostAsync(String host) {
HttpDnsLog.w("init error");
return new String[0];
}
@Override
public String[] getIPv6ListForHostASync(String host) {
return new String[0];
}
@Override
public HTTPDNSResult getAllByHostAsync(String host) {
HttpDnsLog.w("init error");
return Constants.EMPTY;
}
@Override
public HTTPDNSResult getHttpDnsResultForHostAsync(String host) {
return Constants.EMPTY;
}
@Override
public HTTPDNSResult getIpsByHostAsync(String host, RequestIpType type) {
return Constants.EMPTY;
}
@Override
public HTTPDNSResult getHttpDnsResultForHostAsync(String host, RequestIpType type) {
return Constants.EMPTY;
}
@Override
public void setAuthCurrentTime(long time) {
}
@Override
public String getSessionId() {
return null;
}
@Override
public HTTPDNSResult getIpsByHostAsync(String host, Map<String, String> params,
String cacheKey) {
HttpDnsLog.w("init error");
return Constants.EMPTY;
}
@Override
public HTTPDNSResult getHttpDnsResultForHostAsync(String host, Map<String, String> params,
String cacheKey) {
return Constants.EMPTY;
}
@Override
public HTTPDNSResult getIpsByHostAsync(String host, RequestIpType type,
Map<String, String> params, String cacheKey) {
HttpDnsLog.w("init error");
return Constants.EMPTY;
}
@Override
public HTTPDNSResult getHttpDnsResultForHostAsync(String host, RequestIpType type,
Map<String, String> params, String cacheKey) {
return Constants.EMPTY;
}
@Override
public HTTPDNSResult getHttpDnsResultForHostSync(String host, RequestIpType type, Map<String, String> params, String cacheKey) {
return Constants.EMPTY;
}
@Override
public void getHttpDnsResultForHostAsync(String host, RequestIpType type, Map<String, String> params, String cacheKey, HttpDnsCallback callback) {
}
@Override
public HTTPDNSResult getHttpDnsResultForHostSyncNonBlocking(String host, RequestIpType type, Map<String, String> params, String cacheKey) {
return Constants.EMPTY;
}
@Override
public void setRegion(String region) {
}
@Override
public void setRegion(Region region) {
}
@Override
public String getIPv6ByHostAsync(String host) {
HttpDnsLog.w("init error");
return null;
}
@Override
public String getIPv6ForHostAsync(String host) {
return null;
}
@Override
public HTTPDNSResult getByHost(String host, RequestIpType type) {
HttpDnsLog.w("init error");
return Constants.EMPTY;
}
@Override
public void cleanHostCache(ArrayList<String> hosts) {
}
@Override
public HTTPDNSResult getHttpDnsResultForHostSync(String host, RequestIpType type) {
return Constants.EMPTY;
}
@Override
public void getHttpDnsResultForHostAsync(String host, RequestIpType type, HttpDnsCallback callback) {
}
@Override
public HTTPDNSResult getHttpDnsResultForHostSyncNonBlocking(String host, RequestIpType type) {
return Constants.EMPTY;
}
}

View File

@@ -0,0 +1,162 @@
package com.newsdk.sdk.android.httpdns.impl;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import com.newsdk.sdk.android.httpdns.RequestIpType;
public class HostResolveLocker {
private static class Recorder {
private final HashSet<String> mV4ResolvingHost = new HashSet<>();
private final HashSet<String> mV6ResolvingHost = new HashSet<>();
private final HashSet<String> mBothResolvingHost = new HashSet<>();
private final HashMap<String, CountDownLatch> mV4Latchs = new HashMap<>();
private final HashMap<String, CountDownLatch> mV6Latchs = new HashMap<>();
private final HashMap<String, CountDownLatch> mBothLatchs = new HashMap<>();
private final Object mLock = new Object();
public boolean beginResolve(String host, RequestIpType type) {
if (type == RequestIpType.both) {
if (mBothResolvingHost.contains(host)) {
// 姝e湪瑙f瀽
return false;
} else {
synchronized (mLock) {
if (mBothResolvingHost.contains(host)) {
// 姝e湪瑙f瀽
return false;
} else {
mBothResolvingHost.add(host);
createLatch(host, mBothLatchs);
return true;
}
}
}
} else if (type == RequestIpType.v4) {
if (mV4ResolvingHost.contains(host)) {
return false;
} else {
synchronized (mLock) {
if (mV4ResolvingHost.contains(host)) {
return false;
} else {
mV4ResolvingHost.add(host);
createLatch(host, mV4Latchs);
return true;
}
}
}
} else if (type == RequestIpType.v6) {
if (mV6ResolvingHost.contains(host)) {
return false;
} else {
synchronized (mLock) {
if (mV6ResolvingHost.contains(host)) {
return false;
} else {
mV6ResolvingHost.add(host);
createLatch(host, mV6Latchs);
return true;
}
}
}
}
return false;
}
private void createLatch(String host, HashMap<String, CountDownLatch> latchs) {
CountDownLatch countDownLatch = new CountDownLatch(1);
latchs.put(host, countDownLatch);
}
private void countDownLatch(String host, HashMap<String, CountDownLatch> latchs) {
CountDownLatch latch = latchs.get(host);
if (latch != null) {
latch.countDown();
}
}
private CountDownLatch getLatch(String host, RequestIpType type) {
switch (type) {
case v4:
return mV4Latchs.get(host);
case v6:
return mV6Latchs.get(host);
case both:
return mBothLatchs.get(host);
}
return null;
}
public void endResolve(String host, RequestIpType type) {
switch (type) {
case v4:
mV4ResolvingHost.remove(host);
countDownLatch(host, mV4Latchs);
break;
case v6:
mV6ResolvingHost.remove(host);
countDownLatch(host, mV6Latchs);
break;
case both:
mBothResolvingHost.remove(host);
countDownLatch(host, mBothLatchs);
break;
}
}
public boolean await(String host, RequestIpType type, long timeout, TimeUnit unit)
throws InterruptedException {
CountDownLatch countDownLatch = getLatch(host, type);
if (countDownLatch != null) {
return countDownLatch.await(timeout, unit);
} else {
return true;
}
}
}
private final Object mLock = new Object();
private final Recorder mDefaultRecorder = new Recorder();
private final HashMap<String, Recorder> mRecorders = new HashMap<>();
public boolean beginResolve(String host, RequestIpType type, String cacheKey) {
Recorder recorder = getRecorder(cacheKey);
return recorder.beginResolve(host, type);
}
private Recorder getRecorder(String cacheKey) {
Recorder recorder;
if (cacheKey == null || cacheKey.isEmpty()) {
recorder = mDefaultRecorder;
} else {
recorder = mRecorders.get(cacheKey);
if (recorder == null) {
synchronized (mLock) {
recorder = mRecorders.get(cacheKey);
if (recorder == null) {
recorder = new Recorder();
mRecorders.put(cacheKey, recorder);
}
}
}
}
return recorder;
}
public void endResolve(String host, RequestIpType type, String cacheKey) {
Recorder recorder = getRecorder(cacheKey);
recorder.endResolve(host, type);
}
public boolean await(String host, RequestIpType type, String cacheKey, long timeout,
TimeUnit unit) throws InterruptedException {
Recorder recorder = getRecorder(cacheKey);
return recorder.await(host, type, timeout, unit);
}
}

View File

@@ -0,0 +1,120 @@
package com.newsdk.sdk.android.httpdns.impl;
import java.util.HashMap;
import java.util.HashSet;
import com.newsdk.sdk.android.httpdns.RequestIpType;
public class HostResolveRecorder {
private static class Recorder {
private final HashSet<String> mV4ResolvingHost = new HashSet<>();
private final HashSet<String> mV6ResolvingHost = new HashSet<>();
private final HashSet<String> mBothResolvingHost = new HashSet<>();
private final Object mLock = new Object();
public boolean beginResolve(String host, RequestIpType type) {
if (type == RequestIpType.both) {
if (mBothResolvingHost.contains(host) || (mV4ResolvingHost.contains(host)
&& mV6ResolvingHost.contains(host))) {
// 姝e湪瑙f瀽
return false;
} else {
synchronized (mLock) {
if (mBothResolvingHost.contains(host) || (mV4ResolvingHost.contains(host)
&& mV6ResolvingHost.contains(host))) {
// 姝e湪瑙f瀽
return false;
} else {
mBothResolvingHost.add(host);
return true;
}
}
}
} else if (type == RequestIpType.v4) {
if (mV4ResolvingHost.contains(host) || mBothResolvingHost.contains(host)) {
return false;
} else {
synchronized (mLock) {
if (mV4ResolvingHost.contains(host) || mBothResolvingHost.contains(host)) {
return false;
} else {
mV4ResolvingHost.add(host);
return true;
}
}
}
} else if (type == RequestIpType.v6) {
if (mV6ResolvingHost.contains(host) || mBothResolvingHost.contains(host)) {
return false;
} else {
synchronized (mLock) {
if (mV6ResolvingHost.contains(host) || mBothResolvingHost.contains(host)) {
return false;
} else {
mV6ResolvingHost.add(host);
return true;
}
}
}
}
return false;
}
public void endResolve(String host, RequestIpType type) {
switch (type) {
case v4:
mV4ResolvingHost.remove(host);
break;
case v6:
mV6ResolvingHost.remove(host);
break;
case both:
mBothResolvingHost.remove(host);
break;
}
}
}
private final Object mLock = new Object();
private final Recorder mDefaultRecorder = new Recorder();
private final HashMap<String, Recorder> mRecorderHashMap = new HashMap<>();
public boolean beginResolve(String host, RequestIpType type) {
return beginResolve(host, type, null);
}
public void endResolve(String host, RequestIpType type) {
endResolve(host, type, null);
}
public boolean beginResolve(String host, RequestIpType type, String cacheKey) {
Recorder recorder = getRecorder(cacheKey);
return recorder.beginResolve(host, type);
}
private Recorder getRecorder(String cacheKey) {
Recorder recorder = null;
if (cacheKey == null || cacheKey.isEmpty()) {
recorder = mDefaultRecorder;
} else {
recorder = mRecorderHashMap.get(cacheKey);
if (recorder == null) {
synchronized (mLock) {
recorder = mRecorderHashMap.get(cacheKey);
if (recorder == null) {
recorder = new Recorder();
mRecorderHashMap.put(cacheKey, recorder);
}
}
}
}
return recorder;
}
public void endResolve(String host, RequestIpType type, String cacheKey) {
Recorder recorder = getRecorder(cacheKey);
recorder.endResolve(host, type);
}
}

View File

@@ -0,0 +1,432 @@
package com.newsdk.sdk.android.httpdns.impl;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import com.newsdk.sdk.android.httpdns.BuildConfig;
import com.newsdk.sdk.android.httpdns.HttpDnsSettings;
import com.newsdk.sdk.android.httpdns.InitConfig;
import com.newsdk.sdk.android.httpdns.config.ConfigCacheHelper;
import com.newsdk.sdk.android.httpdns.config.RegionServer;
import com.newsdk.sdk.android.httpdns.config.ServerConfig;
import com.newsdk.sdk.android.httpdns.config.region.RegionServerManager;
import com.newsdk.sdk.android.httpdns.config.SpCacheItem;
import com.newsdk.sdk.android.httpdns.observable.ObservableConfig;
import com.newsdk.sdk.android.httpdns.observable.ObservableConstants;
import com.newsdk.sdk.android.httpdns.observable.ObservableManager;
import com.newsdk.sdk.android.httpdns.request.HttpRequestConfig;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
import com.newsdk.sdk.android.httpdns.utils.Constants;
import com.newsdk.sdk.android.httpdns.utils.ThreadUtil;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
/**
* httpdns鐨勯厤缃?
*/
public class HttpDnsConfig implements SpCacheItem {
private final Context mContext;
private boolean mEnabled = Constants.DEFAULT_SDK_ENABLE;
/**
* 鍒濆鏈嶅姟鑺傜偣
*/
private RegionServer mInitServer;
/**
* 鍏滃簳鐨勮皟搴︽湇鍔P锛岀敤浜庡簲瀵瑰浗闄呯増鏈嶅姟IP鏈夊彲鑳戒笉绋冲畾鐨勬儏鍐?
*/
private RegionServer mDefaultUpdateServer;
/**
* 褰撳墠鏈嶅姟鑺傜偣
*/
private final ServerConfig mCurrentServer;
/**
* 鐢ㄦ埛鐨刟ccountId
*/
private final String mAccountId;
/**
* 褰撳墠璇锋眰浣跨敤鐨剆chema
*/
private String mSchema = Constants.DEFAULT_SCHEMA;
/**
* 褰撳墠region
*/
private String mRegion;
/**
* 瓒呮椂鏃堕暱
*/
private int mTimeout = Constants.DEFAULT_TIMEOUT;
/**
* 鏄惁绂佺敤鏈嶅姟锛屼互閬垮厤宕╂簝
*/
private boolean mHitCrashDefend;
/**
* 鏄惁杩滅▼绂佺敤鏈嶅姟
*/
private boolean mRemoteDisabled = false;
/**
* 鏄惁绂佺敤probe鑳藉姏
*/
private boolean mIPRankingDisabled = false;
/**
* 鏄惁寮€鍚檷绾у埌Local Dns
*/
private boolean mEnableDegradationLocalDns = Constants.DEFAULT_ENABLE_DEGRADATION_LOCAL_DNS;
/**
* 缃戠粶鎺㈡祴鎺ュ彛
*/
private HttpDnsSettings.NetworkDetector mNetworkDetector = null;
private final ConfigCacheHelper mCacheHelper;
protected ExecutorService mWorker = ThreadUtil.createExecutorService();
protected ExecutorService mResolveWorker = ThreadUtil.createResolveExecutorService();
protected ExecutorService mDbWorker = ThreadUtil.createDBExecutorService();
private ObservableConfig mObservableConfig;
private ObservableManager mObservableManager;
private float mObservableSampleBenchMarks;
private String mBizTags;
private String mUA;
public HttpDnsConfig(Context context, String accountId, String secret) {
mContext = context;
mAccountId = accountId;
if (mContext != null) {
mUA = buildUA();
}
//region鎻愬墠璁剧疆
mRegion = getInitRegion(accountId);
mInitServer = RegionServerManager.getInitServer(mRegion);
mDefaultUpdateServer = RegionServerManager.getUpdateServer(mRegion);
mCurrentServer = new ServerConfig(this, mInitServer.getServerIps(), mInitServer.getPorts(), mInitServer.getIpv6ServerIps(), mInitServer.getIpv6Ports());
mObservableConfig = new ObservableConfig();
// 鍏堜粠缂撳瓨璇诲彇鏁版嵁锛屽啀璧嬪€糲acheHelper锛?閬垮厤鍦ㄨ鍙栫紦瀛樿繃绋嬩腑锛岃Е鍙戝啓缂撳瓨鎿嶄綔
ConfigCacheHelper helper = new ConfigCacheHelper();
if (context != null) {
helper.restoreFromCache(context, this);
}
mCacheHelper = helper;
mObservableManager = new ObservableManager(this, secret);
}
public Context getContext() {
return mContext;
}
public String getAccountId() {
return mAccountId;
}
public ServerConfig getCurrentServer() {
return mCurrentServer;
}
public ObservableConfig getObservableConfig() {
return mObservableConfig;
}
public ObservableManager getObservableManager() {
return mObservableManager;
}
public float getObservableSampleBenchMarks() {
return mObservableSampleBenchMarks;
}
public void setObservableSampleBenchMarks(float benchMarks) {
if (mObservableSampleBenchMarks != benchMarks) {
mObservableSampleBenchMarks = benchMarks;
saveToCache();
}
}
public boolean isCurrentRegionMatch() {
return CommonUtil.regionEquals(mRegion, mCurrentServer.getRegion());
}
public boolean isAllInitServer() {
return mInitServer.serverEquals((RegionServer)mCurrentServer);
}
public String getRegion() {
return mRegion;
}
public boolean isEnabled() {
return mEnabled && !mHitCrashDefend && !mRemoteDisabled;
}
/**
* 鏄惁鍚敤httpdns
* <p>
* 娉ㄦ剰鏄?姘镐箙绂佺敤锛屽洜涓虹紦瀛樼殑鍘熷洜锛屼竴鏃︾鐢紝灏辨病鏈夋満浼氬惎鐢ㄤ簡
*/
public void setEnabled(boolean enabled) {
if (this.mEnabled != enabled) {
this.mEnabled = enabled;
saveToCache();
}
}
public int getTimeout() {
return mTimeout;
}
public void setTimeout(int timeout) {
if (this.mTimeout != timeout) {
this.mTimeout = timeout;
saveToCache();
}
}
public String getBizTags() {
return mBizTags;
}
public void setBizTags(String tags) {
mBizTags = tags;
}
public String getSchema() {
return mSchema;
}
public ExecutorService getWorker() {
return mWorker;
}
public ExecutorService getResolveWorker() {
return mResolveWorker;
}
public ExecutorService getDbWorker() {
return mDbWorker;
}
public void setWorker(ExecutorService worker) {
// 缁欐祴璇曚娇鐢?
this.mWorker = worker;
this.mDbWorker = worker;
mResolveWorker = worker;
}
/**
* 鍒囨崲https
*
* @return 閰嶇疆鏄惁鍙樺寲
*/
public boolean setHTTPSRequestEnabled(boolean enabled) {
String oldSchema = mSchema;
if (enabled) {
mSchema = HttpRequestConfig.HTTPS_SCHEMA;
} else {
mSchema = HttpRequestConfig.HTTP_SCHEMA;
}
if (!mSchema.equals(oldSchema)) {
saveToCache();
}
return !mSchema.equals(oldSchema);
}
public void setEnableDegradationLocalDns(boolean enable) {
mEnableDegradationLocalDns = enable;
}
public boolean isEnableDegradationLocalDns() {
return mEnableDegradationLocalDns;
}
/**
* 璁剧疆鐢ㄦ埛鍒囨崲鐨剅egion
*/
public boolean setRegion(String region) {
if (!mRegion.equals(region)) {
mRegion = region;
mInitServer = RegionServerManager.getInitServer(mRegion);
mDefaultUpdateServer = RegionServerManager.getUpdateServer(mRegion);
mCurrentServer.setServerIps(mRegion, mInitServer.getServerIps(), mInitServer.getPorts(), mInitServer.getIpv6ServerIps(), mInitServer.getIpv6Ports());
return true;
}
return false;
}
/**
* 鑾峰彇ipv6鐨勬湇鍔¤妭鐐?
*/
public String[] getIpv6ServerIps() {
return this.mCurrentServer.getIpv6ServerIps();
}
public RegionServer getInitServer() {
return this.mInitServer;
}
public RegionServer getDefaultUpdateServer() {
return mDefaultUpdateServer;
}
public String[] getDefaultIpv6UpdateServer() {
return mDefaultUpdateServer.getIpv6ServerIps();
}
public String getUA() {
return mUA;
}
@Override
public boolean equals(Object o) {
if (this == o) {return true;}
if (o == null || getClass() != o.getClass()) {return false;}
HttpDnsConfig that = (HttpDnsConfig)o;
return mEnabled == that.mEnabled &&
mTimeout == that.mTimeout &&
mHitCrashDefend == that.mHitCrashDefend &&
mRemoteDisabled == that.mRemoteDisabled &&
mIPRankingDisabled == that.mIPRankingDisabled &&
CommonUtil.equals(mContext, that.mContext) &&
CommonUtil.equals(mInitServer, that.mInitServer) &&
CommonUtil.equals(mDefaultUpdateServer, that.mDefaultUpdateServer) &&
CommonUtil.equals(mCurrentServer, that.mCurrentServer) &&
CommonUtil.equals(mAccountId, that.mAccountId) &&
CommonUtil.equals(mSchema, that.mSchema) &&
CommonUtil.equals(mRegion, that.mRegion) &&
CommonUtil.equals(mCacheHelper, that.mCacheHelper) &&
CommonUtil.equals(mWorker, that.mWorker) &&
CommonUtil.equals(mResolveWorker, that.mResolveWorker) &&
CommonUtil.equals(mDbWorker, that.mDbWorker);
}
@Override
public int hashCode() {
return Arrays.hashCode(
new Object[] {mContext, mEnabled, mInitServer, mDefaultUpdateServer, mCurrentServer,
mAccountId, mSchema, mRegion, mTimeout, mHitCrashDefend, mRemoteDisabled,
mIPRankingDisabled,
mCacheHelper, mWorker, mResolveWorker, mDbWorker});
}
/**
* 璁剧疆鍒濆鏈嶅姟IP
* <p>
* 绾夸笂SDK 鍒濆鍖栨湇鍔P鏄唴缃啓姝荤殑銆?
* 鏈珹PI涓昏鐢ㄤ簬涓€浜涙祴璇曚唬鐮佷娇鐢?
*
*/
public void setInitServers(String initRegion, String[] initIps, int[] initPorts,
String[] initIpv6s, int[] initV6Ports) {
this.mRegion = initRegion;
if (initIps == null) {
return;
}
String[] oldInitServerIps = this.mInitServer.getServerIps();
int[] oldInitPorts = this.mInitServer.getPorts();
String[] oldInitIpv6ServerIps = this.mInitServer.getIpv6ServerIps();
int[] oldInitIpv6Ports = this.mInitServer.getIpv6Ports();
this.mInitServer.updateAll(initRegion, initIps, initPorts, initIpv6s, initV6Ports);
if (mCurrentServer.getServerIps() == null
|| mCurrentServer.getIpv6ServerIps() == null
|| (CommonUtil.isSameServer(oldInitServerIps, oldInitPorts,
mCurrentServer.getServerIps(), mCurrentServer.getPorts())
&& CommonUtil.isSameServer(oldInitIpv6ServerIps, oldInitIpv6Ports,
mCurrentServer.getIpv6ServerIps(), mCurrentServer.getIpv6Ports()))) {
mCurrentServer.setServerIps(initRegion, initIps, initPorts, initIpv6s, initV6Ports);
}
}
/**
* 璁剧疆鍏滃簳鐨勮皟搴P锛?
* 娴嬭瘯浠g爜浣跨敤
*/
public void setDefaultUpdateServer(String[] ips, int[] ports) {
this.mDefaultUpdateServer.updateRegionAndIpv4(this.mInitServer.getRegion(), ips, ports);
}
public void setDefaultUpdateServerIpv6(String[] defaultServerIps, int[] ports) {
this.mDefaultUpdateServer.updateIpv6(defaultServerIps, ports);
}
public void crashDefend(boolean crashDefend) {
this.mHitCrashDefend = crashDefend;
}
public void remoteDisable(boolean disable) {
this.mRemoteDisabled = disable;
}
public void ipRankingDisable(boolean disable) {
this.mIPRankingDisabled = disable;
}
public boolean isIPRankingDisabled() {
return mIPRankingDisabled;
}
public HttpDnsSettings.NetworkDetector getNetworkDetector() {
return mNetworkDetector;
}
public void setNetworkDetector(HttpDnsSettings.NetworkDetector networkDetector) {
this.mNetworkDetector = networkDetector;
}
// 缂撳瓨鐩稿叧鐨?澶勭悊锛屾殏鏃舵斁杩欓噷
public void saveToCache() {
if (mCacheHelper != null && mContext != null) {
mCacheHelper.saveConfigToCache(mContext, this);
}
}
public SpCacheItem[] getCacheItem() {
return new SpCacheItem[] {this, mCurrentServer, mObservableConfig};
}
@Override
public void restoreFromCache(SharedPreferences sp) {
mEnabled = sp.getBoolean(Constants.CONFIG_ENABLE, Constants.DEFAULT_SDK_ENABLE);
mObservableSampleBenchMarks = sp.getFloat(Constants.CONFIG_OBSERVABLE_BENCH_MARKS, -1);
}
@Override
public void saveToCache(SharedPreferences.Editor editor) {
editor.putBoolean(Constants.CONFIG_ENABLE, mEnabled);
editor.putFloat(Constants.CONFIG_OBSERVABLE_BENCH_MARKS, mObservableSampleBenchMarks);
}
private String getInitRegion(String accountId) {
InitConfig config = InitConfig.getInitConfig(accountId);
if (config == null) {
return Constants.REGION_DEFAULT;
}
return CommonUtil.fixRegion(config.getRegion());
}
private String buildUA() {
if (mContext == null) {
return "";
}
String versionName = ObservableConstants.UNKNOWN;
try {
versionName = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
}
return Build.BRAND + "/" + Build.MODEL
+ ";" + "Android" + "/" + Build.VERSION.RELEASE
+ ";" + mContext.getPackageName() + "/" + versionName
+ ";" + "HTTPDNS" + "/" + BuildConfig.VERSION_NAME;
}
}

View File

@@ -0,0 +1,13 @@
package com.newsdk.sdk.android.httpdns.impl;
import android.content.Context;
import com.newsdk.sdk.android.httpdns.HttpDnsService;
/**
* httpdns鏈嶅姟鍒涘缓鎺ュ彛
*/
public interface HttpDnsCreator {
HttpDnsService create(Context context, String accountId, String secretKey);
}

View File

@@ -0,0 +1,43 @@
package com.newsdk.sdk.android.httpdns.impl;
import android.content.Context;
import com.newsdk.sdk.android.httpdns.HttpDnsService;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import java.util.HashMap;
/**
* HttpDnsService 瀹炰緥鎸佹湁鑰?
*/
public class HttpDnsInstanceHolder {
private final HttpDnsCreator mHttpDnsCreator;
private final HashMap<String, HttpDnsService> mInstances;
private final ErrorImpl mError = new ErrorImpl();
public HttpDnsInstanceHolder(HttpDnsCreator creator) {
this.mHttpDnsCreator = creator;
mInstances = new HashMap<>();
}
public HttpDnsService get(Context context, String account, String secretKey) {
if (account == null || account.equals("")) {
HttpDnsLog.e("init httpdns with emtpy account!!");
return mError;
}
HttpDnsService service = mInstances.get(account);
if (service == null) {
service = mHttpDnsCreator.create(context, account, secretKey);
mInstances.put(account, service);
} else {
if (service instanceof HttpDnsServiceImpl) {
((HttpDnsServiceImpl) service).setSecret(secretKey);
}
}
return service;
}
}

View File

@@ -0,0 +1,959 @@
package com.newsdk.sdk.android.httpdns.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.sdk.android.crashdefend.CrashDefendApi;
import com.alibaba.sdk.android.crashdefend.CrashDefendCallback;
import com.newsdk.sdk.android.httpdns.BuildConfig;
import com.newsdk.sdk.android.httpdns.HTTPDNSResult;
import com.newsdk.sdk.android.httpdns.HttpDnsCallback;
import com.newsdk.sdk.android.httpdns.HttpDnsService;
import com.newsdk.sdk.android.httpdns.HttpDnsSettings;
import com.newsdk.sdk.android.httpdns.InitConfig;
import com.newsdk.sdk.android.httpdns.Region;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.SyncService;
import com.newsdk.sdk.android.httpdns.cache.RecordDBHelper;
import com.newsdk.sdk.android.httpdns.observable.ObservableConstants;
import com.newsdk.sdk.android.httpdns.observable.event.CleanHostCacheEvent;
import com.newsdk.sdk.android.httpdns.resolve.HostFilter;
import com.newsdk.sdk.android.httpdns.resolve.ResolveHostCache;
import com.newsdk.sdk.android.httpdns.resolve.ResolveHostCacheGroup;
import com.newsdk.sdk.android.httpdns.resolve.ResolveHostRequestHandler;
import com.newsdk.sdk.android.httpdns.resolve.ResolveHostResultRepo;
import com.newsdk.sdk.android.httpdns.resolve.ResolveHostService;
import com.newsdk.sdk.android.httpdns.resolve.BatchResolveHostService;
import com.newsdk.sdk.android.httpdns.HTTPDNSResultWrapper;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.net.HttpDnsNetworkDetector;
import com.newsdk.sdk.android.httpdns.net.NetworkStateManager;
import com.newsdk.sdk.android.httpdns.ranking.IPRankingService;
import com.newsdk.sdk.android.httpdns.serverip.RegionServerScheduleService;
import com.newsdk.sdk.android.httpdns.serverip.RegionServerScheduleService.OnRegionServerIpUpdate;
import com.newsdk.sdk.android.httpdns.serverip.ranking.RegionServerRankingService;
import com.newsdk.sdk.android.httpdns.track.SessionTrackMgr;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
import com.newsdk.sdk.android.httpdns.utils.Constants;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Looper;
import android.text.TextUtils;
/**
* 鍩熷悕瑙f瀽鏈嶅姟 httpdns鎺ュ彛鐨勫疄鐜?
*/
public class HttpDnsServiceImpl implements HttpDnsService, OnRegionServerIpUpdate,
NetworkStateManager.OnNetworkChange, SyncService {
protected HttpDnsConfig mHttpDnsConfig;
private ResolveHostResultRepo mResultRepo;
protected ResolveHostRequestHandler mRequestHandler;
protected RegionServerScheduleService mScheduleService;
protected IPRankingService mIpIPRankingService;
protected RegionServerRankingService mRegionServerRankingService;
protected ResolveHostService mResolveHostService;
protected BatchResolveHostService mBatchResolveHostService;
private HostFilter mFilter;
private SignService mSignService;
private AESEncryptService mAESEncryptService;
private boolean resolveAfterNetworkChange = true;
private boolean mUseCustomServiceHosts = false;
/**
* crash defend 榛樿鍏抽棴
*/
private boolean mCrashDefendEnabled = false;
public static Context sContext;
public HttpDnsServiceImpl(Context context, final String accountId, String secret) {
try {
InitConfig config = InitConfig.getInitConfig(accountId);
sContext = (config != null && config.getContext() != null) ? config.getContext() : context;
secret = (config != null && config.getSecretKey() != null) ? config.getSecretKey() : secret;
mHttpDnsConfig = new HttpDnsConfig(sContext, accountId, secret);
if (sContext == null) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.e("init httpdns with null context!!");
}
mHttpDnsConfig.setEnabled(false);
return;
}
mFilter = new HostFilter();
mSignService = new SignService(secret);
mAESEncryptService = new AESEncryptService();
mIpIPRankingService = new IPRankingService(this.mHttpDnsConfig);
mRegionServerRankingService = new RegionServerRankingService(mHttpDnsConfig);
mResultRepo = new ResolveHostResultRepo(this.mHttpDnsConfig, this.mIpIPRankingService,
new RecordDBHelper(this.mHttpDnsConfig.getContext(), this.mHttpDnsConfig.getAccountId()),
new ResolveHostCacheGroup());
mScheduleService = new RegionServerScheduleService(this.mHttpDnsConfig, this);
mRequestHandler = new ResolveHostRequestHandler(mHttpDnsConfig, mScheduleService,
mSignService, mAESEncryptService);
HostResolveLocker asyncLocker = new HostResolveLocker();
mResolveHostService = new ResolveHostService(this.mHttpDnsConfig,
mIpIPRankingService,
mRequestHandler, mResultRepo, mFilter, asyncLocker);
mBatchResolveHostService = new BatchResolveHostService(this.mHttpDnsConfig, mResultRepo,
mRequestHandler,
mIpIPRankingService, mFilter, asyncLocker);
mHttpDnsConfig.setNetworkDetector(HttpDnsNetworkDetector.getInstance());
beforeInit();
setupInitConfig(accountId);
if (mCrashDefendEnabled) {
initCrashDefend(sContext, mHttpDnsConfig);
}
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.w("init fail, crash defend");
return;
}
NetworkStateManager.getInstance().init(sContext);
NetworkStateManager.getInstance().addListener(this);
tryUpdateRegionServer(sContext, accountId);
if (!mUseCustomServiceHosts) {
mRegionServerRankingService.rankServiceIp(mHttpDnsConfig.getCurrentServer());
}
favorInit(sContext, accountId);
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("httpdns service is init " + accountId);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void setupInitConfig(final String accountId) {
InitConfig config = InitConfig.getInitConfig(accountId);
if (config != null) {
// 鍏堣缃拰缃戠粶鐩稿叧鐨勫唴瀹?
this.mHttpDnsConfig.setTimeout(config.getTimeout());
this.mHttpDnsConfig.setHTTPSRequestEnabled(config.isEnableHttps());
mHttpDnsConfig.setBizTags(config.getBizTags());
mHttpDnsConfig.setEnableDegradationLocalDns(config.isEnableDegradationLocalDns());
// 鍐嶈缃竴浜涘彲浠ユ彁鍓嶏紝娌℃湁鍓綔鐢ㄧ殑鍐呭
mResolveHostService.setEnableExpiredIp(config.isEnableExpiredIp());
if (config.getIPRankingList() != null) {
mIpIPRankingService.setIPRankingList(config.getIPRankingList());
}
// 璁剧疆region 蹇呴』鍦?璇诲彇缂撳瓨涔嬪墠銆?.4.1鐗堟湰寮€濮媟egion鍒濆鍖栨彁鍓嶅埌HttpDnsConfig鍒濆鍖?
// 璁剧疆 涓荤珯鍩熷悕 闇€瑕佸湪 璇诲彇缂撳瓨涔嬪墠
this.mResultRepo.setHostListWhichIpFixed(config.getHostListWithFixedIp());
// 璁剧疆缂撳瓨鎺у埗锛屽苟璇诲彇缂撳瓨
mResultRepo.setCachedIPEnabled(config.isEnableCacheIp(), config.getExpiredThresholdMillis());
this.mResultRepo.setCacheTtlChanger(config.getCacheTtlChanger());
resolveAfterNetworkChange = config.isResolveAfterNetworkChange();
if (config.getDegradationFilter() != null) {
mFilter.setFilter(config.getDegradationFilter());
}
if (config.getNotUseHttpDnsFilter() != null) {
mFilter.setFilter(config.getNotUseHttpDnsFilter());
}
mHttpDnsConfig.getObservableManager().positiveEnableObservable(config.isEnableObservable());
mCrashDefendEnabled = config.isEnableCrashDefend();
mRequestHandler.setSdnsGlobalParams(config.getSdnsGlobalParams());
mAESEncryptService.setAesSecretKey(config.getAesSecretKey());
applyCustomServiceHosts(config);
}
}
private void applyCustomServiceHosts(InitConfig config) {
String primaryHost = config.getPrimaryServiceHost();
String backupHost = config.getBackupServiceHost();
ArrayList<String> hosts = new ArrayList<>();
if (!TextUtils.isEmpty(primaryHost)) {
hosts.add(primaryHost.trim());
}
if (!TextUtils.isEmpty(backupHost) && !backupHost.trim().equalsIgnoreCase(primaryHost == null ? "" : primaryHost.trim())) {
hosts.add(backupHost.trim());
}
if (hosts.isEmpty()) {
return;
}
String[] serverHosts = hosts.toArray(new String[0]);
int[] ports = new int[serverHosts.length];
int servicePort = config.getServicePort();
Arrays.fill(ports, servicePort > 0 ? servicePort : -1);
mHttpDnsConfig.setInitServers(mHttpDnsConfig.getRegion(), serverHosts, ports, serverHosts, ports);
mHttpDnsConfig.setDefaultUpdateServer(serverHosts, ports);
mHttpDnsConfig.setDefaultUpdateServerIpv6(serverHosts, ports);
mHttpDnsConfig.setHTTPSRequestEnabled(true);
mUseCustomServiceHosts = true;
}
protected void beforeInit() {
// only for test
}
protected void favorInit(Context context, String accountId) {
// for different favor init
}
protected void initCrashDefend(Context context, final HttpDnsConfig config) {
CrashDefendApi.registerCrashDefendSdk(context, "httpdns", BuildConfig.VERSION_NAME, 2, 7,
new CrashDefendCallback() {
@Override
public void onSdkStart(int limitCount, int crashCount, int restoreCount) {
config.crashDefend(false);
}
@Override
public void onSdkStop(int limitCount, int crashCount, int restoreCount,
long nextRestoreInterval) {
config.crashDefend(true);
HttpDnsLog.w("sdk is not safe to run");
}
@Override
public void onSdkClosed(int restoreCount) {
config.crashDefend(true);
HttpDnsLog.e("sdk will not run any more");
}
});
}
public void setSecret(String secret) {
if (!mHttpDnsConfig.isEnabled()) {
return;
}
InitConfig config = InitConfig.getInitConfig(mHttpDnsConfig.getAccountId());
secret = (config != null && config.getSecretKey() != null) ? config.getSecretKey() : secret;
this.mSignService.setSecretKey(secret);
}
@Override
public void serverIpUpdated(boolean regionUpdated) {
if (!mHttpDnsConfig.isEnabled()) {
return;
}
if (regionUpdated) {
mResultRepo.clearMemoryCache();
}
mRequestHandler.resetStatus();
//鏈嶅姟IP鏇存柊锛岃Е鍙戞湇鍔P娴嬮€?
if (!mUseCustomServiceHosts) {
mRegionServerRankingService.rankServiceIp(mHttpDnsConfig.getCurrentServer());
}
}
@Override
public void setPreResolveHosts(List<String> hostList) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return;
}
if (hostList == null || hostList.size() == 0) {
HttpDnsLog.i("setPreResolveHosts empty list");
return;
}
setPreResolveHosts(hostList, RequestIpType.v4);
}
@Override
public void setPreResolveHosts(List<String> hostList, RequestIpType requestIpType) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return;
}
if (hostList == null || hostList.size() == 0) {
HttpDnsLog.i("setPreResolveHosts empty list");
return;
}
requestIpType = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), requestIpType);
mBatchResolveHostService.batchResolveHostAsync(hostList, requestIpType);
}
@Override
public String getIpByHostAsync(String host) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return null;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return null;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return null;
}
String[] ips = getIPv4ListForHostAsync(host);
if (ips == null || ips.length == 0) {
return null;
}
return ips[0];
}
@Override
public String getIPv4ForHostAsync(String host) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return null;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return null;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return null;
}
String[] ips = getIPv4ListForHostAsync(host);
if (ips == null || ips.length == 0) {
return null;
}
return ips[0];
}
@Override
public String[] getIpsByHostAsync(final String host) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return new String[0];
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return new String[0];
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return new String[0];
}
return mResolveHostService.resolveHostSyncNonBlocking(host, RequestIpType.v4, null, getCurrentNetworkKey()).getIps();
}
@Override
public String[] getIPv4ListForHostAsync(String host) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return new String[0];
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return new String[0];
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return new String[0];
}
return mResolveHostService.resolveHostSyncNonBlocking(host, RequestIpType.v4, null, getCurrentNetworkKey()).getIps();
}
@Override
public String[] getIPv6sByHostAsync(String host) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return new String[0];
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return new String[0];
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return new String[0];
}
return mResolveHostService.resolveHostSyncNonBlocking(host, RequestIpType.v6, null, getCurrentNetworkKey())
.getIpv6s();
}
@Override
public String[] getIPv6ListForHostASync(String host) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return new String[0];
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return new String[0];
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return new String[0];
}
return mResolveHostService.resolveHostSyncNonBlocking(host, RequestIpType.v6, null, getCurrentNetworkKey())
.getIpv6s();
}
@Override
public HTTPDNSResult getAllByHostAsync(String host) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
return mResolveHostService.resolveHostSyncNonBlocking(host, RequestIpType.both, null, getCurrentNetworkKey());
}
@Override
public HTTPDNSResult getHttpDnsResultForHostAsync(String host) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
return mResolveHostService.resolveHostSyncNonBlocking(host, RequestIpType.both, null, getCurrentNetworkKey());
}
@Override
public HTTPDNSResult getIpsByHostAsync(String host, RequestIpType type) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
return mResolveHostService.resolveHostSyncNonBlocking(host, type, null, getCurrentNetworkKey());
}
@Override
public HTTPDNSResult getHttpDnsResultForHostAsync(String host, RequestIpType type) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
return mResolveHostService.resolveHostSyncNonBlocking(host, type, null, getCurrentNetworkKey());
}
@Override
public void setAuthCurrentTime(long time) {
if (!mHttpDnsConfig.isEnabled()) {
return;
}
mSignService.setCurrentTimestamp(time);
}
@Override
public String getSessionId() {
return SessionTrackMgr.getInstance().getSessionId();
}
@Override
public HTTPDNSResult getIpsByHostAsync(String host, Map<String, String> params,
String cacheKey) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
return mResolveHostService.resolveHostSyncNonBlocking(host, RequestIpType.v4, params, cacheKey);
}
@Override
public HTTPDNSResult getHttpDnsResultForHostAsync(String host, Map<String, String> params,
String cacheKey) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
return mResolveHostService.resolveHostSyncNonBlocking(host, RequestIpType.v4, params, cacheKey);
}
@Override
public HTTPDNSResult getIpsByHostAsync(String host, RequestIpType type,
Map<String, String> params, String cacheKey) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
return mResolveHostService.resolveHostSyncNonBlocking(host, type, params, cacheKey);
}
@Override
public HTTPDNSResult getHttpDnsResultForHostAsync(String host, RequestIpType type,
Map<String, String> params, String cacheKey) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
return mResolveHostService.resolveHostSyncNonBlocking(host, type, params, cacheKey);
}
@Override
public HTTPDNSResult getHttpDnsResultForHostSync(String host, RequestIpType type, Map<String, String> params, String cacheKey) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
if (Looper.getMainLooper() == Looper.myLooper()) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("request in main thread, use async request");
}
return mResolveHostService.resolveHostSyncNonBlocking(host, type, null, getCurrentNetworkKey());
}
return mResolveHostService.resolveHostSync(host, type, params, cacheKey);
}
@Override
public void getHttpDnsResultForHostAsync(String host, RequestIpType type, Map<String, String> params, String cacheKey, HttpDnsCallback callback) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
if (callback != null) {
callback.onHttpDnsCompleted(Constants.EMPTY);
}
return;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
if (callback != null) {
callback.onHttpDnsCompleted(Constants.EMPTY);
}
return;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
if (callback != null) {
callback.onHttpDnsCompleted(Constants.EMPTY);
}
return;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
mResolveHostService.resolveHostAsync(host, type, params, cacheKey, callback);
}
@Override
public HTTPDNSResult getHttpDnsResultForHostSyncNonBlocking(String host, RequestIpType type, Map<String, String> params, String cacheKey) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
return mResolveHostService.resolveHostSyncNonBlocking(host, type, params, cacheKey);
}
@Override
public void setRegion(String region) {
if (mUseCustomServiceHosts) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("ignore setRegion in custom service host mode");
}
return;
}
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return;
}
region = CommonUtil.fixRegion(region);
if (CommonUtil.regionEquals(this.mHttpDnsConfig.getRegion(), region)
&& !this.mHttpDnsConfig.isAllInitServer()) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("region " + region + " is same, do not update serverIps");
}
return;
}
boolean changed = mHttpDnsConfig.setRegion(region);
if (changed) {
mResultRepo.clearMemoryCache();
//region鍙樺寲锛屾湇鍔P鍙樻垚瀵瑰簲鐨勯缃甀P锛岃Е鍙戞祴閫?
if (!mUseCustomServiceHosts) {
mRegionServerRankingService.rankServiceIp(mHttpDnsConfig.getCurrentServer());
}
}
if (!mUseCustomServiceHosts) {
mScheduleService.updateRegionServerIps(region, Constants.UPDATE_REGION_SERVER_SCENES_REGION_CHANGE);
}
}
@Override
public void setRegion(Region region) {
setRegion(region == null ? "" : region.getRegion());
}
@Override
public String getIPv6ByHostAsync(String host) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return null;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return null;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return null;
}
String[] ips = getIPv6sByHostAsync(host);
if (ips == null || ips.length == 0) {
return null;
}
return ips[0];
}
@Override
public String getIPv6ForHostAsync(String host) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return null;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return null;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return null;
}
String[] ips = getIPv6sByHostAsync(host);
if (ips == null || ips.length == 0) {
return null;
}
return ips[0];
}
@Override
public void onNetworkChange(String networkType) {
if (!mHttpDnsConfig.isEnabled()) {
return;
}
try {
mHttpDnsConfig.getWorker().execute(new Runnable() {
@Override
public void run() {
// 鑾峰彇褰撳墠缃戠粶鏍囪瘑
String requestNetworkKey = getCurrentNetworkKey();
// 鑾峰彇鍘嗗彶鍩熷悕
HashMap<String, RequestIpType> allHost = mResultRepo.getAllHostWithoutFixedIP();
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("network change to " + requestNetworkKey + ", smart resolve hosts");
}
// 鏅鸿兘澧為噺瑙f瀽
if (resolveAfterNetworkChange && mHttpDnsConfig.isEnabled()) {
smartBatchResolve(allHost, requestNetworkKey);
}
}
});
//缃戠粶鍙樺寲锛岃Е鍙戞湇鍔P娴嬮€?
if (!mUseCustomServiceHosts) {
mRegionServerRankingService.rankServiceIp(mHttpDnsConfig.getCurrentServer());
}
} catch (Exception e) {
}
}
@Override
public HTTPDNSResult getByHost(String host, RequestIpType type) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
if (Looper.getMainLooper() == Looper.myLooper()) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("request in main thread, use async request");
}
return mResolveHostService.resolveHostSyncNonBlocking(host, type, null, getCurrentNetworkKey());
}
return mResolveHostService.resolveHostSync(host, type, null, getCurrentNetworkKey());
}
private RequestIpType changeTypeWithNetType(HttpDnsSettings.NetworkDetector networkDetector,
RequestIpType type) {
if (type == RequestIpType.auto) {
if (networkDetector != null) {
switch (networkDetector.getNetType(mHttpDnsConfig.getContext())) {
case v4:
return RequestIpType.v4;
default:
return RequestIpType.both;
}
}
return RequestIpType.both;
}
return type;
}
public void cleanHostCache(ArrayList<String> hosts) {
CleanHostCacheEvent cleanHostCacheEvent = new CleanHostCacheEvent();
if (hosts == null || hosts.size() == 0) {
// 娓呯悊鎵€鏈塰ost
mResultRepo.clear();
cleanHostCacheEvent.setTag(ObservableConstants.CLEAN_ALL_HOST_CACHE);
} else {
// 娓呯悊閫変腑鐨刪ost
cleanHostCacheEvent.setTag(ObservableConstants.CLEAN_SPECIFY_HOST_CACHE);
mResultRepo.clear(hosts);
}
cleanHostCacheEvent.setStatusCode(200);
cleanHostCacheEvent.setCostTime((int) (System.currentTimeMillis() - cleanHostCacheEvent.getTimestamp()));
mHttpDnsConfig.getObservableManager().addObservableEvent(cleanHostCacheEvent);
}
@Override
public HTTPDNSResult getHttpDnsResultForHostSync(String host, RequestIpType type) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
if (Looper.getMainLooper() == Looper.myLooper()) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("request in main thread, use async request");
}
return mResolveHostService.resolveHostSyncNonBlocking(host, type, null, getCurrentNetworkKey());
}
return mResolveHostService.resolveHostSync(host, type, null, getCurrentNetworkKey());
}
@Override
public void getHttpDnsResultForHostAsync(String host, RequestIpType type, HttpDnsCallback callback) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
if (callback != null) {
callback.onHttpDnsCompleted(Constants.EMPTY);
}
return;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
if (callback != null) {
callback.onHttpDnsCompleted(Constants.EMPTY);
}
return;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
if (callback != null) {
callback.onHttpDnsCompleted(Constants.EMPTY);
}
return;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
mResolveHostService.resolveHostAsync(host, type, null, getCurrentNetworkKey(), callback);
}
@Override
public HTTPDNSResult getHttpDnsResultForHostSyncNonBlocking(String host, RequestIpType type) {
if (!mHttpDnsConfig.isEnabled()) {
HttpDnsLog.i("service is disabled");
return Constants.EMPTY;
}
if (!CommonUtil.isAHost(host)) {
HttpDnsLog.i("host is invalid. " + host);
return Constants.EMPTY;
}
if (CommonUtil.isAnIP(host)) {
HttpDnsLog.i("host is ip. " + host);
return Constants.EMPTY;
}
type = changeTypeWithNetType(mHttpDnsConfig.getNetworkDetector(), type);
return mResolveHostService.resolveHostSyncNonBlocking(host, type, null, getCurrentNetworkKey());
}
private void tryUpdateRegionServer(Context context, String accountId) {
if (mUseCustomServiceHosts) {
return;
}
if (mHttpDnsConfig.getCurrentServer().shouldUpdateServerIp()) {
mScheduleService.updateRegionServerIps(Constants.UPDATE_REGION_SERVER_SCENES_INIT);
} else {
InitConfig config = InitConfig.getInitConfig(accountId);
String initRegion = Constants.REGION_DEFAULT;
if (config != null) {
initRegion = CommonUtil.fixRegion(config.getRegion());
}
SharedPreferences sp = context.getSharedPreferences(
Constants.CONFIG_CACHE_PREFIX + accountId, Context.MODE_PRIVATE);
String cachedRegion = sp.getString(Constants.CONFIG_CURRENT_SERVER_REGION,
Constants.REGION_DEFAULT);
if (!CommonUtil.regionEquals(cachedRegion, initRegion)) {
mScheduleService.updateRegionServerIps(Constants.UPDATE_REGION_SERVER_SCENES_REGION_CHANGE);
}
}
}
/**
* 鏅鸿兘澧為噺瑙f瀽锛氬彧瑙f瀽褰撳墠缃戠粶鐜涓嬬己澶辩殑鍩熷悕
*
* @param allHosts 鎵€鏈夊巻鍙插煙鍚?
* @param requestNetworkKey 璇锋眰鏃剁殑缃戠粶鏍囪瘑
*/
private void smartBatchResolve(HashMap<String, RequestIpType> allHosts, String requestNetworkKey) {
ArrayList<String> v4List = new ArrayList<>();
ArrayList<String> v6List = new ArrayList<>();
ArrayList<String> bothList = new ArrayList<>();
// 妫€鏌ュ綋鍓嶇綉缁滅幆澧冧笅鏄惁闇€瑕佽В鏋?
for (Map.Entry<String, RequestIpType> entry : allHosts.entrySet()) {
String host = entry.getKey();
RequestIpType type = entry.getValue();
// 浣跨敤璇锋眰鏃剁殑缃戠粶鏍囪瘑妫€鏌ョ紦瀛?
if (needsResolveInNetwork(host, type, requestNetworkKey)) {
if (type == RequestIpType.v4) {
v4List.add(host);
} else if (type == RequestIpType.v6) {
v6List.add(host);
} else {
bothList.add(host);
}
}
}
// 浣跨敤甯︾綉缁滄爣璇嗙殑鎵归噺瑙f瀽鏂规硶
if (v4List.size() > 0) {
mBatchResolveHostService.batchResolveHostAsync(v4List, RequestIpType.v4);
}
if (v6List.size() > 0) {
mBatchResolveHostService.batchResolveHostAsync(v6List, RequestIpType.v6);
}
if (bothList.size() > 0) {
mBatchResolveHostService.batchResolveHostAsync(bothList, RequestIpType.both);
}
if (v4List.size() > 0 || v6List.size() > 0 || bothList.size() > 0) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("smart resolve " + (v4List.size() + v6List.size() + bothList.size()) + " hosts for network " + requestNetworkKey);
}
}
}
/**
* 妫€鏌ユ寚瀹氱綉缁滅幆澧冧笅鏄惁闇€瑕佽В鏋愬煙鍚?
*
* @param host 鍩熷悕
* @param type 瑙f瀽绫诲瀷
* @param networkKey 缃戠粶鏍囪瘑
* @return 鏄惁闇€瑕佽В鏋?
*/
private boolean needsResolveInNetwork(String host, RequestIpType type, String networkKey) {
// 妫€鏌ユ寚瀹氱綉缁滅幆澧冧笅鏄惁鏈夋湁鏁堢紦瀛?
ResolveHostCache cache = mResultRepo.getCacheGroup().getCache(networkKey);
HTTPDNSResultWrapper result = cache.getResult(host, type);
return result == null || result.isExpired();
}
/**
* 鑾峰彇褰撳墠缃戠粶鏍囪瘑锛岀敤浜庣綉缁滈殧绂荤紦瀛?
*
* @return 褰撳墠缃戠粶鏍囪瘑
*/
private String getCurrentNetworkKey() {
return NetworkStateManager.getInstance().getCurrentNetworkKey();
}
}

View File

@@ -0,0 +1,141 @@
package com.newsdk.sdk.android.httpdns.impl;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class SignService {
private static final String ALGORITHM = "HmacSHA256";
public static final int EXPIRATION_TIME = 10 * 60;
private static final String SDNS_PREFIX = "sdns-";
private static final Set<String> includeParamKeys = new HashSet<>();
private String mSecretKey;
private long mOffset = 0L;
public SignService(String secretKey) {
mSecretKey = secretKey;
includeParamKeys.addAll(Arrays.asList("id", "m", "dn", "cip", "q", "enc", "exp", "tags", "v"));
}
/**
* 设置密钥
*/
public void setSecretKey(String secretKey) {
mSecretKey = secretKey;
}
/**
* 使用 HMAC-SHA256 生成十六进制格式的签名
*/
public String sign(Map<String, String> param) {
if (TextUtils.isEmpty(mSecretKey)) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("secretKey为空");
}
return "";
}
String signStr;
try {
signStr = generateV2SignContent(param);
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("signStr:" + signStr);
}
signStr = hmacSha256(signStr);
} catch (Exception e) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.e("sign fail.", e);
}
signStr = "";
}
return signStr;
}
/**
* 鏂扮増 /resolve 璇锋眰绛惧悕锛? * appId|lower(domain)|upper(qtype)|exp|nonce
*/
public String signResolve(String appId, String domain, String qtype, String exp, String nonce) {
if (TextUtils.isEmpty(mSecretKey)
|| TextUtils.isEmpty(appId)
|| TextUtils.isEmpty(domain)
|| TextUtils.isEmpty(qtype)
|| TextUtils.isEmpty(exp)
|| TextUtils.isEmpty(nonce)) {
return "";
}
String raw = appId + "|" + domain.toLowerCase() + "|" + qtype.toUpperCase() + "|" + exp + "|" + nonce;
try {
return hmacSha256(raw);
} catch (Exception e) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.e("sign resolve fail.", e);
}
return "";
}
}
private static String generateV2SignContent(Map<String, String> map) {
Map<String, String> sortedMap = new TreeMap<>();
for(Map.Entry<String, String> entry : map.entrySet()) {
String paramKey = entry.getKey();
String paramValue = entry.getValue();
if (includeParamKeys.contains(paramKey) || paramKey.startsWith(SDNS_PREFIX)) {
if(!TextUtils.isEmpty(paramValue)) {
sortedMap.put(paramKey, paramValue);
}
}
}
StringBuilder signContent = new StringBuilder();
for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
if (signContent.length() > 0) {
signContent.append("&");
}
signContent.append(entry.getKey()).append("=").append(entry.getValue());
}
return signContent.toString();
}
private String hmacSha256(String content)
throws NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance(ALGORITHM);
mac.init(new SecretKeySpec(mSecretKey.getBytes(StandardCharsets.UTF_8), ALGORITHM));
byte[] signedBytes = mac.doFinal(content.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder(signedBytes.length * 2);
for (byte b : signedBytes) {
String h = Integer.toHexString(b & 0xff);
if (h.length() == 1) {
sb.append('0');
}
sb.append(h);
}
return sb.toString();
}
public void setCurrentTimestamp(long serverTime) {
mOffset = serverTime - System.currentTimeMillis() / 1000;
}
public String getExpireTime(){
return Long.toString(System.currentTimeMillis() / 1000 + EXPIRATION_TIME + mOffset);
}
public Boolean isSignMode(){
return !TextUtils.isEmpty(mSecretKey);
}
}

View File

@@ -0,0 +1,145 @@
package com.newsdk.sdk.android.httpdns.log;
import java.util.HashSet;
import com.newsdk.sdk.android.httpdns.ILogger;
import android.util.Log;
/**
* 鏃ュ織宸ュ叿绫?
*/
public class HttpDnsLog {
public static final String TAG = "httpdns";
private static boolean printToLogcat = false;
private static final HashSet<ILogger> LOGGERS = new HashSet<>();
/**
* 璁剧疆鏃ュ織鎺ュ彛
* 涓嶅彈{@link #printToLogcat} 鎺у埗
*/
public static void setLogger(ILogger logger) {
if (logger != null) {
LOGGERS.add(logger);
}
}
/**
* 绉婚櫎鏃ュ織鎺ュ彛
*/
public static void removeLogger(ILogger logger) {
if (logger != null) {
LOGGERS.remove(logger);
}
}
/**
* logcat寮€鍏?
*
* @param enable
*/
public static void enable(boolean enable) {
HttpDnsLog.printToLogcat = enable;
}
public static boolean isPrint() {
return HttpDnsLog.printToLogcat;
}
public static void e(String errLog) {
if (HttpDnsLog.printToLogcat) {
Log.e(TAG, errLog);
}
if (HttpDnsLog.LOGGERS.size() > 0) {
for (ILogger logger : HttpDnsLog.LOGGERS) {
logger.log("[E]" + errLog);
}
}
}
public static void i(String infoLog) {
if (HttpDnsLog.printToLogcat) {
Log.i(TAG, infoLog);
}
if (HttpDnsLog.LOGGERS.size() > 0) {
for (ILogger logger : HttpDnsLog.LOGGERS) {
logger.log("[I]" + infoLog);
}
}
}
public static void d(String debugLog) {
if (HttpDnsLog.printToLogcat) {
Log.d(TAG, debugLog);
}
if (HttpDnsLog.LOGGERS.size() > 0) {
for (ILogger logger : HttpDnsLog.LOGGERS) {
logger.log("[D]" + debugLog);
}
}
}
public static void w(String warnLog) {
if (HttpDnsLog.printToLogcat) {
Log.w(TAG, warnLog);
}
if (HttpDnsLog.LOGGERS.size() > 0) {
for (ILogger logger : HttpDnsLog.LOGGERS) {
logger.log("[W]" + warnLog);
}
}
}
public static void e(String errLog, Throwable throwable) {
if (HttpDnsLog.printToLogcat) {
Log.e(TAG, errLog, throwable);
}
if (HttpDnsLog.LOGGERS.size() > 0) {
for (ILogger logger : HttpDnsLog.LOGGERS) {
logger.log("[E]" + errLog);
}
printStackTrace(throwable);
}
}
public static void w(String warnLog, Throwable throwable) {
if (HttpDnsLog.printToLogcat) {
Log.e(TAG, warnLog, throwable);
}
if (HttpDnsLog.LOGGERS.size() > 0) {
for (ILogger logger : HttpDnsLog.LOGGERS) {
logger.log("[W]" + warnLog);
}
printStackTrace(throwable);
}
}
private static void printStackTrace(Throwable throwable) {
if (HttpDnsLog.LOGGERS.size() > 0) {
for (ILogger logger : HttpDnsLog.LOGGERS) {
logger.log(Log.getStackTraceString(throwable));
}
}
}
/**
* ip鏁扮粍杞垚瀛楃涓叉柟渚胯緭鍑?
*
* @param ips
* @return
*/
public static String wrap(String[] ips) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[");
for (int i = 0; i < ips.length; i++) {
if (i != 0) {
stringBuilder.append(",");
}
stringBuilder.append(ips[i]);
}
stringBuilder.append("]");
return stringBuilder.toString();
}
}

View File

@@ -0,0 +1,132 @@
package com.newsdk.sdk.android.httpdns.net;
import java.util.concurrent.ExecutorService;
import com.newsdk.sdk.android.httpdns.HttpDnsSettings;
import com.newsdk.sdk.android.httpdns.NetType;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.utils.ThreadUtil;
import android.content.Context;
import com.aliyun.ams.ipdetector.Inet64Util;
public class HttpDnsNetworkDetector implements HttpDnsSettings.NetworkDetector {
private static class Holder {
private static final HttpDnsNetworkDetector INSTANCE = new HttpDnsNetworkDetector();
}
public static HttpDnsNetworkDetector getInstance() {
return Holder.INSTANCE;
}
private HttpDnsNetworkDetector() {
}
private final ExecutorService mWorker = ThreadUtil.createSingleThreadService("NetType");
private boolean mCheckInterface = true;
private String mHostToCheckNetType = "www.taobao.com";
private NetType mCache = NetType.none;
private boolean mDisableCache = false;
private Context mContext;
/**
* 缃戠粶鍙樺寲鏃讹紝娓呴櫎缂撳瓨
*/
public void cleanCache(final boolean connected) {
if (mDisableCache) {
return;
}
mCache = NetType.none;
if (connected && this.mContext != null) {
mWorker.execute(new Runnable() {
@Override
public void run() {
// 寮傛鎺㈡祴涓€涓?
if (mContext != null) {
mCache = detectNetType(mContext);
}
}
});
}
}
/**
* 鏄惁绂佺敤缂撳瓨锛岄粯璁や笉绂佺敤
* 涓嶇‘瀹氭槸鍚﹀瓨鍦ㄧ綉缁滈摼鎺ヤ笉鍙樼殑鎯呭喌涓嬶紝缃戠粶鎯呭喌浼氬彂鐢熷彉鍖栫殑鎯呭喌锛屾墍浠ユ彁渚涗簡姝ゅ紑鍏?
*/
public void disableCache(boolean disable) {
this.mDisableCache = disable;
}
/**
* 濡傛灉涓嶈兘妫€鏌ユ湰鍦扮綉鍏砳p,鍙互璋冪敤姝ゆ帴鍙e叧闂?
*/
public void setCheckInterface(boolean checkInterface) {
this.mCheckInterface = checkInterface;
}
/**
* 鏈変簺鍦烘櫙闇€瑕侀€氳繃鏈湴瑙f瀽鏉ョ‘璁ょ綉缁滅被鍨嬶紝榛樿浣跨敤 www.taobao.com
*/
public void setHostToCheckNetType(String hostToCheckNetType) {
this.mHostToCheckNetType = hostToCheckNetType;
}
@Override
public NetType getNetType(Context context) {
if (mDisableCache) {
NetType tmp = detectNetType(context);
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("ipdetector type is " + tmp.name());
}
return tmp;
}
if (mCache != NetType.none) {
return mCache;
}
mCache = detectNetType(context);
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("ipdetector type is " + mCache.name());
}
return mCache;
}
private NetType detectNetType(Context context) {
this.mContext = context.getApplicationContext();
try {
int type;// 涓嶆鏌ユ湰鍦癐P鐨勬儏鍐典笅锛屾棤娉曡繃婊pv6鍙湁鏈湴ip鐨勬儏鍐碉紝闇€瑕侀€氳繃鍏跺畠鏂瑰紡妫€娴嬩笅銆?
// 娌℃湁缃戠粶锛?
if (mCheckInterface) {
type = Inet64Util.getIpStack(context);
} else {
type = Inet64Util.getIpStackCheckLocal(context);
}
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("ip detector type is " + type);
}
if (type == IP_DUAL_STACK) {
return NetType.both;
} else if (type == IPV4_ONLY) {
return NetType.v4;
} else if (type == IPV6_ONLY) {
return NetType.v6;
} else {
// 娌℃湁缃戠粶锛?
return NetType.none;
}
} catch (Throwable e) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.i("ip detector not exist.");
}
return NetType.none;
}
}
private final static int IPV4_ONLY = 1;
private final static int IPV6_ONLY = 2;
private final static int IP_DUAL_STACK = 3;
}

View File

@@ -0,0 +1,238 @@
package com.newsdk.sdk.android.httpdns.net;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.Inet6Address;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.utils.ThreadUtil;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Network;
import android.net.LinkProperties;
import android.net.LinkAddress;
import android.os.Build;
import android.os.Process;
public class NetworkStateManager {
public static final String NONE_NETWORK = "None_Network";
private static final String NETWORK_KEY_PREFIX = "emasInner_";
private Context mContext;
private String mLastConnectedNetwork = NONE_NETWORK;
private volatile String mCurrentNetworkKey = NONE_NETWORK;
private final ArrayList<OnNetworkChange> mListeners = new ArrayList<>();
private final ExecutorService mWorker = ThreadUtil.createSingleThreadService("network");
private static class Holder {
private static final NetworkStateManager instance = new NetworkStateManager();
}
public static NetworkStateManager getInstance() {
return Holder.instance;
}
private NetworkStateManager() {
}
public void init(Context ctx) {
if (ctx == null) {
throw new IllegalStateException("Context can't be null");
}
if (this.mContext != null) {
// inited
return;
}
this.mContext = ctx.getApplicationContext();
// 绔嬪嵆妫€娴嬪綋鍓嶇綉缁滅姸鎬?
mWorker.execute(() -> {
try {
String currentNetwork = detectCurrentNetwork();
if (!currentNetwork.equals(NONE_NETWORK)) {
mLastConnectedNetwork = currentNetwork;
}
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("[NetworkStateManager.init] - Initial network detected: " + currentNetwork);
}
} catch (Exception e) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.e("[NetworkStateManager.init] - Failed to detect initial network", e);
}
}
});
BroadcastReceiver bcReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
try {
mWorker.execute(new Runnable() {
@Override
public void run() {
try {
if (isInitialStickyBroadcast()) { // no need to handle initial
// sticky broadcast
return;
}
String action = intent.getAction();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)
&& hasNetInfoPermission(context)) {
String currentNetwork = detectCurrentNetwork();
HttpDnsNetworkDetector.getInstance().cleanCache(
!currentNetwork.equals(NONE_NETWORK));
if (!currentNetwork.equals(NONE_NETWORK)
&& !currentNetwork.equalsIgnoreCase(mLastConnectedNetwork)) {
for (OnNetworkChange onNetworkChange : mListeners) {
onNetworkChange.onNetworkChange(currentNetwork);
}
}
if (!currentNetwork.equals(NONE_NETWORK)) {
mLastConnectedNetwork = currentNetwork;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (Exception ignored) {
}
}
};
try {
if (hasNetInfoPermission(mContext)) {
IntentFilter mFilter = new IntentFilter();
mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(bcReceiver, mFilter);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private String detectCurrentNetwork() {
try {
ConnectivityManager connectivityManager = (ConnectivityManager)mContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connectivityManager.getActiveNetworkInfo();
if (info != null && info.isAvailable() && info.isConnected()) {
String name = info.getTypeName();
String ipPrefix = getLocalIpPrefix();
if (ipPrefix != null) {
name = name + "_" + ipPrefix;
}
// 澧炲姞鍓嶇紑锛岄槻姝笌鐢ㄦ埛cacheKey鍐茬獊
mCurrentNetworkKey = (name == null) ? NONE_NETWORK : (NETWORK_KEY_PREFIX + name);
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("[detectCurrentNetwork] - Network key:" + mCurrentNetworkKey + " subType "
+ "name: "
+ info.getSubtypeName());
}
return mCurrentNetworkKey;
}
} catch (Exception e) {
e.printStackTrace();
}
mCurrentNetworkKey = NONE_NETWORK;
return NONE_NETWORK;
}
private String getLocalIpPrefix() {
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return null;
}
ConnectivityManager connectivityManager = (ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
Network activeNetwork = connectivityManager.getActiveNetwork();
if (activeNetwork == null) {
return null;
}
LinkProperties linkProperties = connectivityManager.getLinkProperties(activeNetwork);
if (linkProperties == null) {
return null;
}
String ipv6Backup = null;
for (LinkAddress linkAddress : linkProperties.getLinkAddresses()) {
InetAddress address = linkAddress.getAddress();
if (address.isLoopbackAddress() || address.isLinkLocalAddress()) {
continue;
}
if (address instanceof Inet4Address) {
String ip = address.getHostAddress();
String[] parts = ip.split("\\.");
if (parts.length >= 3) {
return parts[0] + "." + parts[1] + "." + parts[2];
}
} else if (address instanceof Inet6Address && ipv6Backup == null) {
String ipv6 = address.getHostAddress();
if (ipv6.contains("%")) {
ipv6 = ipv6.substring(0, ipv6.indexOf("%"));
}
String[] parts = ipv6.split(":");
if (parts.length >= 4) {
ipv6Backup = parts[0] + ":" + parts[1] + ":" + parts[2] + ":" + parts[3];
}
}
}
return ipv6Backup;
} catch (Exception e) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("[getLocalIpPrefix] - Failed to get IP prefix: " + e.getMessage());
}
}
return null;
}
public String getCurrentNetworkKey() {
return mCurrentNetworkKey;
}
public void addListener(OnNetworkChange change) {
this.mListeners.add(change);
}
public interface OnNetworkChange {
void onNetworkChange(String networkType);
}
public void reset() {
mContext = null;
mLastConnectedNetwork = NONE_NETWORK;
mCurrentNetworkKey = NONE_NETWORK;
mListeners.clear();
}
private static boolean hasNetInfoPermission(Context context) {
try {
return checkSelfPermission(context, Manifest.permission.ACCESS_NETWORK_STATE)
== PackageManager.PERMISSION_GRANTED;
} catch (Throwable e) {
HttpDnsLog.w("check network info permission fail", e);
}
return false;
}
private static int checkSelfPermission(Context context, String permission) {
return context.checkPermission(permission, Process.myPid(), Process.myUid());
}
}

View File

@@ -0,0 +1,22 @@
package com.newsdk.sdk.android.httpdns.network;
import java.io.IOException;
public class HttpDnsAdapterException extends IOException {
private final String errorCode;
public HttpDnsAdapterException(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public HttpDnsAdapterException(String errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public String getErrorCode() {
return errorCode;
}
}

View File

@@ -0,0 +1,71 @@
package com.newsdk.sdk.android.httpdns.network;
import com.newsdk.sdk.android.httpdns.RequestIpType;
public class HttpDnsAdapterOptions {
private final int connectTimeoutMillis;
private final int readTimeoutMillis;
private final boolean allowInsecureCertificatesForDebugOnly;
private final RequestIpType requestIpType;
private HttpDnsAdapterOptions(Builder builder) {
connectTimeoutMillis = builder.connectTimeoutMillis;
readTimeoutMillis = builder.readTimeoutMillis;
allowInsecureCertificatesForDebugOnly = builder.allowInsecureCertificatesForDebugOnly;
requestIpType = builder.requestIpType;
}
public int getConnectTimeoutMillis() {
return connectTimeoutMillis;
}
public int getReadTimeoutMillis() {
return readTimeoutMillis;
}
public boolean isAllowInsecureCertificatesForDebugOnly() {
return allowInsecureCertificatesForDebugOnly;
}
public RequestIpType getRequestIpType() {
return requestIpType;
}
public static class Builder {
private int connectTimeoutMillis = 3000;
private int readTimeoutMillis = 5000;
private boolean allowInsecureCertificatesForDebugOnly = false;
private RequestIpType requestIpType = RequestIpType.auto;
public Builder setConnectTimeoutMillis(int value) {
if (value > 0) {
connectTimeoutMillis = value;
}
return this;
}
public Builder setReadTimeoutMillis(int value) {
if (value > 0) {
readTimeoutMillis = value;
}
return this;
}
public Builder setAllowInsecureCertificatesForDebugOnly(boolean value) {
allowInsecureCertificatesForDebugOnly = value;
return this;
}
public Builder setRequestIpType(RequestIpType type) {
if (type != null) {
requestIpType = type;
}
return this;
}
public HttpDnsAdapterOptions build() {
return new HttpDnsAdapterOptions(this);
}
}
}

View File

@@ -0,0 +1,44 @@
package com.newsdk.sdk.android.httpdns.network;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
public class HttpDnsAdapterRequest {
private final String method;
private final String url;
private final Map<String, String> headers;
private final byte[] body;
public HttpDnsAdapterRequest(String method, String url) {
this(method, url, null, null);
}
public HttpDnsAdapterRequest(String method, String url, Map<String, String> headers, byte[] body) {
this.method = method == null || method.trim().isEmpty() ? "GET" : method.trim().toUpperCase();
this.url = url;
if (headers == null || headers.isEmpty()) {
this.headers = Collections.emptyMap();
} else {
this.headers = Collections.unmodifiableMap(new LinkedHashMap<>(headers));
}
this.body = body;
}
public String getMethod() {
return method;
}
public String getUrl() {
return url;
}
public Map<String, String> getHeaders() {
return headers;
}
public byte[] getBody() {
return body;
}
}

View File

@@ -0,0 +1,35 @@
package com.newsdk.sdk.android.httpdns.network;
import java.util.List;
import java.util.Map;
public class HttpDnsAdapterResponse {
private final int statusCode;
private final Map<String, List<String>> headers;
private final byte[] body;
private final String usedIp;
public HttpDnsAdapterResponse(int statusCode, Map<String, List<String>> headers, byte[] body, String usedIp) {
this.statusCode = statusCode;
this.headers = headers;
this.body = body;
this.usedIp = usedIp;
}
public int getStatusCode() {
return statusCode;
}
public Map<String, List<String>> getHeaders() {
return headers;
}
public byte[] getBody() {
return body;
}
public String getUsedIp() {
return usedIp;
}
}

View File

@@ -0,0 +1,12 @@
package com.newsdk.sdk.android.httpdns.network;
public final class HttpDnsErrorCode {
private HttpDnsErrorCode() {
}
public static final String NO_IP_AVAILABLE = "NO_IP_AVAILABLE";
public static final String TLS_EMPTY_SNI_FAILED = "TLS_EMPTY_SNI_FAILED";
public static final String HOST_ROUTE_REJECTED = "HOST_ROUTE_REJECTED";
public static final String RESOLVE_SIGN_INVALID = "RESOLVE_SIGN_INVALID";
}

View File

@@ -0,0 +1,330 @@
package com.newsdk.sdk.android.httpdns.network;
import com.newsdk.sdk.android.httpdns.HTTPDNSResult;
import com.newsdk.sdk.android.httpdns.HttpDnsService;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class HttpDnsHttpAdapter {
private static final int BUFFER_SIZE = 4096;
private final HttpDnsService httpDnsService;
private final HttpDnsAdapterOptions options;
public HttpDnsHttpAdapter(HttpDnsService httpDnsService) {
this(httpDnsService, new HttpDnsAdapterOptions.Builder().build());
}
public HttpDnsHttpAdapter(HttpDnsService httpDnsService, HttpDnsAdapterOptions options) {
if (httpDnsService == null) {
throw new IllegalArgumentException("httpDnsService should not be null");
}
this.httpDnsService = httpDnsService;
this.options = options == null ? new HttpDnsAdapterOptions.Builder().build() : options;
}
public HttpDnsAdapterResponse execute(HttpDnsAdapterRequest request) throws IOException {
if (request == null || request.getUrl() == null || request.getUrl().trim().isEmpty()) {
throw new HttpDnsAdapterException(HttpDnsErrorCode.HOST_ROUTE_REJECTED,
"request or url is empty");
}
URL originalURL = new URL(request.getUrl());
String originalHost = originalURL.getHost();
if (originalHost == null || originalHost.trim().isEmpty()) {
throw new HttpDnsAdapterException(HttpDnsErrorCode.HOST_ROUTE_REJECTED,
"invalid original host");
}
String scheme = originalURL.getProtocol();
boolean isHttps = "https".equalsIgnoreCase(scheme);
int defaultPort = isHttps ? 443 : 80;
List<String> candidateIps = resolveIps(originalHost);
if (candidateIps.isEmpty()) {
throw new HttpDnsAdapterException(HttpDnsErrorCode.NO_IP_AVAILABLE,
"HTTPDNS returned no ip for host: " + originalHost);
}
IOException lastException = null;
for (String ip : candidateIps) {
if (ip == null || ip.trim().isEmpty()) {
continue;
}
String usedIp = ip.trim();
HttpURLConnection connection = null;
try {
int port = originalURL.getPort() > 0 ? originalURL.getPort() : defaultPort;
URL targetURL = new URL(scheme, usedIp, port, originalURL.getFile());
connection = (HttpURLConnection) targetURL.openConnection();
connection.setConnectTimeout(options.getConnectTimeoutMillis());
connection.setReadTimeout(options.getReadTimeoutMillis());
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod(request.getMethod());
if (isHttps && connection instanceof HttpsURLConnection) {
HttpsURLConnection httpsConn = (HttpsURLConnection) connection;
httpsConn.setSSLSocketFactory(createSocketFactory());
httpsConn.setHostnameVerifier(createHostnameVerifier(originalHost));
}
connection.setRequestProperty("Host", originalHost);
for (Map.Entry<String, String> entry : request.getHeaders().entrySet()) {
if (entry.getKey() == null || entry.getValue() == null) {
continue;
}
if ("host".equalsIgnoreCase(entry.getKey())) {
continue;
}
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
byte[] body = request.getBody();
if (body != null && body.length > 0 && allowsRequestBody(request.getMethod())) {
connection.setDoOutput(true);
connection.getOutputStream().write(body);
}
int code = connection.getResponseCode();
byte[] payload = readResponseBytes(connection, code);
Map<String, List<String>> headers = sanitizeHeaders(connection.getHeaderFields());
return new HttpDnsAdapterResponse(code, headers, payload, usedIp);
} catch (IOException e) {
lastException = e;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
String errorCode = isHttps ? HttpDnsErrorCode.TLS_EMPTY_SNI_FAILED
: HttpDnsErrorCode.HOST_ROUTE_REJECTED;
if (lastException == null) {
throw new HttpDnsAdapterException(errorCode,
"all ip attempts failed with no explicit exception");
}
throw new HttpDnsAdapterException(errorCode,
"all ip attempts failed", lastException);
}
private List<String> resolveIps(String host) {
RequestIpType type = options.getRequestIpType();
HTTPDNSResult result = httpDnsService.getHttpDnsResultForHostSyncNonBlocking(host, type, null, null);
List<String> ips = collectIps(result);
if (!ips.isEmpty()) {
return ips;
}
// Non-blocking read may miss cache in startup/race windows; fallback to sync resolve once.
result = httpDnsService.getHttpDnsResultForHostSync(host, type, null, null);
return collectIps(result);
}
private List<String> collectIps(HTTPDNSResult result) {
if (result == null) {
return Collections.emptyList();
}
List<String> ips = new ArrayList<>();
appendIps(ips, result.getIps());
appendIps(ips, result.getIpv6s());
return ips;
}
private void appendIps(List<String> target, String[] source) {
if (source == null || source.length == 0) {
return;
}
for (String item : source) {
if (item == null) {
continue;
}
String ip = item.trim();
if (ip.isEmpty()) {
continue;
}
if (!target.contains(ip)) {
target.add(ip);
}
}
}
private byte[] readResponseBytes(HttpURLConnection connection, int code) throws IOException {
InputStream stream = code >= 400 ? connection.getErrorStream() : connection.getInputStream();
if (stream == null) {
return new byte[0];
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int count;
while ((count = stream.read(buffer)) > 0) {
out.write(buffer, 0, count);
}
stream.close();
return out.toByteArray();
}
private Map<String, List<String>> sanitizeHeaders(Map<String, List<String>> source) {
if (source == null || source.isEmpty()) {
return Collections.emptyMap();
}
Map<String, List<String>> result = new LinkedHashMap<>();
for (Map.Entry<String, List<String>> entry : source.entrySet()) {
if (entry.getKey() == null) {
continue;
}
result.put(entry.getKey(), entry.getValue());
}
return result;
}
private boolean allowsRequestBody(String method) {
if (method == null) {
return false;
}
String upper = method.toUpperCase();
return "POST".equals(upper) || "PUT".equals(upper) || "PATCH".equals(upper) || "DELETE".equals(upper);
}
private HostnameVerifier createHostnameVerifier(final String originalHost) {
if (options.isAllowInsecureCertificatesForDebugOnly()) {
return new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
}
final HostnameVerifier defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
return new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return defaultVerifier.verify(originalHost, session);
}
};
}
private SSLSocketFactory createSocketFactory() throws IOException {
try {
SSLSocketFactory baseFactory;
if (options.isAllowInsecureCertificatesForDebugOnly()) {
baseFactory = NewAllSocketFactory();
} else {
baseFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
}
return new NoSniSocketFactory(baseFactory);
} catch (GeneralSecurityException e) {
throw new IOException("create ssl socket factory failed", e);
}
}
private SSLSocketFactory NewAllSocketFactory() throws GeneralSecurityException {
TrustManager[] managers = new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}};
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, managers, new SecureRandom());
return context.getSocketFactory();
}
private static class NoSniSocketFactory extends SSLSocketFactory {
private final SSLSocketFactory delegate;
private NoSniSocketFactory(SSLSocketFactory delegate) {
this.delegate = delegate;
}
@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
@Override
public java.net.Socket createSocket(java.net.Socket s, String host, int port, boolean autoClose)
throws IOException {
return sanitize(delegate.createSocket(s, host, port, autoClose));
}
@Override
public java.net.Socket createSocket(String host, int port) throws IOException {
return sanitize(delegate.createSocket(host, port));
}
@Override
public java.net.Socket createSocket(String host, int port, java.net.InetAddress localHost, int localPort)
throws IOException {
return sanitize(delegate.createSocket(host, port, localHost, localPort));
}
@Override
public java.net.Socket createSocket(java.net.InetAddress host, int port) throws IOException {
return sanitize(delegate.createSocket(host, port));
}
@Override
public java.net.Socket createSocket(java.net.InetAddress address, int port, java.net.InetAddress localAddress,
int localPort) throws IOException {
return sanitize(delegate.createSocket(address, port, localAddress, localPort));
}
private java.net.Socket sanitize(java.net.Socket socket) {
if (!(socket instanceof SSLSocket)) {
return socket;
}
SSLSocket sslSocket = (SSLSocket) socket;
try {
SSLParameters params = sslSocket.getSSLParameters();
try {
java.lang.reflect.Method setServerNames = SSLParameters.class.getMethod("setServerNames", List.class);
setServerNames.invoke(params, Collections.emptyList());
} catch (Throwable ignored) {
}
sslSocket.setSSLParameters(params);
} catch (Throwable ignored) {
}
return sslSocket;
}
}
}

View File

@@ -0,0 +1,118 @@
package com.newsdk.sdk.android.httpdns.observable;
import android.content.SharedPreferences;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.config.SpCacheItem;
import com.newsdk.sdk.android.httpdns.utils.Constants;
import org.json.JSONException;
import org.json.JSONObject;
public class ObservableConfig implements SpCacheItem {
//榛樿鍏抽棴
public boolean enable = false;
public double sampleRatio = 1.0;
public String endpoint = "";
public int batchReportMaxSize = 50;
public int batchReportIntervalTime = 60;
public int maxReportsPerMinute = 4;
public JSONObject raw = null;
public boolean updateConfig(ObservableConfig config) {
if (config == null) {
//璋冨害鎺ュ彛娌℃湁涓嬪彂閰嶇疆锛屽叧闂彲瑙傛祴
if (enable) {
enable = false;
raw = null;
return true;
}
return false;
}
if (isSameConfig(config)) {
return false;
}
enable = config.enable;
sampleRatio = config.sampleRatio;
endpoint = config.endpoint;
batchReportMaxSize = config.batchReportMaxSize;
batchReportIntervalTime = config.batchReportIntervalTime;
maxReportsPerMinute = config.maxReportsPerMinute;
raw = config.raw;
return true;
}
private boolean isSameConfig(ObservableConfig config) {
return enable == config.enable
&& sampleRatio == config.sampleRatio
&& TextUtils.equals(endpoint, config.endpoint)
&& batchReportMaxSize == config.batchReportMaxSize
&& batchReportIntervalTime == config.batchReportIntervalTime
&& maxReportsPerMinute == config.maxReportsPerMinute;
}
public static ObservableConfig fromJson(JSONObject json) {
if (json == null) {
return null;
}
ObservableConfig observableConfig = new ObservableConfig();
if (json.has("enable")) {
observableConfig.enable = json.optBoolean("enable");
}
if (json.has("sample_ratio")) {
observableConfig.sampleRatio = json.optDouble("sample_ratio");
}
String endpoint = json.optString("endpoint");
if (!TextUtils.isEmpty(endpoint)) {
observableConfig.endpoint = endpoint;
}
observableConfig.batchReportMaxSize = json.optInt("batch_report_max_size", 50);
if (observableConfig.batchReportMaxSize <= 0) {
observableConfig.batchReportMaxSize = 50;
}
observableConfig.batchReportIntervalTime = json.optInt("batch_report_interval_time", 60);
if (observableConfig.batchReportIntervalTime <= 0) {
observableConfig.batchReportIntervalTime = 60;
}
observableConfig.maxReportsPerMinute = json.optInt("max_reports_per_minute", 4);
if (observableConfig.maxReportsPerMinute <= 0) {
observableConfig.maxReportsPerMinute = 4;
}
observableConfig.raw = json;
return observableConfig;
}
@Override
public void restoreFromCache(SharedPreferences sp) {
String cachedObservableConfig = sp.getString(Constants.CONFIG_OBSERVABLE_CONFIG, null);
if (!TextUtils.isEmpty(cachedObservableConfig)) {
try {
JSONObject json = new JSONObject(cachedObservableConfig);
ObservableConfig cachedConfig = fromJson(json);
enable = cachedConfig.enable;
sampleRatio = cachedConfig.sampleRatio;
endpoint = cachedConfig.endpoint;
batchReportMaxSize = cachedConfig.batchReportMaxSize;
batchReportIntervalTime = cachedConfig.batchReportIntervalTime;
maxReportsPerMinute = cachedConfig.maxReportsPerMinute;
raw = cachedConfig.raw;
} catch (JSONException e) {
}
}
}
@Override
public void saveToCache(SharedPreferences.Editor editor) {
if (raw != null) {
editor.putString(Constants.CONFIG_OBSERVABLE_CONFIG, raw.toString());
} else {
editor.remove(Constants.CONFIG_OBSERVABLE_CONFIG);
}
}
}

View File

@@ -0,0 +1,39 @@
package com.newsdk.sdk.android.httpdns.observable;
public final class ObservableConstants {
public static final int REQUEST_IP_TYPE_AUTO = 0x00;
public static final int REQUEST_IP_TYPE_V4 = 0x01;
public static final int REQUEST_IP_TYPE_V6 = 0x02;
public static final int REQUEST_IP_TYPE_BOTH = 0x03;
public static final int RESOLVE_API_UNKNOWN = 0x00;
public static final int RESOLVE_API_SYNC = 0x04;
public static final int RESOLVE_API_ASYNC = 0x08;
public static final int RESOLVE_API_SYN_NON_BLOCKING = 0x0C;
public static final int REMOTE_CACHE_NULL = 0x00;
public static final int REMOTE_CACHE_EXPIRED = 0x10;
public static final int CACHE_NONE = 0x00;
public static final int CACHE_NOT_EXPIRED = 0x10;
public static final int CACHE_EXPIRED_NOT_USE = 0x20;
public static final int CACHE_EXPIRED_USE = 0x30;
public static final int REQUEST_NOT_RETRY = 0x00;
public static final int REQUEST_RETRY = 0x10;
public static final String UNKNOWN = "unknown";
public static final int HTTP_REQUEST = 0x00;
public static final int HTTPS_REQUEST = 0x04;
public static final int NOT_SIGN_MODE_REQUEST = 0x00;
public static final int SIGN_MODE_REQUEST = 0x08;
public static final int CLEAN_ALL_HOST_CACHE = 1;
public static final int CLEAN_SPECIFY_HOST_CACHE = 2;
public static final int EMPTY_RESULT = 0x00;
public static final int NOT_EMPTY_RESULT = 0x40;
}

View File

@@ -0,0 +1,99 @@
package com.newsdk.sdk.android.httpdns.observable;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.request.HttpRequestWrapper;
import com.newsdk.sdk.android.httpdns.request.ResponseParser;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
public class ObservableHttpRequest<T> extends HttpRequestWrapper<T> {
private String url;
private ResponseParser<T> parser;
private Map<String, String> mHeaders;
private String mBody;
public ObservableHttpRequest(String url, ResponseParser<T> parser, Map<String, String> headers, String body) {
super(null);
this.url = url;
this.parser = parser;
mHeaders = headers;
mBody = body;
}
@Override
public T request() throws Throwable {
HttpURLConnection conn = null;
InputStream in = null;
BufferedReader streamReader = null;
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("request url " + url);
}
try {
conn = (HttpURLConnection)new URL(url).openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(10000);
if (mHeaders != null) {
for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
}
if (!TextUtils.isEmpty(mBody)) {
conn.setRequestMethod("POST");
conn.setDoOutput(true);
OutputStream outputStream = conn.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
bw.write(mBody);
bw.close();
}
conn.connect();
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
in = conn.getInputStream();
streamReader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
String responseStr = readStringFrom(streamReader).toString();
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("request success " + responseStr);
}
return parser.parse(null, responseStr);
}
} catch (Throwable e) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d(e.getMessage());
}
} finally {
if (conn != null) {
conn.disconnect();
}
try {
if (in != null) {
in.close();
}
if (streamReader != null) {
streamReader.close();
}
} catch (IOException ignored) {
}
}
return null;
}
}

View File

@@ -0,0 +1,376 @@
package com.newsdk.sdk.android.httpdns.observable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.text.TextUtils;
import android.text.format.DateUtils;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsConfig;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.observable.event.GroupEvent;
import com.newsdk.sdk.android.httpdns.observable.event.LocalDnsEvent;
import com.newsdk.sdk.android.httpdns.observable.event.ObservableEvent;
import com.newsdk.sdk.android.httpdns.observable.event.ReportingRateExceptionEvent;
import com.newsdk.sdk.android.httpdns.request.HttpRequest;
import com.newsdk.sdk.android.httpdns.request.HttpRequestTask;
import com.newsdk.sdk.android.httpdns.request.RequestCallback;
import com.newsdk.sdk.android.httpdns.request.ResponseParser;
import com.newsdk.sdk.android.httpdns.request.RetryHttpRequest;
import com.newsdk.sdk.android.httpdns.resolve.ResolveHostHelper;
import com.newsdk.sdk.android.httpdns.track.SessionTrackMgr;
import com.newsdk.sdk.android.httpdns.utils.ThreadUtil;
/**
* utils data upload manager
*/
public class ObservableManager {
private static final int MESSAGE_REPORT = 101;
private HttpDnsConfig mHttpDnsConfig;
private String mSecret = null;
private int mReportBatchIndex = 0;
private List<ObservableEvent> mCacheEvents = new ArrayList<>();
private boolean mPositiveEnableObservable = true;
private boolean mReportingRateException = false;
private AtomicBoolean initMessage = new AtomicBoolean(false);
private ArrayDeque<Long> mReportsTime = new ArrayDeque<>();
private AtomicBoolean mReporting = new AtomicBoolean(false);
private final Handler mHandler;
private static final ExecutorService sWorker = ThreadUtil.createObservableExecutorService();
private static final ExecutorService mReportWorker = ThreadUtil.createObservableReportExecutorService();
private static final char[] hexChar = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
public ObservableManager(HttpDnsConfig httpDnsConfig, String secret) {
mHttpDnsConfig = httpDnsConfig;
mSecret = secret;
if (mHttpDnsConfig.getObservableSampleBenchMarks() < 0) {
mHttpDnsConfig.setObservableSampleBenchMarks(generateSampleBenchMarks());
}
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("observable: " + mHttpDnsConfig.getObservableSampleBenchMarks());
}
HandlerThread handlerThread = new HandlerThread("httpdns_observable");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_REPORT) {
report();
if (isEnableObservable() || !mCacheEvents.isEmpty()) {
mHandler.sendEmptyMessageDelayed(MESSAGE_REPORT, mHttpDnsConfig.getObservableConfig().batchReportIntervalTime * DateUtils.SECOND_IN_MILLIS);
}
}
}
};
}
public void positiveEnableObservable(boolean enable) {
mPositiveEnableObservable = enable;
}
private boolean isEnableReport() {
return mPositiveEnableObservable && !TextUtils.isEmpty(mHttpDnsConfig.getObservableConfig().endpoint);
}
/**
* 鏄惁寮€鍚彲瑙傛祴锛屽鏋滃叧闂紝鍒欐墦鐐瑰拰涓婃姤閮藉叧闂?
* @return
*/
private boolean isEnableObservable() {
return mPositiveEnableObservable && mHttpDnsConfig.getObservableConfig().enable
&& mHttpDnsConfig.getObservableSampleBenchMarks() < mHttpDnsConfig.getObservableConfig().sampleRatio
&& !mReportingRateException;
}
public void addObservableEvent(final ObservableEvent event) {
if (!isEnableObservable()) {
return;
}
if (event == null) {
return;
}
if (event instanceof LocalDnsEvent) {
//闇€瑕乴ocal dns鐨別vent锛屽湪杩欓噷缁熶竴鎵цlocal dns瑙
try {
sWorker.execute(new Runnable() {
@Override
public void run() {
((LocalDnsEvent) event).localDns(event.getHostName());
addObservableEventInner(event);
}
});
} catch (Exception e) {
//绾跨▼姹犲紓甯革紝涔熻娣诲姞浜嬩欢
addObservableEventInner(event);
}
} else {
addObservableEventInner(event);
}
}
private void addObservableEventInner(final ObservableEvent event) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (event instanceof GroupEvent) {
ObservableEvent temp;
GroupEvent targetGroupEvent = null;
for (int i= 0; i != mCacheEvents.size(); ++i) {
temp = mCacheEvents.get(i);
if (temp instanceof GroupEvent) {
if (((GroupEvent) temp).isSameGroup(event)) {
targetGroupEvent = (GroupEvent) temp;
break;
}
}
}
if (targetGroupEvent != null) {
targetGroupEvent.groupWith(event);
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("group event: " + targetGroupEvent.toString());
}
} else {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("add group event: " + event.toString());
}
addEventInner(event);
tryReport();
}
} else {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("add event: " + event.toString());
}
addEventInner(event);
tryReport();
}
}
});
if (initMessage.compareAndSet(false, true)) {
mHandler.sendEmptyMessageDelayed(MESSAGE_REPORT, mHttpDnsConfig.getObservableConfig().batchReportIntervalTime * DateUtils.SECOND_IN_MILLIS);
}
}
private void addEventInner(ObservableEvent event) {
mCacheEvents.add(event);
if (mCacheEvents.size() >= 400) {
ReportingRateExceptionEvent reportingRateExceptionEvent = new ReportingRateExceptionEvent();
reportingRateExceptionEvent.setStatusCode(200);
Map<Integer, Integer> eventNumMap = new HashMap<>();
for (ObservableEvent event1 : mCacheEvents) {
Integer num = eventNumMap.get(event1.getEventName());
if (num == null) {
num = 0;
}
eventNumMap.put(event1.getEventName(), num + 1);
}
int eventName = -1;
int tmpNum = 0;
for (Map.Entry<Integer, Integer> entry : eventNumMap.entrySet()) {
if (entry.getValue() > tmpNum) {
tmpNum = entry.getValue();
eventName = entry.getKey();
}
}
reportingRateExceptionEvent.setTag(eventName);
addObservableEvent(reportingRateExceptionEvent);
if (HttpDnsLog.isPrint()) {
HttpDnsLog.w("observable report rate exception.");
}
//鍏抽棴鏃ュ織閲囬泦
mReportingRateException = true;
}
}
private void tryReport() {
if (mCacheEvents.size() >= mHttpDnsConfig.getObservableConfig().batchReportMaxSize) {
//杈惧埌涓婃姤鏁伴噺
mHandler.removeMessages(MESSAGE_REPORT);
mHandler.sendEmptyMessage(MESSAGE_REPORT);
}
}
private void report() {
if (TextUtils.isEmpty(mHttpDnsConfig.getObservableConfig().endpoint)) {
return;
}
if (mCacheEvents.isEmpty()) {
return;
}
if (!isEnableReport()) {
mCacheEvents.clear();
++mReportBatchIndex;
return;
}
//涓婃姤娴侀噺鎺у埗鍒ゆ柇
long current = System.currentTimeMillis();
if (reachingReportingLimit(current)) {
return;
}
if (mReporting.compareAndSet(false, true)) {
String body = buildReportBody();
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("observable: " + body);
}
int num = Math.min(mHttpDnsConfig.getObservableConfig().batchReportMaxSize, mCacheEvents.size());
for (int i = 0; i != num; ++i) {
mCacheEvents.remove(0);
}
Map<String, String> headers = getHeader(mReportBatchIndex++);
try {
String url = getUrl(body);
if (TextUtils.isEmpty(url)) {
return;
}
//娣诲姞涓婃姤鏃堕棿鐐癸紝鐢ㄤ簬涓婃姤娴侀噺鎺у埗
mReportsTime.addLast(current);
HttpRequest<String> request = new ObservableHttpRequest<>(url, new ResponseParser<String>() {
@Override
public String parse(String serverIp, String response) throws Throwable {
return response;
}
}, headers, body);
// 閲嶈瘯2娆?
request = new RetryHttpRequest<>(request, 2);
mReportWorker.execute(new HttpRequestTask<>(request, new RequestCallback<String>() {
@Override
public void onSuccess(String response) {
mReporting.set(false);
mHandler.removeMessages(MESSAGE_REPORT);
mHandler.sendEmptyMessage(MESSAGE_REPORT);
}
@Override
public void onFail(Throwable throwable) {
mReporting.set(false);
}
}));
} catch (Throwable e) {
mReporting.set(false);
}
}
}
private String buildReportBody() {
StringBuilder sb = new StringBuilder();
int num = Math.min(mHttpDnsConfig.getObservableConfig().batchReportMaxSize, mCacheEvents.size());
for (int i = 0; i != num; ++i) {
sb.append(mCacheEvents.get(i).toString());
sb.append("\n");
}
return sb.toString();
}
private String getUrl(String content) throws UnsupportedEncodingException, NoSuchAlgorithmException {
ObservableConfig config = mHttpDnsConfig.getObservableConfig();
String url = config.endpoint;
if (TextUtils.isEmpty(url)) {
return null;
}
if (!TextUtils.isEmpty(url) && (!url.startsWith("http://") && !url.startsWith("https://"))) {
url = "https://" + url;
}
if (!url.endsWith("/")) {
url += "/";
}
url += mHttpDnsConfig.getAccountId() + "/metrics";
long time = System.currentTimeMillis();
url += "?t=" + time;
url += "&ssk=" + (TextUtils.isEmpty(mSecret) ? 0 : 1);
//tags
url += ResolveHostHelper.getTags(mHttpDnsConfig);
String sign = md5(md5(content) + "-" + (TextUtils.isEmpty(mSecret) ? mHttpDnsConfig.getAccountId() : mSecret) + "-" + time);
url += "&s=" + sign;
return url;
}
private Map<String, String> getHeader(int reportBatchIndex) {
Map<String, String> headers = new HashMap<>();
headers.put("User-Agent", mHttpDnsConfig.getUA());
headers.put("X-HTTPDNS-REQUEST-ID", SessionTrackMgr.getInstance().getSessionId() + "-" + reportBatchIndex);
return headers;
}
private String md5(String content) throws NoSuchAlgorithmException, UnsupportedEncodingException {
byte[] hash;
hash = MessageDigest.getInstance("MD5").digest(content.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder(hash.length * 2);
for (byte aByte : hash) {
sb.append(hexChar[(aByte & 0xf0) >>> 4]);
sb.append(hexChar[aByte & 0x0f]);
}
return sb.toString();
}
private float generateSampleBenchMarks() {
Random random = new Random(System.currentTimeMillis());
return random.nextFloat();
}
private boolean reachingReportingLimit(long current) {
int limit = mHttpDnsConfig.getObservableConfig().maxReportsPerMinute;
if (mReportsTime.size() < limit) {
return false;
}
//鍏堢Щ闄よ秴杩囨瘡鍒嗛挓涓婃姤娆℃暟鐨勪笂鎶ユ椂闂寸偣
while (mReportsTime.size() > limit) {
mReportsTime.pollFirst();
}
Long first = mReportsTime.peekFirst();
if (first == null) {
return false;
}
return current - first < DateUtils.MINUTE_IN_MILLIS;
}
}

View File

@@ -0,0 +1,25 @@
package com.newsdk.sdk.android.httpdns.observable.event;
public class BatchQueryHttpDnsApiEvent extends QueryHttpDnsApiEvent {
public BatchQueryHttpDnsApiEvent() {
super();
mEventName = 2;
}
@Override
public void setHostName(String hostName) {
//do nothing
}
@Override
public void setHttpDnsIps(String[] ipv4s, String[] ipv6s) {
//do nothing
}
@Override
public void setLocalDnsIps(String localDnsIps) {
//do nothing
}
}

View File

@@ -0,0 +1,83 @@
package com.newsdk.sdk.android.httpdns.observable.event;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.observable.ObservableConstants;
public class CallSdkApiEvent extends ObservableEvent implements GroupEvent, LocalDnsEvent {
public CallSdkApiEvent(long startTime) {
super();
mTimestamp = startTime;
mEventName = 5;
mCount = 1;
}
public void setRequestType(RequestIpType queryType) {
if (queryType == RequestIpType.v4) {
mTag |= ObservableConstants.REQUEST_IP_TYPE_V4;
} else if (queryType == RequestIpType.v6) {
mTag |= ObservableConstants.REQUEST_IP_TYPE_V6;
} else if (queryType == RequestIpType.both) {
mTag |= ObservableConstants.REQUEST_IP_TYPE_BOTH;
}
}
public void setInvokeApi(int api) {
mTag |= api;
}
public void setCacheScene(int scene) {
mTag |= scene;
}
public void setResultStatus(int status) {
mTag |= status;
}
public void setTimestamp(long timestamp) {
mTimestamp = timestamp;
}
@Override
public void setErrorCode(String errorCode) {
//do nothing
}
private void incrementCount() {
++mCount;
}
@Override
public boolean isSameGroup(ObservableEvent event) {
if (event == null) {
return false;
}
return TextUtils.equals(getHostName(), event.getHostName())
&& getTag() == event.getTag();
}
@Override
public void groupWith(ObservableEvent event) {
setTimestamp(event.getTimestamp());
mServerIp = event.getServerIp();
int totalCostTime = getCostTime() * getCount();
incrementCount();
setCostTime((totalCostTime + event.getCostTime()) / getCount());
if (!TextUtils.isEmpty(event.getHttpDnsIps())) {
mHttpDnsIps = event.getHttpDnsIps();
}
if (!TextUtils.isEmpty(event.getLocalDnsIps())) {
mLocalDnsIps = event.getLocalDnsIps();
mLocalDnsCost = event.getLocalDnsCost();
}
}
@Override
public int getRequestIpType() {
return mTag;
}
}

View File

@@ -0,0 +1,45 @@
package com.newsdk.sdk.android.httpdns.observable.event;
public class CleanHostCacheEvent extends ObservableEvent {
public CleanHostCacheEvent() {
super();
mEventName = 6;
mCount = 1;
}
public void setTag(int cleanType) {
mTag = cleanType;
}
@Override
public void setHostName(String hostName) {
//do nothing
}
@Override
public void setServerIp(String serverIp) {
//do nothing
}
@Override
public void setIpType(int type) {
//do nothing
}
@Override
public void setErrorCode(String errorCode) {
//do nothing
}
@Override
public void setHttpDnsIps(String[] ipv4s, String[] ipv6s) {
//do nothing
}
@Override
public void setLocalDnsIps(String localDnsIps) {
//do nothing
}
}

View File

@@ -0,0 +1,11 @@
package com.newsdk.sdk.android.httpdns.observable.event;
/**
* 闇€瑕佽仛鍚堢殑浜嬩欢
*/
public interface GroupEvent {
boolean isSameGroup(ObservableEvent event);
void groupWith(ObservableEvent event);
}

View File

@@ -0,0 +1,68 @@
package com.newsdk.sdk.android.httpdns.observable.event;
import com.newsdk.sdk.android.httpdns.observable.ObservableConstants;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
public interface LocalDnsEvent {
default void localDns(String host) {
try {
long localDnsStart = System.currentTimeMillis();
InetAddress[] addresses = InetAddress.getAllByName(host);
long localDnsCost = System.currentTimeMillis() - localDnsStart;
if (addresses != null && addresses.length > 0) {
List<String> ips = new ArrayList<>();
List<String> ipv6s = new ArrayList<>();
for (InetAddress address : addresses) {
if (address instanceof Inet4Address) {
ips.add(address.getHostAddress());
} else if (address instanceof Inet6Address) {
ipv6s.add(address.getHostAddress());
}
}
StringBuilder sb = new StringBuilder();
int ipType = getRequestIpType();
if ((ipType & ObservableConstants.REQUEST_IP_TYPE_V4) == ObservableConstants.REQUEST_IP_TYPE_V4) {
for (int i = 0; i != ips.size(); ++i) {
sb.append(ips.get(i));
if (i != ips.size() - 1) {
sb.append(",");
}
}
}
if ((ipType & ObservableConstants.REQUEST_IP_TYPE_V6) ==ObservableConstants.REQUEST_IP_TYPE_V6) {
if (!ipv6s.isEmpty() && sb.length() > 0) {
sb.append(";");
}
for (int i = 0; i != ipv6s.size(); ++i) {
sb.append(ipv6s.get(i));
if (i != ipv6s.size() - 1) {
sb.append(",");
}
}
}
if (this instanceof ObservableEvent) {
((ObservableEvent) this).setLocalDnsIps(sb.toString());
((ObservableEvent) this).setLocalDnsCost(localDnsCost);
}
}
} catch (Exception e) {
}
}
/**
* 杩斿洖鍊煎拰tag涓殑璇锋眰绫诲瀷淇濇寔涓€鑷?
* @return
*/
abstract int getRequestIpType();
}

View File

@@ -0,0 +1,177 @@
package com.newsdk.sdk.android.httpdns.observable.event;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsServiceImpl;
import com.newsdk.sdk.android.httpdns.observable.ObservableConstants;
import com.newsdk.sdk.android.httpdns.utils.NetworkUtil;
public abstract class ObservableEvent {
private static final String DIVIDER = "|";
protected int mEventName;
protected int mTag;
protected String mHostName;
protected long mTimestamp;
protected String mServerIp;
protected int mCostTime;
private String mIpType;
protected int mStatusCode;
protected String mErrorCode;
protected int mCount;
private String mNetworkType;
protected String mHttpDnsIps;
protected String mLocalDnsIps;
protected long mLocalDnsCost;
protected ObservableEvent() {
mTimestamp = System.currentTimeMillis();
mNetworkType = String.valueOf(NetworkUtil.getNetworkType(HttpDnsServiceImpl.sContext));
}
public int getEventName() {
return mEventName;
}
public int getTag() {
return mTag;
}
public void setHostName(String hostName) {
mHostName = hostName;
}
public String getHostName() {
return mHostName;
}
public long getTimestamp() {
return mTimestamp;
}
public void setServerIp(String serverIp) {
mServerIp = serverIp;
}
public String getServerIp() {
return mServerIp;
}
public void setCostTime(int time) {
mCostTime = time;
}
public int getCostTime() {
return mCostTime;
}
public void setIpType(int type) {
mIpType = String.valueOf(type);
}
public int getIpType() {
return Integer.parseInt(mIpType);
}
public void setStatusCode(int statusCode) {
mStatusCode = statusCode;
}
public int getStatusCode() {
return mStatusCode;
}
public void setErrorCode(String errorCode) {
if (TextUtils.isEmpty(errorCode)) {
return;
}
if (errorCode.length() > 128) {
mErrorCode = errorCode.substring(0, 128);
} else {
mErrorCode = errorCode;
}
}
public String getErrorCode() {
return mErrorCode;
}
public int getCount() {
return mCount;
}
public void setHttpDnsIps(String[] ipv4s, String[] ipv6s) {
int ipType = 0;
if (ipv4s != null && ipv4s.length > 0) {
ipType |= ObservableConstants.REQUEST_IP_TYPE_V4;
}
if (ipv6s != null && ipv6s.length > 0) {
ipType |= ObservableConstants.REQUEST_IP_TYPE_V6;
}
setIpType(ipType);
StringBuilder sb = new StringBuilder();
if (ipv4s != null) {
for (int i = 0; i != ipv4s.length; ++i) {
sb.append(ipv4s[i]);
if (i != ipv4s.length - 1) {
sb.append(",");
}
}
}
if (ipv6s != null) {
if (ipv6s.length != 0 && sb.length() > 0) {
sb.append(";");
}
for (int i = 0; i != ipv6s.length; ++i) {
sb.append(ipv6s[i]);
if (i != ipv6s.length - 1) {
sb.append(",");
}
}
}
mHttpDnsIps = sb.toString();
}
public String getHttpDnsIps() {
return mHttpDnsIps;
}
public void setLocalDnsIps(String localDnsIps) {
mLocalDnsIps = localDnsIps;
}
public String getLocalDnsIps() {
return mLocalDnsIps;
}
public void setLocalDnsCost(long localDnsCost) {
mLocalDnsCost = localDnsCost;
}
public long getLocalDnsCost() {
return mLocalDnsCost;
}
public String toString() {
return mEventName +
DIVIDER + mTag +
DIVIDER + (TextUtils.isEmpty(mHostName) ? "" : mHostName) +
DIVIDER + mTimestamp +
DIVIDER + (TextUtils.isEmpty(mServerIp) ? "" : mServerIp) +
DIVIDER + mCostTime +
DIVIDER + (TextUtils.isEmpty(mNetworkType) ? "" : mNetworkType) + //棰勭暀鐨勭綉缁滅被鍨?
DIVIDER + ((TextUtils.isEmpty(mIpType)) ? "" : mIpType) +
DIVIDER + mStatusCode +
DIVIDER + (TextUtils.isEmpty(mErrorCode) ? "" : mErrorCode) +
DIVIDER + mCount +
DIVIDER + (TextUtils.isEmpty(mHttpDnsIps) ? "" : mHttpDnsIps) +
DIVIDER + (TextUtils.isEmpty(mLocalDnsIps) ? "" : mLocalDnsIps) +
DIVIDER + mLocalDnsCost;
}
}

View File

@@ -0,0 +1,37 @@
package com.newsdk.sdk.android.httpdns.observable.event;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.observable.ObservableConstants;
public class QueryHttpDnsApiEvent extends ObservableEvent implements LocalDnsEvent {
public QueryHttpDnsApiEvent() {
super();
mEventName = 3;
mCount = 1;
}
public void setTag(boolean isRetry, RequestIpType queryType, boolean http, boolean signMode) {
mTag = isRetry ? ObservableConstants.REQUEST_RETRY : ObservableConstants.REQUEST_NOT_RETRY;
if (queryType == RequestIpType.v4) {
mTag |= ObservableConstants.REQUEST_IP_TYPE_V4;
} else if (queryType == RequestIpType.v6) {
mTag |= ObservableConstants.REQUEST_IP_TYPE_V6;
} else if (queryType == RequestIpType.both) {
mTag |= ObservableConstants.REQUEST_IP_TYPE_BOTH;
}
if (!http) {
mTag |= ObservableConstants.HTTPS_REQUEST;
}
if (signMode) {
mTag |= ObservableConstants.SIGN_MODE_REQUEST;
}
}
@Override
public int getRequestIpType() {
return mTag;
}
}

View File

@@ -0,0 +1,45 @@
package com.newsdk.sdk.android.httpdns.observable.event;
public class ReportingRateExceptionEvent extends ObservableEvent {
public ReportingRateExceptionEvent() {
super();
mEventName = 8;
mCount = 1;
}
public void setTag(int eventName) {
mTag = eventName;
}
@Override
public void setHostName(String hostName) {
//do nothing
}
@Override
public void setCostTime(int time) {
mCostTime = 0;
}
@Override
public void setIpType(int type) {
//do nothing
}
@Override
public void setErrorCode(String errorCode) {
//do nothing
}
@Override
public void setHttpDnsIps(String[] ipv4s, String[] ipv6s) {
//do nothing
}
@Override
public void setLocalDnsIps(String localDnsIps) {
//do nothing
}
}

View File

@@ -0,0 +1,53 @@
package com.newsdk.sdk.android.httpdns.observable.event;
import com.newsdk.sdk.android.httpdns.utils.Constants;
public class UpdateRegionServerIpsEvent extends ObservableEvent {
public UpdateRegionServerIpsEvent() {
super();
mEventName = 7;
mCount = 1;
}
public void setTag(int scenes) {
if (scenes == Constants.UPDATE_REGION_SERVER_SCENES_INIT) {
mTag = 3;
} else if (scenes == Constants.UPDATE_REGION_SERVER_SCENES_REGION_CHANGE) {
mTag = 2;
} else if (scenes == Constants.UPDATE_REGION_SERVER_SCENES_SERVER_UNAVAILABLE) {
mTag = 1;
}
}
@Override
public void setHostName(String hostName) {
//do nothing
}
@Override
public void setServerIp(String serverIp) {
//do nothing
}
@Override
public void setIpType(int type) {
//do nothing
}
@Override
public void setErrorCode(String errorCode) {
//do nothing
}
@Override
public void setHttpDnsIps(String[] ipv4s, String[] ipv6s) {
//do nothing
}
@Override
public void setLocalDnsIps(String localDnsIps) {
//do nothing
}
}

View File

@@ -0,0 +1,49 @@
package com.newsdk.sdk.android.httpdns.ranking;
/**
* IP浼橀€夐厤缃」
*/
public class IPRankingBean {
/**
* 杩涜ip浼橀€夌殑鍩熷悕
*/
String hostName;
/**
* 鐢ㄤ簬娴嬭瘯閫熷害鐨勭鍙?
*/
int port;
public IPRankingBean(String hostName, int port) {
this.hostName = hostName;
this.port = port;
}
public String getHostName() {
return hostName;
}
public int getPort() {
return port;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
IPRankingBean that = (IPRankingBean)o;
return port == that.port && hostName != null && hostName.equals(that.hostName);
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + (hostName == null ? 0 : hostName.hashCode());
hash = 31 * hash + port;
return hash;
}
}

View File

@@ -0,0 +1,9 @@
package com.newsdk.sdk.android.httpdns.ranking;
/**
* IP浼橀€夌殑缁撴灉鍥炶皟
*/
public interface IPRankingCallback {
void onResult(String host, String[] sortedIps);
}

View File

@@ -0,0 +1,80 @@
package com.newsdk.sdk.android.httpdns.ranking;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentSkipListSet;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsConfig;
/**
* IP浼橀€夋湇鍔?
*/
public class IPRankingService {
private final HttpDnsConfig mHttpDnsConfig;
private List<IPRankingBean> mIPRankingBeanList;
private IPRankingTask.SpeedTestSocketFactory mSocketFactory
= new IPRankingTask.SpeedTestSocketFactory() {
@Override
public Socket create() {
return new Socket();
}
};
private final ConcurrentSkipListSet<String> mProbingHosts = new ConcurrentSkipListSet<>();
public IPRankingService(HttpDnsConfig config) {
this.mHttpDnsConfig = config;
}
/**
* 杩涜ipv4浼橀€?
*/
public void probeIpv4(String host, String[] ips, final IPRankingCallback IPRankingCallback) {
if (mHttpDnsConfig.isIPRankingDisabled()) {
return;
}
IPRankingBean ipRankingBean = getIPRankingBean(host);
if (ipRankingBean != null && ips != null && ips.length > 1) {
if (mProbingHosts.contains(host)) {
return;
}
mProbingHosts.add(host);
try {
mHttpDnsConfig.getWorker().execute(
new IPRankingTask(mSocketFactory, host, ips, ipRankingBean, new IPRankingCallback() {
@Override
public void onResult(String host, String[] sortedIps) {
mProbingHosts.remove(host);
if (IPRankingCallback != null) {
IPRankingCallback.onResult(host, sortedIps);
}
}
}));
} catch (Exception e) {
mProbingHosts.remove(host);
}
}
}
public void setIPRankingList(List<IPRankingBean> ipRankingBeanList) {
this.mIPRankingBeanList = ipRankingBeanList;
}
public void setSocketFactory(IPRankingTask.SpeedTestSocketFactory socketFactory) {
this.mSocketFactory = socketFactory;
}
private IPRankingBean getIPRankingBean(String host) {
if (mIPRankingBeanList != null && mIPRankingBeanList.size() > 0) {
ArrayList<IPRankingBean> list = new ArrayList<>(mIPRankingBeanList);
for (IPRankingBean item : list) {
if (host.equals(item.getHostName())) {
return item;
}
}
}
return null;
}
}

View File

@@ -0,0 +1,64 @@
package com.newsdk.sdk.android.httpdns.ranking;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
/**
* ip浼橀€夊疄鐜?
*/
public class IPRankingTask implements Runnable {
public interface SpeedTestSocketFactory {
Socket create();
}
private final SpeedTestSocketFactory mSocketFactory;
private final String mHost;
private final String[] mIps;
private final IPRankingBean mIPRankingBean;
private final IPRankingCallback mIPRankingCallback;
public IPRankingTask(SpeedTestSocketFactory socketFactory, String host, String[] ips,
IPRankingBean ipRankingBean, IPRankingCallback IPRankingCallback) {
this.mSocketFactory = socketFactory;
this.mHost = host;
this.mIps = ips;
this.mIPRankingBean = ipRankingBean;
this.mIPRankingCallback = IPRankingCallback;
}
@Override
public void run() {
int[] speeds = new int[mIps.length];
for (int i = 0; i < mIps.length; i++) {
speeds[i] = testConnectSpeed(mIps[i], mIPRankingBean.getPort());
}
String[] result = CommonUtil.sortIpsWithSpeeds(mIps, speeds);
if (mIPRankingCallback != null) {
mIPRankingCallback.onResult(mHost, result);
}
}
private int testConnectSpeed(String ip, int port) {
long start = System.currentTimeMillis();
long end = Long.MAX_VALUE;
try (Socket socket = mSocketFactory.create()) {
SocketAddress remoteAddress = new InetSocketAddress(ip, port);
socket.connect(remoteAddress, 5 * 1000);
end = System.currentTimeMillis();
} catch (IOException e) {
e.printStackTrace();
}
if (end == Long.MAX_VALUE) {
return Integer.MAX_VALUE;
}
return (int) (end - start);
}
}

View File

@@ -0,0 +1,34 @@
package com.newsdk.sdk.android.httpdns.request;
/**
* 鏁版嵁璇锋眰杞紓姝?
*/
public abstract class AsyncRequestTask<T> implements Runnable {
private final RequestCallback<T> mCallback;
public AsyncRequestTask(RequestCallback<T> callback) {
this.mCallback = callback;
}
/**
* 璇锋眰鏁版嵁锛屼笉闇€瑕佺洿鎺ヨ皟鐢紝闄ら潪鎯宠鍚屾鑾峰彇璇锋眰鏁版嵁
*/
public abstract T request() throws Throwable;
@Override
public void run() {
try {
T t = request();
if (mCallback != null) {
mCallback.onSuccess(t);
}
} catch (Throwable throwable) {
throwable.printStackTrace();
if (mCallback != null) {
mCallback.onFail(throwable);
}
}
}
}

View File

@@ -0,0 +1,74 @@
package com.newsdk.sdk.android.httpdns.request;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.observable.ObservableConstants;
import com.newsdk.sdk.android.httpdns.observable.ObservableManager;
import com.newsdk.sdk.android.httpdns.observable.event.BatchQueryHttpDnsApiEvent;
import com.newsdk.sdk.android.httpdns.resolve.ResolveHostResponse;
public class BatchResolveHttpRequestStatusWatcher implements HttpRequestWatcher.Watcher {
ObservableManager observableManager;
private BatchQueryHttpDnsApiEvent mBatchQueryHttpDnsApiEvent;
public BatchResolveHttpRequestStatusWatcher(ObservableManager observableManager) {
this.observableManager = observableManager;
}
@Override
public void onStart(HttpRequestConfig config) {
mBatchQueryHttpDnsApiEvent = new BatchQueryHttpDnsApiEvent();
}
@Override
public void onSuccess(HttpRequestConfig config, Object data) {
if (mBatchQueryHttpDnsApiEvent != null && observableManager != null) {
mBatchQueryHttpDnsApiEvent.setTag(config.isRetry(), config.getResolvingIpType(),
HttpRequestConfig.HTTP_SCHEMA.equals(config.getSchema()), config.isSignMode());
mBatchQueryHttpDnsApiEvent.setServerIp(config.getIp());
mBatchQueryHttpDnsApiEvent.setCostTime((int) (System.currentTimeMillis() - mBatchQueryHttpDnsApiEvent.getTimestamp()));
int resultIpType = 0x00;
if (data instanceof ResolveHostResponse) {
for (ResolveHostResponse.HostItem item : ((ResolveHostResponse) data).getItems()) {
if (item.getIpType() == RequestIpType.v4) {
resultIpType |= ObservableConstants.REQUEST_IP_TYPE_V4;
} else if (item.getIpType() == RequestIpType.v6) {
resultIpType |= ObservableConstants.REQUEST_IP_TYPE_V6;
}
}
}
mBatchQueryHttpDnsApiEvent.setIpType(resultIpType);
mBatchQueryHttpDnsApiEvent.setStatusCode(resultIpType == 0x00 ? 204 : 200);
observableManager.addObservableEvent(mBatchQueryHttpDnsApiEvent);
mBatchQueryHttpDnsApiEvent = null;
}
}
@Override
public void onFail(HttpRequestConfig config, Throwable throwable) {
if (mBatchQueryHttpDnsApiEvent != null && observableManager != null) {
mBatchQueryHttpDnsApiEvent.setTag(config.isRetry(), config.getResolvingIpType(),
HttpRequestConfig.HTTP_SCHEMA.equals(config.getSchema()), config.isSignMode());
mBatchQueryHttpDnsApiEvent.setServerIp(config.getIp());
mBatchQueryHttpDnsApiEvent.setCostTime((int) (System.currentTimeMillis() - mBatchQueryHttpDnsApiEvent.getTimestamp()));
mBatchQueryHttpDnsApiEvent.setIpType(0x00);
if (throwable instanceof HttpException) {
mBatchQueryHttpDnsApiEvent.setStatusCode(((HttpException) throwable).getCode());
String errorCode = throwable.getMessage();
mBatchQueryHttpDnsApiEvent.setErrorCode(TextUtils.isEmpty(errorCode) ? "Unknown" : errorCode);
} else {
mBatchQueryHttpDnsApiEvent.setStatusCode(-1);
mBatchQueryHttpDnsApiEvent.setErrorCode(throwable.getClass().getSimpleName() + ":" + throwable.getMessage());
}
observableManager.addObservableEvent(mBatchQueryHttpDnsApiEvent);
mBatchQueryHttpDnsApiEvent = null;
}
}
}

View File

@@ -0,0 +1,156 @@
package com.newsdk.sdk.android.httpdns.request;
import java.util.Arrays;
import org.json.JSONException;
import org.json.JSONObject;
/**
* 缃戠粶璇锋眰澶辫触鐨勫紓甯?
*/
public class HttpException extends Exception {
public static final int ERROR_CODE_403 = 403;
public static final int ERROR_CODE_400 = 400;
public static final int ERROR_CODE_500 = 500;
/**
* 鐢ㄦ埛鏈嶅姟level涓嶅尮閰?
* 锛堢敤鎴锋湁涓嶅悓鐨刲evel锛岄珮level鏈変竴浜涗笓鐢ㄧ殑鏈嶅姟鑺傜偣锛屽鏋滀竴涓綆level鐨勭敤鎴凤紝鍚戜竴涓珮level涓撶敤鐨勬湇鍔¤妭鐐硅姹傦紝灏变細杩斿洖姝ら敊璇級
* <p>
* 闇€瑕侀噸璇?鍒囨崲鏈嶅姟IP
*/
public static final String ERROR_MSG_SERVICE_LEVEL_DENY = "ServiceLevelDeny";
/**
* 鏈敤绛惧悕璁块棶
* 涓嶉噸璇?涓嶅垏鎹?
* 鐢熸垚绌鸿В鏋?缂撳瓨1灏忔椂
*/
public static final String ERROR_MSG_UNSIGNED = "UnsignedInterfaceDisabled";
/**
* 绛惧悕杩囨湡
* 涓嶉噸璇?涓嶅垏鎹?锛坰dk閫昏緫淇濊瘉涓嶅簲璇ヨ繃鏈燂級
*/
public static final String ERROR_MSG_SIGNATURE_EXPIRED = "SignatureExpired";
/**
* 绛惧悕楠岃瘉澶辫触
* 涓嶉噸璇?涓嶅垏鎹?
*/
public static final String ERROR_MSG_INVALID_SIGNATURE = "InvalidSignature";
/**
* 璐︽埛鏈嶅姟level缂哄け
* 涓嶉噸璇?涓嶅垏鎹?
* 鐢熸垚绌鸿В鏋?缂撳瓨1灏忔椂
*/
public static final String ERROR_MSG_INVALID_ACCOUNT = "InvalidAccount";
/**
* 璐︽埛涓嶅瓨鍦ㄦ垨鑰呯鐢?
* 涓嶉噸璇?涓嶅垏鎹?
* 鐢熸垚绌鸿В鏋?缂撳瓨1灏忔椂
*/
public static final String ERROR_MSG_ACCOUNT_NOT_EXISTS = "AccountNotExists";
/**
* 绛惧悕鏈夋晥鏃堕棿杩囬暱
* 涓嶉噸璇?涓嶅垏鎹?
*/
public static final String ERROR_MSG_INVALID_DURATION = "InvalidDuration";
/**
* 鏃犳晥鍩熷悕
* 涓嶉噸璇?涓嶅垏鎹?
*/
public static final String ERROR_MSG_INVALID_HOST = "InvalidHost";
public static final String ERROR_MSG_TAG = "code";
private final int mCode;
private HttpException(int code, String message) {
super(message);
this.mCode = code;
}
/**
* Http status code
*/
public int getCode() {
return mCode;
}
/**
* 鍒涘缓寮傚父
*
* @param code
* @param message 鏈嶅姟鍣ㄨ繑鍥炵殑鐗瑰畾鏍煎紡鐨勬暟鎹?
* @return
*/
public static HttpException create(int code, String message) {
return new HttpException(code, tryTranslateMessage(message));
}
private static String tryTranslateMessage(String message) {
JSONObject object;
try {
object = new JSONObject(message);
return object.getString(ERROR_MSG_TAG);
} catch (JSONException ignored) {
}
return message;
}
@Override
public boolean equals(Object o) {
if (this == o) {return true;}
if (o == null || getClass() != o.getClass()) {return false;}
HttpException that = (HttpException)o;
return mCode == that.mCode && getMessage().equals(that.getMessage());
}
@Override
public int hashCode() {
return Arrays.hashCode(new Object[] {mCode, getMessage()});
}
/**
* 鏄笉鏄鍒囨崲鏈嶅姟IP
*/
public boolean shouldShiftServer() {
String msg = getMessage();
return !ERROR_MSG_UNSIGNED.equals(msg)
&& !ERROR_MSG_SIGNATURE_EXPIRED.equals(msg)
&& !ERROR_MSG_INVALID_SIGNATURE.equals(msg)
&& !ERROR_MSG_INVALID_ACCOUNT.equals(msg)
&& !ERROR_MSG_ACCOUNT_NOT_EXISTS.equals(msg)
&& !ERROR_MSG_INVALID_DURATION.equals(msg)
&& !ERROR_MSG_INVALID_HOST.equals(msg);
}
/**
* 杩欎釜閿欒鏄惁寤鸿閲嶈瘯
*/
public boolean shouldRetry() {
String msg = getMessage();
return !ERROR_MSG_UNSIGNED.equals(msg)
&& !ERROR_MSG_SIGNATURE_EXPIRED.equals(msg)
&& !ERROR_MSG_INVALID_SIGNATURE.equals(msg)
&& !ERROR_MSG_INVALID_ACCOUNT.equals(msg)
&& !ERROR_MSG_ACCOUNT_NOT_EXISTS.equals(msg)
&& !ERROR_MSG_INVALID_DURATION.equals(msg)
&& !ERROR_MSG_INVALID_HOST.equals(msg);
}
/**
* 杩欎釜閿欒鏄惁瑕佸垱寤虹┖缂撳瓨
*/
public boolean shouldCreateEmptyCache() {
String msg = getMessage();
return ERROR_MSG_UNSIGNED.equals(msg)
|| ERROR_MSG_INVALID_ACCOUNT.equals(msg)
|| ERROR_MSG_ACCOUNT_NOT_EXISTS.equals(msg);
}
}

View File

@@ -0,0 +1,212 @@
package com.newsdk.sdk.android.httpdns.request;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
/**
* HTTP request wrapper for resolve APIs.
*/
public class HttpRequest<T> {
private HttpRequestConfig requestConfig;
private ResponseParser<T> translator;
protected HttpRequest() {
}
public HttpRequest(HttpRequestConfig requestConfig, ResponseParser<T> translator) {
this.requestConfig = requestConfig;
this.translator = translator;
}
public HttpRequestConfig getRequestConfig() {
return requestConfig;
}
public T request() throws Throwable {
HttpURLConnection conn = null;
InputStream in = null;
BufferedReader streamReader = null;
long start = System.currentTimeMillis();
String serverIp = requestConfig.getIp();
String url = requestConfig.url();
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("request url " + url);
}
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setReadTimeout(requestConfig.getTimeout());
conn.setConnectTimeout(requestConfig.getTimeout());
conn.setRequestProperty("User-Agent", requestConfig.getUA());
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
String serverHost = requestConfig.getIp();
if (serverHost != null && !CommonUtil.isAnIP(serverHost)) {
// Server is a domain name — explicitly set SNI so CDN/proxy
// can select the correct certificate during TLS handshake.
SSLSocketFactory base = (SSLSocketFactory) SSLSocketFactory.getDefault();
httpsConn.setSSLSocketFactory(new SniSocketFactory(base, serverHost));
final String sniHost = serverHost;
final HostnameVerifier defaultVerifier =
HttpsURLConnection.getDefaultHostnameVerifier();
httpsConn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return defaultVerifier.verify(sniHost, session);
}
});
} else {
httpsConn.setHostnameVerifier(
HttpsURLConnection.getDefaultHostnameVerifier());
}
}
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
in = conn.getErrorStream();
if (in != null) {
streamReader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
String errStr = readStringFrom(streamReader).toString();
throw HttpException.create(conn.getResponseCode(), errStr);
} else {
throw HttpException.create(conn.getResponseCode(), "");
}
} else {
in = conn.getInputStream();
streamReader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
String responseStr = readStringFrom(streamReader).toString();
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("request success " + responseStr);
}
return translator.parse(serverIp, responseStr);
}
} catch (Throwable e) {
long cost = System.currentTimeMillis() - start;
HttpDnsLog.w("request " + url + " fail, cost " + cost, e);
throw e;
} finally {
if (conn != null) {
conn.disconnect();
}
try {
if (in != null) {
in.close();
}
if (streamReader != null) {
streamReader.close();
}
} catch (IOException ignored) {
}
}
}
public static StringBuilder readStringFrom(BufferedReader streamReader) throws IOException {
StringBuilder sb = new StringBuilder();
String line;
while ((line = streamReader.readLine()) != null) {
sb.append(line);
}
return sb;
}
/**
* SSLSocketFactory that explicitly sets SNI (Server Name Indication)
* to the specified hostname. Used for HTTPDNS API calls where the
* server is accessed by domain name (e.g. behind a CDN).
*/
private static class SniSocketFactory extends SSLSocketFactory {
private final SSLSocketFactory delegate;
private final String sniHostname;
SniSocketFactory(SSLSocketFactory delegate, String sniHostname) {
this.delegate = delegate;
this.sniHostname = sniHostname;
}
@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
@Override
public java.net.Socket createSocket(java.net.Socket s, String host, int port,
boolean autoClose) throws IOException {
// Pass the domain as host so the SSL layer sets SNI correctly
return applySni(delegate.createSocket(s, sniHostname, port, autoClose));
}
@Override
public java.net.Socket createSocket(String host, int port) throws IOException {
return applySni(delegate.createSocket(host, port));
}
@Override
public java.net.Socket createSocket(String host, int port,
java.net.InetAddress localHost, int localPort)
throws IOException {
return applySni(delegate.createSocket(host, port, localHost, localPort));
}
@Override
public java.net.Socket createSocket(java.net.InetAddress host, int port)
throws IOException {
return applySni(delegate.createSocket(host, port));
}
@Override
public java.net.Socket createSocket(java.net.InetAddress address, int port,
java.net.InetAddress localAddress, int localPort)
throws IOException {
return applySni(delegate.createSocket(address, port, localAddress, localPort));
}
private java.net.Socket applySni(java.net.Socket socket) {
if (!(socket instanceof SSLSocket)) {
return socket;
}
SSLSocket sslSocket = (SSLSocket) socket;
try {
SSLParameters params = sslSocket.getSSLParameters();
try {
// API 24+: SSLParameters.setServerNames(List<SNIServerName>)
Class<?> sniClass = Class.forName("javax.net.ssl.SNIHostName");
Object sniName = sniClass.getConstructor(String.class)
.newInstance(sniHostname);
java.lang.reflect.Method setter = SSLParameters.class
.getMethod("setServerNames", List.class);
setter.invoke(params, Collections.singletonList(sniName));
} catch (Throwable ignored) {
}
sslSocket.setSSLParameters(params);
} catch (Throwable ignored) {
}
// Fallback for older Android: Conscrypt's setHostname()
try {
java.lang.reflect.Method setHostname = sslSocket.getClass()
.getMethod("setHostname", String.class);
setHostname.invoke(sslSocket, sniHostname);
} catch (Throwable ignored) {
}
return sslSocket;
}
}
}

View File

@@ -0,0 +1,170 @@
package com.newsdk.sdk.android.httpdns.request;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.impl.AESEncryptService;
import com.newsdk.sdk.android.httpdns.utils.Constants;
/**
* 缃戠粶璇锋眰鐨勯厤缃?
*/
public class HttpRequestConfig {
public static final String HTTP_SCHEMA = "http://";
public static final String HTTPS_SCHEMA = "https://";
public static final String HTTPS_CERTIFICATE_HOSTNAME = "203.107.1.1";
/**
* 璇锋眰鍗忚
*/
private String mSchema = HTTP_SCHEMA;
/**
* 鏈嶅姟鍣╥p
*/
private String mIp;
/**
* 鏈嶅姟鍣ㄧ鍙?
*/
private int mPort;
/**
* 璇锋眰璺緞锛屽寘鍚玵uery鍙傛暟
*/
private String mPath;
/**
* 璇锋眰瓒呮椂鏃堕棿
*/
private int mTimeout = Constants.DEFAULT_TIMEOUT;
/**
* 鏈嶅姟鍣↖P绫诲瀷 鍙細鏄?v4 鎴栬€?v6
*/
private RequestIpType mIpType = RequestIpType.v4;
private String mUA = "";
//寰呰В鏋愮殑鍩熷悕
private String mResolvingHost;
//寰呰В鏋愮殑鍩熷悕鐨刬p绫诲瀷
private RequestIpType mResolvingIpType;
//鏄笉鏄噸璇?
private boolean isRetry = false;
private boolean isSignMode = false;
private AESEncryptService mAESEncryptService;
public HttpRequestConfig(String ip, int port, String path) {
this.mIp = ip;
this.mPort = port;
this.mPath = path;
}
public HttpRequestConfig(String schema, String ip, int port, String path, int timeout, RequestIpType ipType) {
this.mSchema = schema;
this.mIp = ip;
this.mPort = port;
this.mPath = path;
this.mTimeout = timeout;
this.mIpType = ipType;
}
public HttpRequestConfig(String schema, String ip, int port, String path, int timeout, RequestIpType ipType, boolean signMode) {
this.mSchema = schema;
this.mIp = ip;
this.mPort = port;
this.mPath = path;
this.mTimeout = timeout;
this.mIpType = ipType;
isSignMode = signMode;
}
public void setSchema(String schema) {
this.mSchema = schema;
}
public void setIp(String ip) {
this.mIp = ip;
}
public void setPort(int port) {
this.mPort = port;
}
public String getSchema() {
return this.mSchema;
}
public String getIp() {
return mIp;
}
public int getPort() {
return mPort;
}
public void setTimeout(int timeout) {
this.mTimeout = timeout;
}
public int getTimeout() {
return mTimeout;
}
public RequestIpType getIpType() {
return mIpType;
}
public String url() {
if (mIpType == RequestIpType.v6) {
//鍩熷悕鍏滃簳锛岃繖閲岄渶瑕佸鍩熷悕鍋氱壒娈婂鐞?
if (!TextUtils.isEmpty(mIp) && mIp.contains(".")) {
return mSchema + mIp + ":" + mPort + mPath;
}
return mSchema + "[" + mIp + "]" + ":" + mPort + mPath;
} else {
return mSchema + mIp + ":" + mPort + mPath;
}
}
public void setUA(String ua) {
mUA = ua;
}
public String getUA() {
return mUA;
}
public void setResolvingHost(String host) {
mResolvingHost = host;
}
public String getResolvingHost() {
return mResolvingHost;
}
public void setResolvingIpType(RequestIpType type) {
mResolvingIpType = type;
}
public RequestIpType getResolvingIpType() {
return mResolvingIpType;
}
public void setRetry() {
isRetry = true;
}
public boolean isRetry() {
return isRetry;
}
public boolean isSignMode() {
return isSignMode;
}
public AESEncryptService getAESEncryptService() {
return mAESEncryptService;
}
public void setAESEncryptService(AESEncryptService mAESEncryptService) {
this.mAESEncryptService = mAESEncryptService;
}
}

View File

@@ -0,0 +1,26 @@
package com.newsdk.sdk.android.httpdns.request;
import com.newsdk.sdk.android.httpdns.observable.ObservableManager;
public class HttpRequestFailWatcher implements HttpRequestWatcher.Watcher {
public HttpRequestFailWatcher(ObservableManager reportManager) {
}
@Override
public void onStart(HttpRequestConfig config) {
}
@Override
public void onSuccess(HttpRequestConfig config, Object data) {
}
@Override
public void onFail(HttpRequestConfig config, Throwable throwable) {
}
}

View File

@@ -0,0 +1,20 @@
package com.newsdk.sdk.android.httpdns.request;
/**
* 缃戠粶璇锋眰鐨勫紓姝ヤ换鍔?
*/
public class HttpRequestTask<T> extends AsyncRequestTask<T> {
private final HttpRequest<T> mHttpRequest;
public HttpRequestTask(HttpRequest<T> httpRequest, RequestCallback<T> callback) {
super(callback);
this.mHttpRequest = httpRequest;
}
@Override
public T request() throws Throwable {
return mHttpRequest.request();
}
}

View File

@@ -0,0 +1,54 @@
package com.newsdk.sdk.android.httpdns.request;
/**
* 鐩戝惉缃戠粶璇锋眰锛岀敤浜庨檮鍔犱笟鍔¢€昏緫
*/
public class HttpRequestWatcher<T> extends HttpRequestWrapper<T> {
private final Watcher mWatcher;
public HttpRequestWatcher(HttpRequest<T> request, Watcher watcher) {
super(request);
this.mWatcher = watcher;
}
@Override
public T request() throws Throwable {
try {
if (mWatcher != null) {
try {
mWatcher.onStart(getRequestConfig());
} catch (Exception e) {
e.printStackTrace();
}
}
T t = super.request();
if (mWatcher != null) {
try {
mWatcher.onSuccess(getRequestConfig(), t);
} catch (Exception e) {
e.printStackTrace();
}
}
return t;
} catch (Throwable throwable) {
if (mWatcher != null) {
try {
mWatcher.onFail(getRequestConfig(), throwable);
} catch (Exception e) {
e.printStackTrace();
}
}
throw throwable;
}
}
public interface Watcher {
void onStart(HttpRequestConfig config);
void onSuccess(HttpRequestConfig config, Object data);
void onFail(HttpRequestConfig config, Throwable throwable);
}
}

View File

@@ -0,0 +1,24 @@
package com.newsdk.sdk.android.httpdns.request;
/**
* 缃戠粶璇锋眰鐨勫寘瑁呯被
*/
public class HttpRequestWrapper<T> extends HttpRequest<T> {
private final HttpRequest<T> mHttpRequest;
public HttpRequestWrapper(HttpRequest<T> request) {
this.mHttpRequest = request;
}
@Override
public HttpRequestConfig getRequestConfig() {
return mHttpRequest.getRequestConfig();
}
@Override
public T request() throws Throwable {
return mHttpRequest.request();
}
}

View File

@@ -0,0 +1,11 @@
package com.newsdk.sdk.android.httpdns.request;
/**
* http璇锋眰缁撴灉鍥炶皟
*/
public interface RequestCallback<T> {
void onSuccess(T response);
void onFail(Throwable throwable);
}

View File

@@ -0,0 +1,9 @@
package com.newsdk.sdk.android.httpdns.request;
/**
* http鍝嶅簲瑙
*/
public interface ResponseParser<T> {
T parse(String serverIp, String response) throws Throwable;
}

View File

@@ -0,0 +1,45 @@
package com.newsdk.sdk.android.httpdns.request;
/**
* 澶辫触鏃?閲嶈瘯璇锋眰
*/
public class RetryHttpRequest<T> extends HttpRequestWrapper<T> {
private int retryCount;
public RetryHttpRequest(HttpRequest<T> request, int retryCount) {
super(request);
this.retryCount = retryCount;
}
@Override
public T request() throws Throwable {
while (true) {
try {
return super.request();
} catch (Throwable throwable) {
if (shouldRetry(throwable)) {
if (retryCount > 0) {
//鍙娴嬮渶瑕?
getRequestConfig().setRetry();
retryCount--;
} else {
throw throwable;
}
} else {
throw throwable;
}
}
}
}
private boolean shouldRetry(Throwable throwable) {
if (throwable instanceof HttpException) {
return ((HttpException)throwable).shouldRetry();
} else {
// 鍏跺畠寮傚父閮藉彲浠ラ噸璇?
return true;
}
}
}

View File

@@ -0,0 +1,82 @@
package com.newsdk.sdk.android.httpdns.request;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.observable.ObservableManager;
import com.newsdk.sdk.android.httpdns.observable.event.QueryHttpDnsApiEvent;
import com.newsdk.sdk.android.httpdns.resolve.ResolveHostResponse;
public class SingleResolveHttpRequestStatusWatcher implements HttpRequestWatcher.Watcher {
private final ObservableManager observableManager;
private QueryHttpDnsApiEvent mQueryHttpDnsApiEvent = null;
public SingleResolveHttpRequestStatusWatcher(ObservableManager observableManager) {
this.observableManager = observableManager;
}
@Override
public void onStart(HttpRequestConfig config) {
mQueryHttpDnsApiEvent = new QueryHttpDnsApiEvent();
}
@Override
public void onSuccess(HttpRequestConfig config, Object data) {
if (mQueryHttpDnsApiEvent != null && observableManager != null) {
mQueryHttpDnsApiEvent.setTag(config.isRetry(), config.getResolvingIpType(),
HttpRequestConfig.HTTP_SCHEMA.equals(config.getSchema()), config.isSignMode());
mQueryHttpDnsApiEvent.setHostName(config.getResolvingHost());
mQueryHttpDnsApiEvent.setServerIp(config.getIp());
mQueryHttpDnsApiEvent.setCostTime((int) (System.currentTimeMillis() - mQueryHttpDnsApiEvent.getTimestamp()));
int resultIpType = 0x00;
if (data instanceof ResolveHostResponse) {
ResolveHostResponse response = (ResolveHostResponse) data;
String[] ips = null, ipv6s = null;
for (ResolveHostResponse.HostItem item : response.getItems()) {
if (item.getIpType() == RequestIpType.v4) {
resultIpType |= 0x01;
ips = item.getIps();
} else if (item.getIpType() == RequestIpType.v6) {
resultIpType |= 0x02;
ipv6s = item.getIps();
}
}
mQueryHttpDnsApiEvent.setHttpDnsIps(ips, ipv6s);
}
mQueryHttpDnsApiEvent.setIpType(resultIpType);
mQueryHttpDnsApiEvent.setStatusCode(resultIpType == 0x00 ? 204 : 200);
observableManager.addObservableEvent(mQueryHttpDnsApiEvent);
mQueryHttpDnsApiEvent = null;
}
}
@Override
public void onFail(HttpRequestConfig config, Throwable throwable) {
if (mQueryHttpDnsApiEvent != null && observableManager != null) {
mQueryHttpDnsApiEvent.setTag(config.isRetry(), config.getResolvingIpType(),
HttpRequestConfig.HTTP_SCHEMA.equals(config.getSchema()), config.isSignMode());
mQueryHttpDnsApiEvent.setHostName(config.getResolvingHost());
mQueryHttpDnsApiEvent.setServerIp(config.getIp());
mQueryHttpDnsApiEvent.setCostTime((int) (System.currentTimeMillis() - mQueryHttpDnsApiEvent.getTimestamp()));
mQueryHttpDnsApiEvent.setIpType(0x00);
if (throwable instanceof HttpException) {
mQueryHttpDnsApiEvent.setStatusCode(((HttpException) throwable).getCode());
String errorCode = throwable.getMessage();
mQueryHttpDnsApiEvent.setErrorCode(TextUtils.isEmpty(errorCode) ? "Unknown" : errorCode);
} else {
mQueryHttpDnsApiEvent.setStatusCode(-1);
mQueryHttpDnsApiEvent.setErrorCode(throwable.getClass().getSimpleName() + ":" + throwable.getMessage());
}
observableManager.addObservableEvent(mQueryHttpDnsApiEvent);
mQueryHttpDnsApiEvent = null;
}
}
}

View File

@@ -0,0 +1,53 @@
package com.newsdk.sdk.android.httpdns.request;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.observable.ObservableManager;
import com.newsdk.sdk.android.httpdns.observable.event.UpdateRegionServerIpsEvent;
public class UpdateRegionServerHttpRequestStatusWatcher implements HttpRequestWatcher.Watcher {
private final ObservableManager observableManager;
private int mScenes;
private UpdateRegionServerIpsEvent mUpdateRegionServerIpsEvent;
public UpdateRegionServerHttpRequestStatusWatcher(int scenes, ObservableManager observableManager) {
this.observableManager = observableManager;
mScenes = scenes;
}
@Override
public void onStart(HttpRequestConfig config) {
mUpdateRegionServerIpsEvent = new UpdateRegionServerIpsEvent();
mUpdateRegionServerIpsEvent.setTag(mScenes);
}
@Override
public void onSuccess(HttpRequestConfig config, Object data) {
if (mUpdateRegionServerIpsEvent != null && observableManager != null) {
mUpdateRegionServerIpsEvent.setCostTime((int) (System.currentTimeMillis() - mUpdateRegionServerIpsEvent.getTimestamp()));
mUpdateRegionServerIpsEvent.setStatusCode(200);
observableManager.addObservableEvent(mUpdateRegionServerIpsEvent);
mUpdateRegionServerIpsEvent = null;
}
}
@Override
public void onFail(HttpRequestConfig config, Throwable throwable) {
if (mUpdateRegionServerIpsEvent != null && observableManager != null) {
mUpdateRegionServerIpsEvent.setCostTime((int) (System.currentTimeMillis() - mUpdateRegionServerIpsEvent.getTimestamp()));
if (throwable instanceof HttpException) {
mUpdateRegionServerIpsEvent.setStatusCode(((HttpException) throwable).getCode());
String errorCode = throwable.getMessage();
mUpdateRegionServerIpsEvent.setErrorCode(TextUtils.isEmpty(errorCode) ? "Unknown" : errorCode);
} else {
mUpdateRegionServerIpsEvent.setStatusCode(-1);
mUpdateRegionServerIpsEvent.setErrorCode(throwable.getClass().getSimpleName() + ":" + throwable.getMessage());
}
observableManager.addObservableEvent(mUpdateRegionServerIpsEvent);
mUpdateRegionServerIpsEvent = null;
}
}
}

View File

@@ -0,0 +1,192 @@
package com.newsdk.sdk.android.httpdns.resolve;
import com.newsdk.sdk.android.httpdns.HTTPDNSResultWrapper;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.impl.HostResolveLocker;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsConfig;
import com.newsdk.sdk.android.httpdns.log.HttpDnsLog;
import com.newsdk.sdk.android.httpdns.net.NetworkStateManager;
import com.newsdk.sdk.android.httpdns.ranking.IPRankingCallback;
import com.newsdk.sdk.android.httpdns.ranking.IPRankingService;
import com.newsdk.sdk.android.httpdns.request.HttpException;
import com.newsdk.sdk.android.httpdns.request.RequestCallback;
import com.newsdk.sdk.android.httpdns.utils.CommonUtil;
import java.util.ArrayList;
import java.util.List;
/**
* 鎵归噺瑙f瀽鍩熷悕
*
* @author zonglin.nzl
* @date 2020/12/11
*/
public class BatchResolveHostService {
private final HttpDnsConfig mHttpDnsConfig;
private final ResolveHostResultRepo mResultRepo;
private final ResolveHostRequestHandler mRequestHandler;
private final IPRankingService mIpIPRankingService;
private final HostFilter mHostFilter;
private final HostResolveLocker mAsyncLocker;
public BatchResolveHostService(HttpDnsConfig config, ResolveHostResultRepo repo,
ResolveHostRequestHandler requestHandler,
IPRankingService ipIPRankingService, HostFilter filter,
HostResolveLocker locker) {
this.mHttpDnsConfig = config;
this.mResultRepo = repo;
this.mRequestHandler = requestHandler;
this.mIpIPRankingService = ipIPRankingService;
this.mHostFilter = filter;
this.mAsyncLocker = locker;
}
/**
* 鎵归噺瑙f瀽鍩熷悕
*
* @param hostList 寰呰В鏋愬煙鍚嶅垪琛?
* @param type 瑙f瀽绫诲瀷
*/
public void batchResolveHostAsync(final List<String> hostList, final RequestIpType type) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("batch resolve host " + hostList.toString() + " " + type);
}
ArrayList<String> hostsRequestV4 = new ArrayList<>();
ArrayList<String> hostsRequestV6 = new ArrayList<>();
ArrayList<String> hostsRequestBoth = new ArrayList<>();
for (String host : hostList) {
if (!CommonUtil.isAHost(host)
|| CommonUtil.isAnIP(host)
|| this.mHostFilter.isFiltered(host)) {
// 杩囨护鎺変笉闇€瑕佺殑鍩熷悕
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("resolve ignore host as not invalid " + host);
}
continue;
}
// 杩囨护鎺夋湁缂撳瓨鐨勫煙鍚?
String networkKey = NetworkStateManager.getInstance().getCurrentNetworkKey();
if (type == RequestIpType.v4) {
HTTPDNSResultWrapper result = mResultRepo.getIps(host, type, networkKey);
if (result == null || result.isExpired()) {
// 闇€瑕佽В鏋?
hostsRequestV4.add(host);
}
} else if (type == RequestIpType.v6) {
HTTPDNSResultWrapper result = mResultRepo.getIps(host, type, networkKey);
if (result == null || result.isExpired()) {
// 闇€瑕佽В鏋?
hostsRequestV6.add(host);
}
} else {
HTTPDNSResultWrapper resultV4 = mResultRepo.getIps(host, RequestIpType.v4, networkKey);
HTTPDNSResultWrapper resultV6 = mResultRepo.getIps(host, RequestIpType.v6, networkKey);
if ((resultV4 == null || resultV4.isExpired()) && (resultV6 == null || resultV6.isExpired())) {
// 閮介渶瑕佽В鏋?
hostsRequestBoth.add(host);
} else if (resultV4 == null || resultV4.isExpired()) {
hostsRequestV4.add(host);
} else if (resultV6 == null || resultV6.isExpired()) {
hostsRequestV6.add(host);
}
}
}
batchResolveHost(hostsRequestV4, RequestIpType.v4);
batchResolveHost(hostsRequestV6, RequestIpType.v6);
batchResolveHost(hostsRequestBoth, RequestIpType.both);
}
private void batchResolveHost(ArrayList<String> hostList, final RequestIpType type) {
if (hostList == null || hostList.isEmpty()) {
return;
}
ArrayList<String> allHosts = new ArrayList<>(hostList);
// 棰勮В鏋愭瘡娆℃渶澶?涓煙鍚?
final int maxCountPerRequest = 5;
int requestCount = (hostList.size() + maxCountPerRequest - 1) / maxCountPerRequest;
for (int i = 0; i < requestCount; i++) {
final ArrayList<String> targetHost = new ArrayList<>();
while (targetHost.size() < maxCountPerRequest && allHosts.size() > 0) {
String host = allHosts.remove(0);
if (mAsyncLocker.beginResolve(host, type, null)) {
targetHost.add(host);
} else {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("resolve ignore host as already interpret " + host);
}
}
}
if (targetHost.size() <= 0) {
continue;
}
if (HttpDnsLog.isPrint()) {
HttpDnsLog.i("resolve host " + targetHost.toString() + " " + type);
}
final String region = mHttpDnsConfig.getRegion();
mRequestHandler.requestResolveHost(targetHost, type,
new RequestCallback<ResolveHostResponse>() {
@Override
public void onSuccess(final ResolveHostResponse resolveHostResponse) {
if (HttpDnsLog.isPrint()) {
HttpDnsLog.d("resolve hosts for " + targetHost.toString() + " " + type
+ " return " + resolveHostResponse.toString());
}
String networkKey = NetworkStateManager.getInstance().getCurrentNetworkKey();
mResultRepo.save(region, resolveHostResponse, networkKey);
if (type == RequestIpType.v4 || type == RequestIpType.both) {
for (final ResolveHostResponse.HostItem item
: resolveHostResponse.getItems()) {
if (item.getIpType() == RequestIpType.v4) {
mIpIPRankingService.probeIpv4(item.getHost(), item.getIps(),
new IPRankingCallback() {
@Override
public void onResult(String host, String[] sortedIps) {
String networkKey = NetworkStateManager.getInstance().getCurrentNetworkKey();
mResultRepo.update(item.getHost(),
item.getIpType(),
networkKey, sortedIps);
}
});
}
}
}
for (String host : targetHost) {
mAsyncLocker.endResolve(host, type, null);
}
}
@Override
public void onFail(Throwable throwable) {
HttpDnsLog.w("resolve hosts for " + targetHost.toString() + " fail",
throwable);
if (throwable instanceof Exception) {
String query = "4";
if (type == RequestIpType.v6) {
query = "6";
}else if (type == RequestIpType.both) {
query = "4,6";
}
String errorMsg = (throwable instanceof HttpException) ? throwable.getMessage() : throwable.toString();
HttpDnsLog.w("RESOLVE FAIL, HOST:" + targetHost + ", QUERY:" + query
+ ", Msg:" + errorMsg);
}
if (throwable instanceof HttpException
&& ((HttpException)throwable).shouldCreateEmptyCache()) {
ResolveHostResponse emptyResponse = ResolveHostResponse.createEmpty(
targetHost, type, 60 * 60);
String networkKey = NetworkStateManager.getInstance().getCurrentNetworkKey();
mResultRepo.save(region, emptyResponse, networkKey);
}
for (String host : targetHost) {
mAsyncLocker.endResolve(host, type, null);
}
}
});
}
}
}

View File

@@ -0,0 +1,71 @@
package com.newsdk.sdk.android.httpdns.resolve;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsConfig;
import com.newsdk.sdk.android.httpdns.serverip.RegionServerScheduleService;
/**
* 鍩熷悕瑙f瀽绛栫暐鎺у埗
*/
public class CategoryController implements StatusControl {
private Status mStatus = Status.NORMAL;
private final NormalResolveCategory mNormal;
private final SniffResolveCategory mSniff;
public CategoryController(HttpDnsConfig config, RegionServerScheduleService scheduleService) {
mNormal = new NormalResolveCategory(config, scheduleService, this);
mSniff = new SniffResolveCategory(config, scheduleService, this);
}
public ResolveHostCategory getCategory() {
if (mStatus == Status.DISABLE) {
return mSniff;
}
return mNormal;
}
@Override
public void turnDown() {
switch (mStatus) {
case NORMAL:
mStatus = Status.PRE_DISABLE;
break;
case PRE_DISABLE:
mStatus = Status.DISABLE;
break;
default:
break;
}
}
@Override
public void turnUp() {
mStatus = Status.NORMAL;
}
/**
* 閲嶇疆绛栫暐
*/
public void reset() {
mStatus = Status.NORMAL;
mSniff.reset();
}
/**
* 璁剧疆鍡呮帰妯″紡璇锋眰闂撮殧
*
*/
public void setSniffTimeInterval(int timeInterval) {
mSniff.setInterval(timeInterval);
}
/**
* 绛栫暐鐘舵€侊紝鍙湁disable鐘舵€佷細浣跨敤鍡呮帰妯″紡
*/
enum Status {
NORMAL,
PRE_DISABLE,
DISABLE
}
}

View File

@@ -0,0 +1,23 @@
package com.newsdk.sdk.android.httpdns.resolve;
import com.newsdk.sdk.android.httpdns.DegradationFilter;
import com.newsdk.sdk.android.httpdns.NotUseHttpDnsFilter;
public class HostFilter {
DegradationFilter mFilter;
NotUseHttpDnsFilter mNotUseHttpDnsFilter;
public boolean isFiltered(String host) {
return (mNotUseHttpDnsFilter != null && mNotUseHttpDnsFilter.notUseHttpDns(host)) || (mFilter != null && mFilter.shouldDegradeHttpDNS(host));
}
@Deprecated
public void setFilter(DegradationFilter filter) {
this.mFilter = filter;
}
public void setFilter(NotUseHttpDnsFilter filter) {
mNotUseHttpDnsFilter = filter;
}
}

View File

@@ -0,0 +1,48 @@
package com.newsdk.sdk.android.httpdns.resolve;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsConfig;
import com.newsdk.sdk.android.httpdns.request.HttpRequest;
import com.newsdk.sdk.android.httpdns.request.HttpRequestConfig;
import com.newsdk.sdk.android.httpdns.request.HttpRequestTask;
import com.newsdk.sdk.android.httpdns.request.HttpRequestWatcher;
import com.newsdk.sdk.android.httpdns.request.RequestCallback;
import com.newsdk.sdk.android.httpdns.request.RetryHttpRequest;
import com.newsdk.sdk.android.httpdns.request.SingleResolveHttpRequestStatusWatcher;
import com.newsdk.sdk.android.httpdns.serverip.RegionServerScheduleService;
/**
* 鍩熷悕瑙f瀽鐨勪竴鑸瓥鐣?
*/
public class NormalResolveCategory implements ResolveHostCategory {
private final HttpDnsConfig mHttpDnsConfig;
private final StatusControl mStatusControl;
private final RegionServerScheduleService mScheduleService;
public NormalResolveCategory(HttpDnsConfig config, RegionServerScheduleService scheduleService, StatusControl statusControl) {
this.mScheduleService = scheduleService;
this.mStatusControl = statusControl;
mHttpDnsConfig = config;
}
@Override
public void resolve(HttpDnsConfig config, HttpRequestConfig requestConfig,
RequestCallback<ResolveHostResponse> callback) {
HttpRequest<ResolveHostResponse> request = new HttpRequest<>(requestConfig,
new ResolveHostResponseParser(requestConfig.getAESEncryptService()));
request = new HttpRequestWatcher<>(request, new SingleResolveHttpRequestStatusWatcher(
mHttpDnsConfig.getObservableManager()));
// 鍒囨崲鏈嶅姟IP锛屾洿鏂版湇鍔P
request = new HttpRequestWatcher<>(request, new ShiftServerWatcher(config,
mScheduleService,
mStatusControl));
// 閲嶈瘯涓€娆?
request = new RetryHttpRequest<>(request, 1);
try {
config.getResolveWorker().execute(new HttpRequestTask<>(request, callback));
} catch (Throwable e) {
callback.onFail(e);
}
}
}

View File

@@ -0,0 +1,243 @@
package com.newsdk.sdk.android.httpdns.resolve;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import com.newsdk.sdk.android.httpdns.HTTPDNSResultWrapper;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.cache.HostRecord;
public class ResolveHostCache {
/**
* v4鐨勮В鏋愯褰?
*/
private final ConcurrentHashMap<String, HostRecord> mV4Records = new ConcurrentHashMap<>();
/**
* v6鐨勮В鏋愯褰?
*/
private final ConcurrentHashMap<String, HostRecord> mV6Records = new ConcurrentHashMap<>();
/**
* v4鐨勮繑鍥炵粨鏋?
*/
private final ConcurrentHashMap<String, HTTPDNSResultWrapper> mV4HttpDnsResults
= new ConcurrentHashMap<>();
/**
* v6鐨勮繑鍥炵粨鏋?
*/
private final ConcurrentHashMap<String, HTTPDNSResultWrapper> mV6HttpDnsResults
= new ConcurrentHashMap<>();
/**
* 鍚屾椂瑙瀽4 6鐨勭粨鏋?
*/
private final ConcurrentHashMap<String, HTTPDNSResultWrapper> mBothHttpDnsResults =
new ConcurrentHashMap<>();
public HTTPDNSResultWrapper getResult(String host, RequestIpType type) {
HTTPDNSResultWrapper result = obtainHttpResult(host, type);
result = buildHttpResult(host, type, result);
cacheResult(host, type, result);
return result;
}
private HTTPDNSResultWrapper obtainHttpResult(String host, RequestIpType type) {
HTTPDNSResultWrapper result = null;
switch (type) {
case v6:
result = mV6HttpDnsResults.get(host);
break;
case v4:
result = mV4HttpDnsResults.get(host);
break;
case both:
result = mBothHttpDnsResults.get(host);
break;
}
return result;
}
private void cacheResult(String host, RequestIpType type, HTTPDNSResultWrapper result) {
if (result != null) {
switch (type) {
case v6:
mV6HttpDnsResults.put(host, result);
break;
case v4:
mV4HttpDnsResults.put(host, result);
break;
case both:
mBothHttpDnsResults.put(host, result);
break;
}
}
}
private HTTPDNSResultWrapper buildHttpResult(String host, RequestIpType type, HTTPDNSResultWrapper result) {
HostRecord record;
switch (type) {
case v6:
record = mV6Records.get(host);
if (record != null) {
if (result == null) {
result = new HTTPDNSResultWrapper(host);
}
result.update(record);
}
break;
case v4:
record = mV4Records.get(host);
if (record != null) {
if (result == null) {
result = new HTTPDNSResultWrapper(host);
}
result.update(record);
}
break;
default:
record = mV4Records.get(host);
HostRecord recordv6 = mV6Records.get(host);
if (record == null || recordv6 == null) {
return result;
}
if (result == null) {
result = new HTTPDNSResultWrapper(host);
}
ArrayList<HostRecord> records = new ArrayList<>();
records.add(record);
records.add(recordv6);
result.update(records);
break;
}
return result;
}
public HostRecord update(String region, String host, RequestIpType type, String extra,
String cacheKey, String[] ips, int ttl, String serverIp, String noIpCode) {
HostRecord record = null;
switch (type) {
case v4:
record = mV4Records.get(host);
if (record == null) {
record = HostRecord.create(region, host, type, extra, cacheKey, ips, ttl, serverIp, noIpCode);
mV4Records.put(host, record);
} else {
record.setRegion(region);
record.setQueryTime(System.currentTimeMillis());
record.setIps(ips);
record.setTtl(ttl);
record.setExtra(extra);
record.setFromDB(false);
record.setServerIp(serverIp);
record.setNoIpCode(noIpCode);
}
break;
case v6:
record = mV6Records.get(host);
if (record == null) {
record = HostRecord.create(region, host, type, extra, cacheKey, ips, ttl, serverIp, noIpCode);
mV6Records.put(host, record);
} else {
record.setRegion(region);
record.setQueryTime(System.currentTimeMillis());
record.setIps(ips);
record.setTtl(ttl);
record.setExtra(extra);
record.setFromDB(false);
record.setServerIp(serverIp);
record.setNoIpCode(noIpCode);
}
break;
default:
throw new IllegalStateException("type should be v4 or b6");
}
return record;
}
public void put(HostRecord record) {
if (record.getType() == RequestIpType.v4.ordinal()) {
mV4Records.put(record.getHost(), record);
} else if (record.getType() == RequestIpType.v6.ordinal()) {
mV6Records.put(record.getHost(), record);
}
}
public HostRecord updateIps(String host, RequestIpType type, String[] ips) {
HostRecord record = null;
switch (type) {
case v4:
record = mV4Records.get(host);
if (record == null) {
return null;
}
record.setIps(ips);
break;
case v6:
record = mV6Records.get(host);
if (record == null) {
return null;
}
record.setIps(ips);
break;
default:
throw new IllegalStateException("type should be v4 or b6");
}
return record;
}
public List<HostRecord> clear() {
ArrayList<HostRecord> list = new ArrayList<>();
list.addAll(mV4Records.values());
list.addAll(mV6Records.values());
mV4Records.clear();
mV6Records.clear();
mV4HttpDnsResults.clear();
mV6HttpDnsResults.clear();
mBothHttpDnsResults.clear();
return list;
}
public List<HostRecord> clear(List<String> hosts) {
ArrayList<HostRecord> records = new ArrayList<>();
for (String host : hosts) {
HostRecord tmp = mV4Records.remove(host);
if (tmp != null) {
records.add(tmp);
}
}
for (String host : hosts) {
HostRecord tmp = mV6Records.remove(host);
if (tmp != null) {
records.add(tmp);
}
}
for (String host : hosts) {
mV4HttpDnsResults.remove(host);
mV6HttpDnsResults.remove(host);
mBothHttpDnsResults.remove(host);
}
return records;
}
public HashMap<String, RequestIpType> getAllHostNotEmptyResult() {
HashMap<String, RequestIpType> all = new HashMap<>();
for (HostRecord record : mV4Records.values()) {
if (record.getIps() != null && record.getIps().length > 0) {
all.put(record.getHost(), RequestIpType.v4);
}
}
for (HostRecord record : mV6Records.values()) {
if (record.getIps() != null && record.getIps().length > 0) {
RequestIpType type = all.get(record.getHost());
if (type == null) {
all.put(record.getHost(), RequestIpType.v6);
} else {
all.put(record.getHost(), RequestIpType.both);
}
}
}
return all;
}
}

View File

@@ -0,0 +1,115 @@
package com.newsdk.sdk.android.httpdns.resolve;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.cache.HostRecord;
import com.newsdk.sdk.android.httpdns.net.NetworkStateManager;
/**
* 缂撳瓨缁勭鐞嗗櫒锛屾敮鎸佺綉缁滈殧绂荤紦瀛?
*/
public class ResolveHostCacheGroup {
/**
* 鎵€鏈夌紦瀛樼粺涓€绠悊锛屽寘鎷綉缁滈殧绂荤紦瀛樺拰SDNS缂撳瓨
*/
private final HashMap<String, ResolveHostCache> mCaches = new HashMap<>();
private final Object lock = new Object();
private static final String NETWORK_KEY_PREFIX = "emasInner_";
public ResolveHostCache getCache(String cacheKey) {
if (cacheKey == null || cacheKey.isEmpty()) {
// 鏅€氳В鏋愪娇鐢ㄥ綋鍓嶇綉缁滄爣璇?
cacheKey = NetworkStateManager.getInstance().getCurrentNetworkKey();
}
// 缁熶竴鐨勭紦瀛樿幏鍙栭€昏緫
ResolveHostCache cache = mCaches.get(cacheKey);
if (cache == null) {
synchronized (lock) {
cache = mCaches.get(cacheKey);
if (cache == null) {
cache = new ResolveHostCache();
mCaches.put(cacheKey, cache);
}
}
}
return cache;
}
/**
* 鑾峰彇鎵€鏈夌綉缁滅紦瀛樹腑鐨勫煙鍚嶏紙鎺掗櫎SDNS缂撳瓨锛?
*/
public HashMap<String, RequestIpType> getAllHostFromNetworkCaches() {
HashMap<String, RequestIpType> allHosts = new HashMap<>();
synchronized (lock) {
for (Map.Entry<String, ResolveHostCache> entry : mCaches.entrySet()) {
String cacheKey = entry.getKey();
if (!cacheKey.startsWith(NETWORK_KEY_PREFIX)) {
continue;
}
ResolveHostCache cache = entry.getValue();
HashMap<String, RequestIpType> hosts = cache.getAllHostNotEmptyResult();
for (Map.Entry<String, RequestIpType> hostEntry : hosts.entrySet()) {
String host = hostEntry.getKey();
RequestIpType type = hostEntry.getValue();
if (!allHosts.containsKey(host)) {
allHosts.put(host, type);
continue;
}
RequestIpType mergedType = mergeIpTypes(allHosts.get(host), type);
allHosts.put(host, mergedType);
}
}
}
return allHosts;
}
private RequestIpType mergeIpTypes(RequestIpType type1, RequestIpType type2) {
if (type1 == RequestIpType.both || type2 == RequestIpType.both) {
return RequestIpType.both;
}
if ((type1 == RequestIpType.v4 && type2 == RequestIpType.v6) ||
(type1 == RequestIpType.v6 && type2 == RequestIpType.v4)) {
return RequestIpType.both;
}
return type1;
}
public List<HostRecord> clearAll() {
ArrayList<HostRecord> records = new ArrayList<>();
if (mCaches.size() > 0) {
synchronized (lock) {
for (ResolveHostCache cache : mCaches.values()) {
records.addAll(cache.clear());
}
}
}
return records;
}
public List<HostRecord> clearAll(List<String> hosts) {
ArrayList<HostRecord> records = new ArrayList<>();
if (mCaches.size() > 0) {
synchronized (lock) {
for (ResolveHostCache cache : mCaches.values()) {
records.addAll(cache.clear(hosts));
}
}
}
return records;
}
}

View File

@@ -0,0 +1,20 @@
package com.newsdk.sdk.android.httpdns.resolve;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsConfig;
import com.newsdk.sdk.android.httpdns.request.HttpRequestConfig;
import com.newsdk.sdk.android.httpdns.request.RequestCallback;
/**
* 鍩熷悕瑙f瀽绛栫暐鎺ュ彛
*/
public interface ResolveHostCategory {
/**
* 瑙f瀽鍩熷悕
* @param config {@link HttpDnsConfig}
* @param requestConfig {@link HttpRequestConfig}
* @param callback {@link RequestCallback<ResolveHostResponse>}
*/
void resolve(HttpDnsConfig config, HttpRequestConfig requestConfig,
RequestCallback<ResolveHostResponse> callback);
}

View File

@@ -0,0 +1,146 @@
package com.newsdk.sdk.android.httpdns.resolve;
import android.text.TextUtils;
import com.newsdk.sdk.android.httpdns.BuildConfig;
import com.newsdk.sdk.android.httpdns.NetType;
import com.newsdk.sdk.android.httpdns.RequestIpType;
import com.newsdk.sdk.android.httpdns.impl.AESEncryptService;
import com.newsdk.sdk.android.httpdns.impl.HttpDnsConfig;
import com.newsdk.sdk.android.httpdns.impl.SignService;
import com.newsdk.sdk.android.httpdns.request.HttpRequestConfig;
import com.newsdk.sdk.android.httpdns.track.SessionTrackMgr;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class ResolveHostHelper {
public static HttpRequestConfig getConfig(HttpDnsConfig config, String host,
RequestIpType type,
Map<String, String> extras, String cacheKey,
Map<String, String> globalParams,
SignService signService,
AESEncryptService encryptService) {
HashMap<String, String> mergedExtras = null;
if ((globalParams != null && !globalParams.isEmpty()) || (extras != null && !extras.isEmpty())) {
mergedExtras = new HashMap<>();
if (globalParams != null) {
mergedExtras.putAll(globalParams);
}
if (extras != null) {
mergedExtras.putAll(extras);
}
}
String path = getPath(config, host, type, mergedExtras, signService, encryptService);
HttpRequestConfig requestConfig = getHttpRequestConfig(config, path, signService.isSignMode());
requestConfig.setUA(config.getUA());
requestConfig.setAESEncryptService(encryptService);
return requestConfig;
}
public static String getPath(HttpDnsConfig config, String host, RequestIpType type,
Map<String, String> extras,
SignService signService,
AESEncryptService encryptService) {
String qtype = getQType(type);
StringBuilder query = new StringBuilder();
appendQuery(query, "appId", config.getAccountId());
appendQuery(query, "dn", host);
appendQuery(query, "qtype", qtype);
appendQuery(query, "sdk_version", BuildConfig.VERSION_NAME);
appendQuery(query, "os", "android");
String sid = SessionTrackMgr.getInstance().getSessionId();
if (!TextUtils.isEmpty(sid)) {
appendQuery(query, "sid", sid);
}
if (extras != null) {
String cip = extras.get("cip");
if (!TextUtils.isEmpty(cip)) {
appendQuery(query, "cip", cip);
}
}
if (signService.isSignMode()) {
String exp = signService.getExpireTime();
String nonce = randomNonce();
String sign = signService.signResolve(config.getAccountId(), host, qtype, exp, nonce);
appendQuery(query, "exp", exp);
appendQuery(query, "nonce", nonce);
appendQuery(query, "sign", sign);
}
return "/resolve?" + query;
}
private static void appendQuery(StringBuilder query, String key, String value) {
if (TextUtils.isEmpty(key) || value == null) {
return;
}
if (query.length() > 0) {
query.append("&");
}
query.append(key).append("=").append(URLEncoder.encode(value, StandardCharsets.UTF_8));
}
private static String getQType(RequestIpType type) {
if (type == RequestIpType.v6) {
return "AAAA";
}
return "A";
}
private static String randomNonce() {
return UUID.randomUUID().toString().replace("-", "");
}
public static HttpRequestConfig getConfig(HttpDnsConfig config, ArrayList<String> hostList,
RequestIpType type, SignService signService,
AESEncryptService encryptService) {
String host = "";
if (hostList != null && hostList.size() > 0) {
host = hostList.get(0);
}
String path = getPath(config, host, type, null, signService, encryptService);
HttpRequestConfig requestConfig = getHttpRequestConfig(config, path, signService.isSignMode());
requestConfig.setUA(config.getUA());
requestConfig.setAESEncryptService(encryptService);
return requestConfig;
}
private static HttpRequestConfig getHttpRequestConfig(HttpDnsConfig config, String path, Boolean isSignMode) {
if (config.getNetworkDetector() != null && config.getNetworkDetector().getNetType(
config.getContext()) == NetType.v6) {
return new HttpRequestConfig(config.getSchema(),
config.getCurrentServer().getServerIpForV6(),
config.getCurrentServer().getPortForV6(), path, config.getTimeout(),
RequestIpType.v6, isSignMode);
} else {
return new HttpRequestConfig(config.getSchema(),
config.getCurrentServer().getServerIp(), config.getCurrentServer().getPort(), path,
config.getTimeout(), RequestIpType.v4, isSignMode);
}
}
public static String getSid() {
String sessionId = SessionTrackMgr.getInstance().getSessionId();
if (sessionId == null) {
return "";
} else {
return "&sid=" + sessionId;
}
}
/**
* 鍏煎鍙娴嬫ā鍧楅€忎紶 tags銆? */
public static String getTags(HttpDnsConfig config) {
if (config == null || TextUtils.isEmpty(config.getBizTags())) {
return "";
}
return "&tags=" + config.getBizTags();
}
}

Some files were not shown because too many files have changed in this diff Show More