From d800a8b729c4aed6e794ab6d8e0cc5cc5988247f Mon Sep 17 00:00:00 2001 From: notsure2 Date: Mon, 11 Dec 2023 23:48:04 +0200 Subject: [PATCH] Add support for "optimize tcp buffers" option per profile. - It tunes down the local sslocal listener socket buffers which is the right thing to do in 99.999% of cases of mobile app. - It additionally also tunes down the remote socket buffers of sslocal when a plugin is used. This is needed to ensure there's no bufferbloat between sslocal and the plugin itself. - Ideally the plugin on its side should also choke its local listening socket buffers and leave only its remote side socket buffers unrestricted. --- .../29.json | 20 ++++++++++++------- .../github/shadowsocks/bg/ProxyInstance.kt | 16 +++++++++++++-- .../github/shadowsocks/database/Profile.kt | 3 +++ .../shadowsocks/preference/DataStore.kt | 3 +++ .../com/github/shadowsocks/utils/Constants.kt | 1 + core/src/main/res/values-ar/strings.xml | 2 ++ core/src/main/res/values-de/strings.xml | 2 ++ core/src/main/res/values-es/strings.xml | 2 ++ core/src/main/res/values-fa/strings.xml | 2 ++ core/src/main/res/values-fr/strings.xml | 2 ++ core/src/main/res/values-ja/strings.xml | 2 ++ core/src/main/res/values-ko/strings.xml | 2 ++ core/src/main/res/values-ru/strings.xml | 2 ++ core/src/main/res/values-tr/strings.xml | 2 ++ core/src/main/res/values-uk/strings.xml | 2 ++ core/src/main/res/values-zh-rCN/strings.xml | 2 ++ core/src/main/res/values-zh-rTW/strings.xml | 2 ++ core/src/main/res/values/strings.xml | 2 ++ .../shadowsocks/ProfileConfigFragment.kt | 3 +++ mobile/src/main/res/xml/pref_profile.xml | 7 +++++-- 20 files changed, 68 insertions(+), 11 deletions(-) diff --git a/core/schemas/com.github.shadowsocks.database.PrivateDatabase/29.json b/core/schemas/com.github.shadowsocks.database.PrivateDatabase/29.json index 5a695600e7..8251c64540 100644 --- a/core/schemas/com.github.shadowsocks.database.PrivateDatabase/29.json +++ b/core/schemas/com.github.shadowsocks.database.PrivateDatabase/29.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 29, - "identityHash": "5b5c55a1277c63e14416316f9198ed43", + "identityHash": "edf35c5851b4cb55bb5dbbf278199450", "entities": [ { "tableName": "Profile", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `host` TEXT NOT NULL, `remotePort` INTEGER NOT NULL, `password` TEXT NOT NULL, `method` TEXT NOT NULL, `route` TEXT NOT NULL, `remoteDns` TEXT NOT NULL, `proxyApps` INTEGER NOT NULL, `bypass` INTEGER NOT NULL, `udpdns` INTEGER NOT NULL, `ipv6` INTEGER NOT NULL, `metered` INTEGER NOT NULL, `individual` TEXT NOT NULL, `plugin` TEXT, `udpFallback` INTEGER, `subscription` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL)", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `host` TEXT NOT NULL, `remotePort` INTEGER NOT NULL, `password` TEXT NOT NULL, `method` TEXT NOT NULL, `route` TEXT NOT NULL, `remoteDns` TEXT NOT NULL, `proxyApps` INTEGER NOT NULL, `bypass` INTEGER NOT NULL, `udpdns` INTEGER NOT NULL, `ipv6` INTEGER NOT NULL, `metered` INTEGER NOT NULL, `individual` TEXT NOT NULL, `plugin` TEXT, `udpFallback` INTEGER, `optimizeBuffers` INTEGER NOT NULL, `subscription` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL)", "fields": [ { "fieldPath": "id", @@ -104,6 +104,12 @@ "affinity": "INTEGER", "notNull": false }, + { + "fieldPath": "optimizeBuffers", + "columnName": "optimizeBuffers", + "affinity": "INTEGER", + "notNull": true + }, { "fieldPath": "subscription", "columnName": "subscription", @@ -130,10 +136,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [], "foreignKeys": [] @@ -162,10 +168,10 @@ } ], "primaryKey": { + "autoGenerate": false, "columnNames": [ "key" - ], - "autoGenerate": false + ] }, "indices": [], "foreignKeys": [] @@ -174,7 +180,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5b5c55a1277c63e14416316f9198ed43')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'edf35c5851b4cb55bb5dbbf278199450')" ] } } \ No newline at end of file diff --git a/core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt b/core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt index 05f834707b..ceff44109a 100644 --- a/core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt +++ b/core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt @@ -117,10 +117,22 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro val cmd = arrayListOf( File((service as Context).applicationInfo.nativeLibraryDir, Executable.SS_LOCAL).absolutePath, "--stat-path", stat.absolutePath, - "-c", configFile.absolutePath, + "-c", configFile.absolutePath ) - if (service.isVpnService) cmd += "--vpn" + if (profile.optimizeBuffers) { + cmd += "--inbound-send-buffer-size 16384" + cmd += "--inbound-recv-buffer-size 16384" + + if (profile.plugin?.isNotBlank() == true) { + cmd += "--outbound-send-buffer-size 16384" + cmd += "--outbound-recv-buffer-size 16384" + } + } + + if (service.isVpnService) { + cmd += "--vpn" + } if (route != Acl.ALL) { cmd += "--acl" diff --git a/core/src/main/java/com/github/shadowsocks/database/Profile.kt b/core/src/main/java/com/github/shadowsocks/database/Profile.kt index bae60e1066..d1f95a1836 100644 --- a/core/src/main/java/com/github/shadowsocks/database/Profile.kt +++ b/core/src/main/java/com/github/shadowsocks/database/Profile.kt @@ -70,6 +70,7 @@ data class Profile( var individual: String = "", var plugin: String? = null, var udpFallback: Long? = null, + var optimizeBuffers: Boolean = true, // managed fields var subscription: SubscriptionStatus = SubscriptionStatus.UserConfigured, @@ -355,6 +356,7 @@ data class Profile( DataStore.individual = individual DataStore.plugin = plugin ?: "" DataStore.udpFallback = udpFallback + DataStore.optimizeBuffers = optimizeBuffers DataStore.privateStore.remove(Key.dirty) } @@ -378,5 +380,6 @@ data class Profile( individual = DataStore.individual plugin = DataStore.plugin udpFallback = DataStore.udpFallback + optimizeBuffers = DataStore.optimizeBuffers } } diff --git a/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt b/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt index a523681f74..c6fd940c5c 100644 --- a/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt +++ b/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt @@ -104,6 +104,9 @@ object DataStore : OnPreferenceDataStoreChangeListener { var udpFallback: Long? get() = privateStore.getLong(Key.udpFallback) set(value) = privateStore.putLong(Key.udpFallback, value) + var optimizeBuffers: Boolean + get() = privateStore.getBoolean(Key.optimizeBuffers) ?: true + set(value) = privateStore.putBoolean(Key.optimizeBuffers, value) var dirty: Boolean get() = privateStore.getBoolean(Key.dirty) ?: false set(value) = privateStore.putBoolean(Key.dirty, value) diff --git a/core/src/main/java/com/github/shadowsocks/utils/Constants.kt b/core/src/main/java/com/github/shadowsocks/utils/Constants.kt index 52b6de20ec..b48f54bbd8 100644 --- a/core/src/main/java/com/github/shadowsocks/utils/Constants.kt +++ b/core/src/main/java/com/github/shadowsocks/utils/Constants.kt @@ -61,6 +61,7 @@ object Key { const val plugin = "plugin" const val pluginConfigure = "plugin.configure" const val udpFallback = "udpFallback" + const val optimizeBuffers = "optimizeBuffers"; const val dirty = "profileDirty" diff --git a/core/src/main/res/values-ar/strings.xml b/core/src/main/res/values-ar/strings.xml index 32c3815094..414dce3b2b 100644 --- a/core/src/main/res/values-ar/strings.xml +++ b/core/src/main/res/values-ar/strings.xml @@ -34,4 +34,6 @@ "المنفذ" "كلمة المرور" "طريقة التشفير" + حسِن مخازن الذاكرة ل TCP + يعالج مشكلة نفاذ الوقت اثناء الرفع نتيجة تضخم مخازن الذاكرة \ No newline at end of file diff --git a/core/src/main/res/values-de/strings.xml b/core/src/main/res/values-de/strings.xml index 8794f90a91..eeedbdeede 100644 --- a/core/src/main/res/values-de/strings.xml +++ b/core/src/main/res/values-de/strings.xml @@ -39,6 +39,7 @@ Empfangen: \t%4$s\t↓\t%2$s" "Verschlüsselungsmethode" + TCP-Puffer optimieren "IPv6-Route" "Leite IPv6-Traffic zu Remote um" "GFW-Liste" @@ -49,6 +50,7 @@ Empfangen: \t%4$s\t↓\t%2$s" "Aktiviere um ausgewählte Apps zu umgehen" "Automatisch verbinden" "Starte Shadowsocks bei Systemstart/nach App-Update automatisch, falls es zuvor aktiv war" + Upload-Zeitüberschreitung (Bufferbloat) beheben "Umschalten benötigt eventuell ROOT-Zugriff" "Nicht unterstützte Kernel-Version: %s < 3.7.1" "Sende DNS über UDP" diff --git a/core/src/main/res/values-es/strings.xml b/core/src/main/res/values-es/strings.xml index 63d8ee9a04..54911d6cd5 100644 --- a/core/src/main/res/values-es/strings.xml +++ b/core/src/main/res/values-es/strings.xml @@ -40,6 +40,7 @@ Recibido: \t%4$s\t↓\t%2$s" "Método de Cifrado" + Optimizar buffers TCP "Ruta IPv6" "Redireccionar tráfico IPv6 a ruta" "Ruta" @@ -54,6 +55,7 @@ Recibido: \t%4$s\t↓\t%2$s" "Activar Shadowsocks al iniciar" + Corregir el error de tiempo de espera de carga debido a bufferbloat "Versión del Núcleo sin soporte: %s < 3.7.1" "Enviar DNS sobre UDP" diff --git a/core/src/main/res/values-fa/strings.xml b/core/src/main/res/values-fa/strings.xml index c38d4c7b58..eb027af4d4 100644 --- a/core/src/main/res/values-fa/strings.xml +++ b/core/src/main/res/values-fa/strings.xml @@ -41,6 +41,7 @@ "روش رمزگذاری" + بهینه‌سازی بافرهای TCP "مسیر IPv6" "ترافیک IPv6 را به سرور هدایت کن" "مسیر" @@ -52,6 +53,7 @@ "این گزینه را فعال کنید تا اپلیکیشن‌های انتخاب شده از VPN استفاده نکنند" "وصل‌شدن اتوماتیک" "فعال‌شدن شدوساکس لحظه روشن‌شدن گوشی بروزرسانی شود اگر از قبل درحال اجرا بوده است" + رفع مشکل تایم اوت آپلود به دلیل بافرهای بزرگ "تغییر وضعیت ممکن است به مجوز ROOT نیاز داشته باشد" "نسخه هسته پشتیبانی نشده: %s <3.7.1" "ارسال DNS از طریق UDP" diff --git a/core/src/main/res/values-fr/strings.xml b/core/src/main/res/values-fr/strings.xml index 18c1724d31..f7e91a86f3 100644 --- a/core/src/main/res/values-fr/strings.xml +++ b/core/src/main/res/values-fr/strings.xml @@ -40,6 +40,7 @@ Reçu : \t\t\t%4$s\t↓\t%2$s" "Méthode d'Encryption" + Optimiser les tampons TCP "Route IPv6" "Rediriger le trafic IPv6 vers le serveur distant" "Route" @@ -57,6 +58,7 @@ Reçu : \t\t\t%4$s\t↓\t%2$s" "Activer Shadowsocks au démarrage" + Résoudre le problème de délai d\'envoi lié au bufferbloat "Activer nécessite la permission ROOT" "Version du noyau non supportée : %s <3.7.1" diff --git a/core/src/main/res/values-ja/strings.xml b/core/src/main/res/values-ja/strings.xml index 5bd153c1bf..39bd5ab3fc 100644 --- a/core/src/main/res/values-ja/strings.xml +++ b/core/src/main/res/values-ja/strings.xml @@ -42,6 +42,7 @@ "暗号化方式" + TCP バッファを最適化 "IPv6 プロキシ" "リモートサーバーに IPv6 パケットを転送" "プロキシ方式" @@ -59,6 +60,7 @@ "システム起動時にバックグラウンドで本サービスを開始" + バッファブロートによるアップロード遅延を解消する "使用するには ROOT 権限が必要" "ご利用のカーネルバージョンはサポートしておりません:%s < 3.7.1" diff --git a/core/src/main/res/values-ko/strings.xml b/core/src/main/res/values-ko/strings.xml index 5081943e40..22222f9890 100644 --- a/core/src/main/res/values-ko/strings.xml +++ b/core/src/main/res/values-ko/strings.xml @@ -39,6 +39,7 @@ "암호화 방법" + TCP 버퍼 최적화 "IPv6 라우팅" "IPv6 트래픽도 원격으로 리다이렉트 합니다" "라우팅 대상" @@ -58,6 +59,7 @@ "장치가 켜질 때 Shadowsocks를 자동으로 활성화합니다" + 업로드 버퍼 크기 초과로 인한 시간 초과 해결 "루트 권한이 필요합니다" "지원하지 않는 버전의 커널입니다: %s < 3.7.1" diff --git a/core/src/main/res/values-ru/strings.xml b/core/src/main/res/values-ru/strings.xml index e601fa3013..48ba925d7e 100644 --- a/core/src/main/res/values-ru/strings.xml +++ b/core/src/main/res/values-ru/strings.xml @@ -40,6 +40,7 @@ "Метод шифрования" + Оптимизировать буферы TCP "Маршрутизация IPv6" "Перенаправлять трафик IPv6 на удалённый сервер" "Маршрут" @@ -52,6 +53,7 @@ "Включите эту функцию для работы выбранных приложений в обход прокси" "Автоподключение" "Запускать Shadowsocks при включении/после обновления приложения, если оно было запущено до этого" + Устранить таймаут загрузки из-за переполнения буфера "Переключение может запрашивать Root (права суперпользователя)" "Неподдерживаемая версия ядра: %s < 3.7.1" "Посылать DNS-запросы через UDP" diff --git a/core/src/main/res/values-tr/strings.xml b/core/src/main/res/values-tr/strings.xml index 63a0c99c10..412778fb8a 100644 --- a/core/src/main/res/values-tr/strings.xml +++ b/core/src/main/res/values-tr/strings.xml @@ -37,6 +37,7 @@ "Uzaktan Port" "Şifre" "Şifreleme Methodu" + TCP Arabelleklerini Optimize Edin "IPv6 trafiğini remote'a yönlendir" "Rota" "GFW Listesi" @@ -53,6 +54,7 @@ "Shadowsocks'ı cihazı başlatırken aç" + Aşırı boyutlu arabelleklerden kaynaklanan yükleme zaman aşımını düzeltin. "Açıp kapamak için ROOT yetkisi gerekiyor" "Desteklenmeyen kernel sürümü: %s < 3.7.1" diff --git a/core/src/main/res/values-uk/strings.xml b/core/src/main/res/values-uk/strings.xml index 921e508512..910e02ab09 100644 --- a/core/src/main/res/values-uk/strings.xml +++ b/core/src/main/res/values-uk/strings.xml @@ -80,6 +80,7 @@ "Використовувати поточний профіль" + Виправити таймаут завантаження через завеликі буфери "Надіслано:" "Отримано:" @@ -92,6 +93,7 @@ "Власні правила" "Додати правило…" "Редагувати правило" + Оптимізувати буфери TCP "Всі" "Оминати локальні мережі" "Оминати Китай" diff --git a/core/src/main/res/values-zh-rCN/strings.xml b/core/src/main/res/values-zh-rCN/strings.xml index a42055ecdb..1174a6744b 100644 --- a/core/src/main/res/values-zh-rCN/strings.xml +++ b/core/src/main/res/values-zh-rCN/strings.xml @@ -40,6 +40,7 @@ "加密方式" + 优化 TCP 缓冲区 "IPv6 路由" "转发 IPv6 流量到远程服务器" "路由" @@ -51,6 +52,7 @@ "绕过选择的应用" "自动连接" "系统启动或应用更新后自动恢复运行" + 解决因缓冲区过大导致的上传超时问题 "切换可能需要 ROOT 权限" "不支持的内核版本: %s < 3.7.1" "使用 UDP DNS" diff --git a/core/src/main/res/values-zh-rTW/strings.xml b/core/src/main/res/values-zh-rTW/strings.xml index 76b5fa6a54..a728c4c707 100644 --- a/core/src/main/res/values-zh-rTW/strings.xml +++ b/core/src/main/res/values-zh-rTW/strings.xml @@ -41,6 +41,7 @@ "加密方法" + 最佳化 TCP 緩衝區 "IPv6 路由" "向遠端重新導向 IPv6 流量" "路由" @@ -58,6 +59,7 @@ "在裝置啟動時啟用 Shadowsocks" + 修正因緩衝區過大導致上傳逾時的問題 "切換需要 ROOT 權限" "不支援的核心版本:%s < 3.7.1" diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 04ed7d9d67..8fb5180a50 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -32,6 +32,8 @@ Remote Port Password Encrypt Method + Optimize TCP Buffers + Fix upload timeout (bufferbloat) IPv6 Route diff --git a/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt index 8ca2d21c4d..f238097ec1 100644 --- a/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/ProfileConfigFragment.kt @@ -79,6 +79,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), private lateinit var pluginConfiguration: PluginConfiguration private lateinit var receiver: BroadcastReceiver private lateinit var udpFallback: Preference + private lateinit var optimizeBuffers: SwitchPreference private fun makeDirt() { DataStore.dirty = true @@ -115,6 +116,8 @@ class ProfileConfigFragment : PreferenceFragmentCompat(), pluginConfiguration = PluginConfiguration(DataStore.plugin) initPlugins() udpFallback = findPreference(Key.udpFallback)!! + optimizeBuffers = findPreference(Key.optimizeBuffers)!! + optimizeBuffers.isChecked = DataStore.optimizeBuffers DataStore.privateStore.registerChangeListener(this) val profile = ProfileManager.getProfile(profileId) ?: Profile() diff --git a/mobile/src/main/res/xml/pref_profile.xml b/mobile/src/main/res/xml/pref_profile.xml index 5db0dd19a3..64f2891d83 100644 --- a/mobile/src/main/res/xml/pref_profile.xml +++ b/mobile/src/main/res/xml/pref_profile.xml @@ -65,8 +65,11 @@ app:key="remoteDns" app:icon="@drawable/ic_action_dns" app:title="@string/remote_dns" - app:useSimpleSummaryProvider="true"/> - + app:useSimpleSummaryProvider="true" /> +