From e2eecadc7412daeb80830addd307156c49bf13d9 Mon Sep 17 00:00:00 2001 From: "github-action[bot]" Date: Sat, 6 Apr 2024 20:26:16 +0200 Subject: [PATCH] Update On Sat Apr 6 20:26:16 CEST 2024 --- .github/update.log | 1 + .../src/main/golang/native/config/fetch.go | 2 +- clash-meta/adapter/outboundgroup/parser.go | 3 +- clash-meta/adapter/provider/parser.go | 15 +- clash-meta/adapter/provider/provider.go | 4 +- clash-meta/component/geodata/init.go | 4 +- clash-meta/component/http/http.go | 8 +- clash-meta/component/mmdb/mmdb.go | 4 +- clash-meta/component/resource/vehicle.go | 12 +- clash-meta/config/config.go | 2 +- clash-meta/config/utils.go | 2 +- clash-meta/docs/config.yaml | 124 ++--- clash-meta/hub/updater/updater.go | 4 +- clash-meta/listener/inner/tcp.go | 5 +- clash-meta/rules/provider/parse.go | 11 +- clash-nyanpasu/backend/Cargo.lock | 64 ++- clash-nyanpasu/manifest/version.json | 4 +- clash-nyanpasu/package.json | 4 +- clash-nyanpasu/pnpm-lock.yaml | 54 +-- echo/go.mod | 1 - echo/go.sum | 2 - echo/internal/relay/conf/cfg.go | 6 +- echo/internal/relay/relay.go | 88 +--- echo/internal/transporter/buffer.go | 18 - echo/internal/transporter/interface.go | 31 +- echo/internal/transporter/{smux.go => mux.go} | 3 +- echo/internal/transporter/raw.go | 172 +++---- .../transporter/{mtcp.go => raw_mux.go} | 64 +-- echo/internal/transporter/ws.go | 45 +- echo/internal/transporter/wss.go | 65 +-- .../transporter/{mwss.go => wss_mux.go} | 80 ++-- echo/internal/web/server.go | 5 +- echo/internal/web/utils.go | 11 + echo/test/relay_test.go | 10 +- .../kernel/linux/modules/netdevices.mk | 17 + ..._generic-add-support-for-sc8280xp-cr.patch | 32 ++ ...ci_generic-Add-HP-variant-of-T99W175.patch | 34 ++ ..._generic-Add-definition-for-some-VID.patch | 66 +++ ..._generic-Drop-redundant-pci_enable_p.patch | 68 +++ ...-mhi-pci_generic-Add-Foxconn-T99W510.patch | 49 ++ ..._generic-Add-support-for-IP_SW0-chan.patch | 67 +++ ..._generic-Add-support-for-Quectel-EM1.patch | 34 ++ ..._generic-Add-support-for-Quectel-RM5.patch | 49 ++ ..._generic-Add-support-for-Dell-DW5932.patch | 34 ++ ..._generic-Add-support-for-Quectel-RM5.patch | 36 ++ ..._generic-add-support-for-Telit-FE990.patch | 33 ++ ...-a-separate-timeout-parameter-for-wa.patch | 175 +++++++ ..._generic-Add-SDX75-based-modem-suppo.patch | 62 +++ ..._generic-constify-modem_telit_fn980_.patch | 28 ++ ...-a-separate-timeout-parameter-for-wa.patch | 175 +++++++ ..._generic-Add-SDX75-based-modem-suppo.patch | 62 +++ ..._generic-constify-modem_telit_fn980_.patch | 28 ++ ...-bus-mhi-core-add-SBL-state-callback.patch | 2 +- ...-bus-mhi-core-add-SBL-state-callback.patch | 2 +- mihomo/adapter/outboundgroup/parser.go | 3 +- mihomo/adapter/provider/parser.go | 15 +- mihomo/adapter/provider/provider.go | 4 +- mihomo/component/geodata/init.go | 4 +- mihomo/component/http/http.go | 8 +- mihomo/component/mmdb/mmdb.go | 4 +- mihomo/component/resource/vehicle.go | 12 +- mihomo/config/config.go | 2 +- mihomo/config/utils.go | 2 +- mihomo/docs/config.yaml | 124 ++--- mihomo/hub/updater/updater.go | 4 +- mihomo/listener/inner/tcp.go | 5 +- mihomo/rules/provider/parse.go | 11 +- ryujinx/Directory.Packages.props | 2 +- ryujinx/docs/README.md | 5 - ryujinx/src/Ryujinx.Cpu/AddressSpace.cs | 437 +----------------- .../Ryujinx.Cpu/AppleHv/HvMemoryManager.cs | 2 +- ryujinx/src/Ryujinx.Cpu/Jit/MemoryManager.cs | 2 +- .../Jit/MemoryManagerHostMapped.cs | 2 +- .../Jit/MemoryManagerHostTracked.cs | 2 +- .../Ryujinx.Graphics.Vulkan/PipelineBase.cs | 1 + .../Ryujinx.Graphics.Vulkan/PipelineState.cs | 11 + .../RenderPassHolder.cs | 7 +- .../ShaderCollection.cs | 2 + .../Ryujinx.Graphics.Vulkan/TextureView.cs | 37 +- .../HOS/ArmProcessContextFactory.cs | 2 +- .../HOS/Kernel/Memory/KPageTable.cs | 2 +- .../HOS/Kernel/Memory/KPageTableBase.cs | 12 +- .../HOS/Kernel/Memory/KSharedMemory.cs | 13 +- ryujinx/src/Ryujinx.HLE/HOS/ModLoader.cs | 2 +- .../HOS/Services/Ptm/Ts/IMeasurementServer.cs | 39 -- .../Ptm/Ipc/MeasurementServer.cs | 63 +++ .../src/Ryujinx.Horizon/Ptm/Ipc/Session.cs | 47 ++ .../src/Ryujinx.Horizon/Ptm/TsIpcServer.cs | 44 ++ ryujinx/src/Ryujinx.Horizon/Ptm/TsMain.cs | 17 + .../src/Ryujinx.Horizon/Sdk/Ts/DeviceCode.cs | 8 + .../Sdk/Ts/IMeasurementServer.cs | 14 + .../src/Ryujinx.Horizon/Sdk/Ts/ISession.cs | 12 + .../Sdk/Ts}/Location.cs | 2 +- ryujinx/src/Ryujinx.Horizon/ServiceTable.cs | 2 + .../src/Ryujinx.Memory/AddressSpaceManager.cs | 2 +- .../Ryujinx.Memory/IVirtualMemoryManager.cs | 6 +- .../MockVirtualMemoryManager.cs | 2 +- .../Configuration/ConfigurationFileFormat.cs | 7 +- .../Configuration/ConfigurationState.cs | 18 + .../Helper/CommandLineState.cs | 7 + ryujinx/src/Ryujinx/Program.cs | 14 +- .../UI/ViewModels/MainWindowViewModel.cs | 10 +- .../Ryujinx/UI/Windows/MainWindow.axaml.cs | 2 +- shadowsocks-rust/Cargo.lock | 54 +-- .../crates/shadowsocks-service/Cargo.toml | 4 +- .../crates/shadowsocks/Cargo.toml | 4 +- v2rayn/v2rayN/v2rayN/Models/ConfigItems.cs | 2 +- yt-dlp/README.md | 3 +- yt-dlp/yt_dlp/extractor/afreecatv.py | 231 +++------ yt-dlp/yt_dlp/extractor/crunchyroll.py | 143 +++--- yt-dlp/yt_dlp/extractor/dropbox.py | 4 +- yt-dlp/yt_dlp/extractor/joqrag.py | 2 +- yt-dlp/yt_dlp/extractor/kick.py | 32 +- 113 files changed, 2052 insertions(+), 1463 deletions(-) rename echo/internal/transporter/{smux.go => mux.go} (98%) rename echo/internal/transporter/{mtcp.go => raw_mux.go} (84%) rename echo/internal/transporter/{mwss.go => wss_mux.go} (81%) create mode 100644 echo/internal/web/utils.go create mode 100644 lede/target/linux/generic/backport-6.1/850-v6.2-bus-mhi-host-pci_generic-add-support-for-sc8280xp-cr.patch create mode 100644 lede/target/linux/generic/backport-6.1/851-v6.2-bus-mhi-host-pci_generic-Add-HP-variant-of-T99W175.patch create mode 100644 lede/target/linux/generic/backport-6.1/852-v6.2-bus-mhi-host-pci_generic-Add-definition-for-some-VID.patch create mode 100644 lede/target/linux/generic/backport-6.1/853-v6.2-bus-mhi-host-pci_generic-Drop-redundant-pci_enable_p.patch create mode 100644 lede/target/linux/generic/backport-6.1/854-v6.4-bus-mhi-pci_generic-Add-Foxconn-T99W510.patch create mode 100644 lede/target/linux/generic/backport-6.1/855-v6.6-bus-mhi-host-pci_generic-Add-support-for-IP_SW0-chan.patch create mode 100644 lede/target/linux/generic/backport-6.1/856-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-EM1.patch create mode 100644 lede/target/linux/generic/backport-6.1/857-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-RM5.patch create mode 100644 lede/target/linux/generic/backport-6.1/858-v6.6-bus-mhi-host-pci_generic-Add-support-for-Dell-DW5932.patch create mode 100644 lede/target/linux/generic/backport-6.1/859-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-RM5.patch create mode 100644 lede/target/linux/generic/backport-6.1/860-v6.6-bus-mhi-host-pci_generic-add-support-for-Telit-FE990.patch create mode 100644 lede/target/linux/generic/backport-6.1/861-v6.8-bus-mhi-host-Add-a-separate-timeout-parameter-for-wa.patch create mode 100644 lede/target/linux/generic/backport-6.1/862-v6.8-bus-mhi-host-pci_generic-Add-SDX75-based-modem-suppo.patch create mode 100644 lede/target/linux/generic/backport-6.1/863-stable-bus-mhi-host-pci_generic-constify-modem_telit_fn980_.patch create mode 100644 lede/target/linux/generic/backport-6.6/850-v6.8-bus-mhi-host-Add-a-separate-timeout-parameter-for-wa.patch create mode 100644 lede/target/linux/generic/backport-6.6/851-v6.8-bus-mhi-host-pci_generic-Add-SDX75-based-modem-suppo.patch create mode 100644 lede/target/linux/generic/backport-6.6/852-stable-bus-mhi-host-pci_generic-constify-modem_telit_fn980_.patch delete mode 100644 ryujinx/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs create mode 100644 ryujinx/src/Ryujinx.Horizon/Ptm/Ipc/MeasurementServer.cs create mode 100644 ryujinx/src/Ryujinx.Horizon/Ptm/Ipc/Session.cs create mode 100644 ryujinx/src/Ryujinx.Horizon/Ptm/TsIpcServer.cs create mode 100644 ryujinx/src/Ryujinx.Horizon/Ptm/TsMain.cs create mode 100644 ryujinx/src/Ryujinx.Horizon/Sdk/Ts/DeviceCode.cs create mode 100644 ryujinx/src/Ryujinx.Horizon/Sdk/Ts/IMeasurementServer.cs create mode 100644 ryujinx/src/Ryujinx.Horizon/Sdk/Ts/ISession.cs rename ryujinx/src/{Ryujinx.HLE/HOS/Services/Ptm/Ts/Types => Ryujinx.Horizon/Sdk/Ts}/Location.cs (61%) diff --git a/.github/update.log b/.github/update.log index 4fbfaf6284..6a0002be8d 100644 --- a/.github/update.log +++ b/.github/update.log @@ -608,3 +608,4 @@ Update On Tue Apr 2 20:27:11 CEST 2024 Update On Wed Apr 3 20:26:29 CEST 2024 Update On Thu Apr 4 20:27:14 CEST 2024 Update On Fri Apr 5 20:26:37 CEST 2024 +Update On Sat Apr 6 20:26:05 CEST 2024 diff --git a/clash-meta-android/core/src/main/golang/native/config/fetch.go b/clash-meta-android/core/src/main/golang/native/config/fetch.go index c1b25105c2..d919f6e745 100644 --- a/clash-meta-android/core/src/main/golang/native/config/fetch.go +++ b/clash-meta-android/core/src/main/golang/native/config/fetch.go @@ -25,7 +25,7 @@ type Status struct { } func openUrl(ctx context.Context, url string) (io.ReadCloser, error) { - response, err := clashHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"ClashMetaForAndroid/" + app.VersionName()}}, nil) + response, err := clashHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"ClashMetaForAndroid/" + app.VersionName()}}, nil, "") if err != nil { return nil, err diff --git a/clash-meta/adapter/outboundgroup/parser.go b/clash-meta/adapter/outboundgroup/parser.go index ac4546d822..876c92fa32 100644 --- a/clash-meta/adapter/outboundgroup/parser.go +++ b/clash-meta/adapter/outboundgroup/parser.go @@ -108,7 +108,6 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide } else { addTestUrlToProviders(PDs, groupOption.URL, expectedStatus, groupOption.Filter, uint(groupOption.Interval)) } - providers = append(providers, PDs...) } @@ -140,7 +139,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide return nil, fmt.Errorf("%s: %w", groupName, err) } - providers = append(providers, pd) + providers = append([]types.ProxyProvider{pd}, providers...) providersMap[groupName] = pd } diff --git a/clash-meta/adapter/provider/parser.go b/clash-meta/adapter/provider/parser.go index 2e4366691e..bbaf29be31 100644 --- a/clash-meta/adapter/provider/parser.go +++ b/clash-meta/adapter/provider/parser.go @@ -44,14 +44,16 @@ type proxyProviderSchema struct { Type string `provider:"type"` Path string `provider:"path,omitempty"` URL string `provider:"url,omitempty"` + Proxy string `provider:"proxy,omitempty"` Interval int `provider:"interval,omitempty"` Filter string `provider:"filter,omitempty"` ExcludeFilter string `provider:"exclude-filter,omitempty"` ExcludeType string `provider:"exclude-type,omitempty"` DialerProxy string `provider:"dialer-proxy,omitempty"` - HealthCheck healthCheckSchema `provider:"health-check,omitempty"` - Override OverrideSchema `provider:"override,omitempty"` + HealthCheck healthCheckSchema `provider:"health-check,omitempty"` + Override OverrideSchema `provider:"override,omitempty"` + Header map[string][]string `provider:"header,omitempty"` } func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvider, error) { @@ -86,16 +88,17 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide path := C.Path.Resolve(schema.Path) vehicle = resource.NewFileVehicle(path) case "http": + var path string if schema.Path != "" { - path := C.Path.Resolve(schema.Path) + path = C.Path.Resolve(schema.Path) if !features.CMFA && !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } - vehicle = resource.NewHTTPVehicle(schema.URL, path) } else { - path := C.Path.GetPathByHash("proxies", schema.URL) - vehicle = resource.NewHTTPVehicle(schema.URL, path) + path = C.Path.GetPathByHash("proxies", schema.URL) } + + vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, schema.Header) default: return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type) } diff --git a/clash-meta/adapter/provider/provider.go b/clash-meta/adapter/provider/provider.go index 2715a30972..aa5b823350 100644 --- a/clash-meta/adapter/provider/provider.go +++ b/clash-meta/adapter/provider/provider.go @@ -125,7 +125,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() resp, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), - http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return } @@ -134,7 +134,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() { userInfoStr := strings.TrimSpace(resp.Header.Get("subscription-userinfo")) if userInfoStr == "" { resp2, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), - http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil) + http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil, "") if err != nil { return } diff --git a/clash-meta/component/geodata/init.go b/clash-meta/component/geodata/init.go index 834567a447..64022f013b 100644 --- a/clash-meta/component/geodata/init.go +++ b/clash-meta/component/geodata/init.go @@ -47,7 +47,7 @@ func InitGeoSite() error { func downloadGeoSite(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return } @@ -66,7 +66,7 @@ func downloadGeoSite(path string) (err error) { func downloadGeoIP(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return } diff --git a/clash-meta/component/http/http.go b/clash-meta/component/http/http.go index 455db681d2..ef37e328b8 100644 --- a/clash-meta/component/http/http.go +++ b/clash-meta/component/http/http.go @@ -16,8 +16,7 @@ import ( "github.com/metacubex/mihomo/listener/inner" ) -func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) { - UA := C.UA +func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader, specialProxy string) (*http.Response, error) { method = strings.ToUpper(method) urlRes, err := URL.Parse(url) if err != nil { @@ -32,7 +31,7 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st } if _, ok := header["User-Agent"]; !ok { - req.Header.Set("User-Agent", UA) + req.Header.Set("User-Agent", C.UA) } if err != nil { @@ -54,7 +53,7 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { - if conn, err := inner.HandleTcp(address); err == nil { + if conn, err := inner.HandleTcp(address, specialProxy); err == nil { return conn, nil } else { d := net.Dialer{} @@ -66,5 +65,4 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st client := http.Client{Transport: transport} return client.Do(req) - } diff --git a/clash-meta/component/mmdb/mmdb.go b/clash-meta/component/mmdb/mmdb.go index 81156bc62d..120739fc15 100644 --- a/clash-meta/component/mmdb/mmdb.go +++ b/clash-meta/component/mmdb/mmdb.go @@ -82,7 +82,7 @@ func IPInstance() IPReader { func DownloadMMDB(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return } @@ -115,7 +115,7 @@ func ASNInstance() ASNReader { func DownloadASN(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.ASNUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.ASNUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return } diff --git a/clash-meta/component/resource/vehicle.go b/clash-meta/component/resource/vehicle.go index b2e2941823..2f71c2e6c6 100644 --- a/clash-meta/component/resource/vehicle.go +++ b/clash-meta/component/resource/vehicle.go @@ -33,8 +33,10 @@ func NewFileVehicle(path string) *FileVehicle { } type HTTPVehicle struct { - url string - path string + url string + path string + proxy string + header http.Header } func (h *HTTPVehicle) Url() string { @@ -52,7 +54,7 @@ func (h *HTTPVehicle) Path() string { func (h *HTTPVehicle) Read() ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*20) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, nil, nil) + resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, h.header, nil, h.proxy) if err != nil { return nil, err } @@ -67,6 +69,6 @@ func (h *HTTPVehicle) Read() ([]byte, error) { return buf, nil } -func NewHTTPVehicle(url string, path string) *HTTPVehicle { - return &HTTPVehicle{url, path} +func NewHTTPVehicle(url string, path string, proxy string, header http.Header) *HTTPVehicle { + return &HTTPVehicle{url, path, proxy, header} } diff --git a/clash-meta/config/config.go b/clash-meta/config/config.go index c793157372..c5c4fa88f4 100644 --- a/clash-meta/config/config.go +++ b/clash-meta/config/config.go @@ -413,7 +413,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { ProxyGroup: []map[string]any{}, TCPConcurrent: false, FindProcessMode: P.FindProcessStrict, - GlobalUA: "clash.meta", + GlobalUA: "clash.meta/" + C.Version, Tun: RawTun{ Enable: false, Device: "", diff --git a/clash-meta/config/utils.go b/clash-meta/config/utils.go index 66bf3441f2..596199ca18 100644 --- a/clash-meta/config/utils.go +++ b/clash-meta/config/utils.go @@ -20,7 +20,7 @@ import ( func downloadForBytes(url string) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return nil, err } diff --git a/clash-meta/docs/config.yaml b/clash-meta/docs/config.yaml index 6aa0686223..869b5231f7 100644 --- a/clash-meta/docs/config.yaml +++ b/clash-meta/docs/config.yaml @@ -8,15 +8,15 @@ mixed-port: 10801 # HTTP(S) 和 SOCKS 代理混合端口 allow-lan: true # 允许局域网连接 bind-address: "*" # 绑定 IP 地址,仅作用于 allow-lan 为 true,'*'表示所有地址 -authentication: # http,socks入口的验证用户名,密码 +authentication: # http,socks 入口的验证用户名,密码 - "username:password" -skip-auth-prefixes: # 设置跳过验证的IP段 +skip-auth-prefixes: # 设置跳过验证的 IP 段 - 127.0.0.1/8 - ::1/128 -lan-allowed-ips: # 允许连接的 IP 地址段,仅作用于 allow-lan 为 true, 默认值为0.0.0.0/0和::/0 +lan-allowed-ips: # 允许连接的 IP 地址段,仅作用于 allow-lan 为 true, 默认值为 0.0.0.0/0 和::/0 - 0.0.0.0/0 - ::/0 -lan-disallowed-ips: # 禁止连接的 IP 地址段, 黑名单优先级高于白名单, 默认值为空 +lan-disallowed-ips: # 禁止连接的 IP 地址段,黑名单优先级高于白名单,默认值为空 - 192.168.0.3/32 # find-process-mode has 3 values:always, strict, off @@ -109,9 +109,9 @@ tun: # auto-detect-interface: true # 自动识别出口网卡 # auto-route: true # 配置路由表 # mtu: 9000 # 最大传输单元 - # gso: false # 启用通用分段卸载, 仅支持 Linux + # gso: false # 启用通用分段卸载,仅支持 Linux # gso-max-size: 65536 # 通用分段卸载包的最大大小 - # strict-route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 + # strict-route: true # 将所有连接路由到 tun 来防止泄漏,但你的设备将无法其他设备被访问 inet4-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 - 0.0.0.0/1 - 128.0.0.0/1 @@ -119,9 +119,9 @@ tun: - "::/1" - "8000::/1" # endpoint-independent-nat: false # 启用独立于端点的 NAT - # include-interface: # 限制被路由的接口。默认不限制, 与 `exclude-interface` 冲突 + # include-interface: # 限制被路由的接口。默认不限制,与 `exclude-interface` 冲突 # - "lan0" - # exclude-interface: # 排除路由的接口, 与 `include-interface` 冲突 + # exclude-interface: # 排除路由的接口,与 `include-interface` 冲突 # - "lan1" # include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto-route # - 0 @@ -143,7 +143,7 @@ tun: # exclude-package: # 排除被路由的 Android 应用包名 # - com.android.captiveportallogin -#ebpf配置 +#ebpf 配置 ebpf: auto-redir: # redirect 模式,仅支持 TCP - eth0 @@ -200,7 +200,7 @@ tunnels: # one line config target: target.com proxy: proxy -# DNS配置 +# DNS 配置 dns: cache-algorithm: arc enable: false # 关闭将使用系统 DNS @@ -208,7 +208,7 @@ dns: listen: 0.0.0.0:53 # 开启 DNS 服务器监听 # ipv6: false # false 将返回 AAAA 的空结果 # ipv6-timeout: 300 # 单位:ms,内部双栈并发时,向上游查询 AAAA 时,等待 AAAA 的时间,默认 100ms - # 用于解析 nameserver,fallback 以及其他DNS服务器配置的,DNS 服务域名 + # 用于解析 nameserver,fallback 以及其他 DNS 服务器配置的,DNS 服务域名 # 只能使用纯 IP 地址,可使用加密 DNS default-nameserver: - 114.114.114.114 @@ -222,12 +222,12 @@ dns: # use-hosts: true # 查询 hosts - # 配置不使用fake-ip的域名 + # 配置不使用 fake-ip 的域名 # fake-ip-filter: # - '*.lan' # - localhost.ptlogin2.qq.com - # DNS主要域名配置 + # DNS 主要域名配置 # 支持 UDP,TCP,DoT,DoH,DoQ # 这部分为主要 DNS 配置,影响所有直连,确保使用对大陆解析精准的 DNS nameserver: @@ -239,7 +239,7 @@ dns: - https://mozilla.cloudflare-dns.com/dns-query#DNS&h3=true # 指定策略组和使用 HTTP/3 - dhcp://en0 # dns from dhcp - quic://dns.adguard.com:784 # DNS over QUIC - # - '8.8.8.8#en0' # 兼容指定DNS出口网卡 + # - '8.8.8.8#en0' # 兼容指定 DNS 出口网卡 # 当配置 fallback 时,会查询 nameserver 中返回的 IP 是否为 CN,非必要配置 # 当不是 CN,则使用 fallback 中的 DNS 查询结果 @@ -338,7 +338,7 @@ proxies: # socks5 # udp-over-tcp: false # ip-version: ipv4 # 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer。默认使用 dual # ipv4:仅使用 IPv4 ipv6:仅使用 IPv6 - # ipv4-prefer:优先使用 IPv4 对于 TCP 会进行双栈解析,并发链接但是优先使用 IPv4 链接, + # ipv4-prefer:优先使用 IPv4 对于 TCP 会进行双栈解析,并发链接但是优先使用 IPv4 链接, # UDP 则为双栈解析,获取结果中的第一个 IPv4 # ipv6-prefer 同 ipv4-prefer # 现有协议都支持此参数,TCP 效果仅在开启 tcp-concurrent 生效 @@ -350,7 +350,7 @@ proxies: # socks5 # max-streams: 0 # Maximum multiplexed streams in a connection before opening a new connection. Conflict with max-connections and min-streams. # padding: false # Enable padding. Requires sing-box server version 1.3-beta9 or later. # statistic: false # 控制是否将底层连接显示在面板中,方便打断底层连接 - # only-tcp: false # 如果设置为true, smux的设置将不会对udp生效,udp连接会直接走底层协议 + # only-tcp: false # 如果设置为 true, smux 的设置将不会对 udp 生效,udp 连接会直接走底层协议 - name: "ss2" type: ss @@ -406,18 +406,18 @@ proxies: # socks5 password: [YOUR_SS_PASSWORD] client-fingerprint: chrome # One of: chrome, ios, firefox or safari - # 可以是chrome, ios, firefox, safari中的一个 + # 可以是 chrome, ios, firefox, safari 中的一个 plugin: restls plugin-opts: host: "www.microsoft.com" # Must be a TLS 1.3 server - # 应当是一个TLS 1.3 服务器 + # 应当是一个 TLS 1.3 服务器 password: [YOUR_RESTLS_PASSWORD] version-hint: "tls13" # Control your post-handshake traffic through restls-script # Hide proxy behaviors like "tls in tls". # see https://github.com/3andne/restls/blob/main/Restls-Script:%20Hide%20Your%20Proxy%20Traffic%20Behavior.md - # 用restls剧本来控制握手后的行为,隐藏"tls in tls"等特征 + # 用 restls 剧本来控制握手后的行为,隐藏"tls in tls"等特征 # 详情:https://github.com/3andne/restls/blob/main/Restls-Script:%20%E9%9A%90%E8%97%8F%E4%BD%A0%E7%9A%84%E4%BB%A3%E7%90%86%E8%A1%8C%E4%B8%BA.md restls-script: "300?100<1,400~100,350~100,600~100,300~200,300~100" @@ -429,18 +429,18 @@ proxies: # socks5 password: [YOUR_SS_PASSWORD] client-fingerprint: chrome # One of: chrome, ios, firefox or safari - # 可以是chrome, ios, firefox, safari中的一个 + # 可以是 chrome, ios, firefox, safari 中的一个 plugin: restls plugin-opts: host: "vscode.dev" # Must be a TLS 1.2 server - # 应当是一个TLS 1.2 服务器 + # 应当是一个 TLS 1.2 服务器 password: [YOUR_RESTLS_PASSWORD] version-hint: "tls12" restls-script: "1000?100<1,500~100,350~100,600~100,400~200" # vmess - # cipher支持 auto/aes-128-gcm/chacha20-poly1305/none + # cipher 支持 auto/aes-128-gcm/chacha20-poly1305/none - name: "vmess" type: vmess server: server @@ -680,11 +680,11 @@ proxies: # socks5 port: 443 # ports: 1000,2000-3000,5000 # port 不可省略 # hop-interval: 15 - # up和down均不写或为0则使用BBR流控 + # up 和 down 均不写或为 0 则使用 BBR 流控 # up: "30 Mbps" # 若不写单位,默认为 Mbps # down: "200 Mbps" # 若不写单位,默认为 Mbps password: yourpassword - # obfs: salamander # 默认为空,如果填写则开启obfs,目前仅支持salamander + # obfs: salamander # 默认为空,如果填写则开启 obfs,目前仅支持 salamander # obfs-password: yourpassword # sni: server.com # skip-cert-verify: false @@ -710,9 +710,9 @@ proxies: # socks5 # reserved: [209,98,59] # 一个出站代理的标识。当值不为空时,将使用指定的 proxy 发出连接 # dialer-proxy: "ss1" - # remote-dns-resolve: true # 强制dns远程解析,默认值为false - # dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在remote-dns-resolve为true时生效 - # 如果peers不为空,该段落中的allowed-ips不可为空;前面段落的server,port,public-key,pre-shared-key均会被忽略,但private-key会被保留且只能在顶层指定 + # remote-dns-resolve: true # 强制 dns 远程解析,默认值为 false + # dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在 remote-dns-resolve 为 true 时生效 + # 如果 peers 不为空,该段落中的 allowed-ips 不可为空;前面段落的 server,port,public-key,pre-shared-key 均会被忽略,但 private-key 会被保留且只能在顶层指定 # peers: # - server: 162.159.192.1 # port: 2480 @@ -726,9 +726,9 @@ proxies: # socks5 server: www.example.com port: 10443 type: tuic - # tuicV4必须填写token (不可同时填写uuid和password) + # tuicV4 必须填写 token(不可同时填写 uuid 和 password) token: TOKEN - # tuicV5必须填写uuid和password(不可同时填写token) + # tuicV5 必须填写 uuid 和 password(不可同时填写 token) uuid: 00000000-0000-0000-0000-000000000001 password: PASSWORD_1 # ip: 127.0.0.1 # for overwriting the DNS lookup result of the server address set in option 'server' @@ -746,8 +746,8 @@ proxies: # socks5 # max-open-streams: 20 # default 100, too many open streams may hurt performance # sni: example.com # - # meta和sing-box私有扩展,将ss-uot用于udp中继,开启此选项后udp-relay-mode将失效 - # 警告,与原版tuic不兼容!!! + # meta 和 sing-box 私有扩展,将 ss-uot 用于 udp 中继,开启此选项后 udp-relay-mode 将失效 + # 警告,与原版 tuic 不兼容!!! # udp-over-stream: false # udp-over-stream-version: 1 @@ -780,12 +780,12 @@ proxies: # socks5 password: password privateKey: path -# dns出站会将请求劫持到内部dns模块,所有请求均在内部处理 +# dns 出站会将请求劫持到内部 dns 模块,所有请求均在内部处理 - name: "dns-out" type: dns proxy-groups: - # 代理链,目前relay可以支持udp的只有vmess/vless/trojan/ss/ssr/tuic - # wireguard目前不支持在relay中使用,请使用proxy中的dialer-proxy配置项 + # 代理链,目前 relay 可以支持 udp 的只有 vmess/vless/trojan/ss/ssr/tuic + # wireguard 目前不支持在 relay 中使用,请使用 proxy 中的 dialer-proxy 配置项 # Traffic: mihomo <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet - name: "relay" type: relay @@ -859,10 +859,19 @@ proxy-groups: # Mihomo 格式的节点或支持 *ray 的分享格式 proxy-providers: provider1: - type: http # http 的 path 可空置,默认储存路径为 homedir的proxies文件夹,文件名为url的md5 + type: http # http 的 path 可空置,默认储存路径为 homedir 的 proxies 文件夹,文件名为 url 的 md5 url: "url" interval: 3600 path: ./provider1.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 + proxy: DIRECT + header: + User-Agent: + - "Clash/v1.18.0" + - "mihomo/1.18.3" + # Accept: + # - 'application/vnd.github.v3.raw' + # Authorization: + # - 'token 1231231' health-check: enable: true interval: 600 @@ -892,8 +901,9 @@ rule-providers: behavior: classical # domain ipcidr interval: 259200 path: /path/to/save/file.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 - type: http # http 的 path 可空置,默认储存路径为 homedir的rules文件夹,文件名为url的md5 + type: http # http 的 path 可空置,默认储存路径为 homedir 的 rules 文件夹,文件名为 url 的 md5 url: "url" + proxy: DIRECT rule2: behavior: classical interval: 259200 @@ -942,7 +952,7 @@ listeners: port: 10808 #listen: 0.0.0.0 # 默认监听 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理 + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 # udp: false # 默认 true - name: http-in-1 @@ -950,14 +960,14 @@ listeners: port: 10809 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) - name: mixed-in-1 type: mixed # HTTP(S) 和 SOCKS 代理混合 port: 10810 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) # udp: false # 默认 true - name: reidr-in-1 @@ -965,14 +975,14 @@ listeners: port: 10811 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) - name: tproxy-in-1 type: tproxy port: 10812 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) # udp: false # 默认 true - name: shadowsocks-in-1 @@ -980,7 +990,7 @@ listeners: port: 10813 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) password: vlmpIPSyHH6f4S8WVPdRIHIlzmB+GIRfoH3aNJ/t9Gg= cipher: 2022-blake3-aes-256-gcm @@ -989,13 +999,13 @@ listeners: port: 10814 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) users: - username: 1 uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 alterId: 1 - # ws-path: "/" # 如果不为空则开启websocket传输层 - # 下面两项如果填写则开启tls(需要同时填写) + # ws-path: "/" # 如果不为空则开启 websocket 传输层 + # 下面两项如果填写则开启 tls(需要同时填写) # certificate: ./server.crt # private-key: ./server.key @@ -1004,10 +1014,10 @@ listeners: port: 10815 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) - # token: # tuicV4填写(可以同时填写users) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) + # token: # tuicV4 填写(可以同时填写 users) # - TOKEN - # users: # tuicV5填写(可以同时填写token) + # users: # tuicV5 填写(可以同时填写 token) # 00000000-0000-0000-0000-000000000000: PASSWORD_0 # 00000000-0000-0000-0000-000000000001: PASSWORD_1 # certificate: ./server.crt @@ -1024,25 +1034,25 @@ listeners: port: 10816 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) network: [tcp, udp] target: target.com - name: tun-in-1 type: tun # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) stack: system # gvisor / mixed dns-hijack: - 0.0.0.0:53 # 需要劫持的 DNS # auto-detect-interface: false # 自动识别出口网卡 # auto-route: false # 配置路由表 # mtu: 9000 # 最大传输单元 - inet4-address: # 必须手动设置ipv4地址段 + inet4-address: # 必须手动设置 ipv4 地址段 - 198.19.0.1/30 - inet6-address: # 必须手动设置ipv6地址段 + inet6-address: # 必须手动设置 ipv6 地址段 - "fdfe:dcba:9877::1/126" - # strict-route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 + # strict-route: true # 将所有连接路由到 tun 来防止泄漏,但你的设备将无法其他设备被访问 # inet4-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 # - 0.0.0.0/1 # - 128.0.0.0/1 @@ -1070,17 +1080,17 @@ listeners: # exclude-package: # 排除被路由的 Android 应用包名 # - com.android.captiveportallogin # 入口配置与 Listener 等价,传入流量将和 socks,mixed 等入口一样按照 mode 所指定的方式进行匹配处理 -# shadowsocks,vmess 入口配置(传入流量将和socks,mixed等入口一样按照mode所指定的方式进行匹配处理) +# shadowsocks,vmess 入口配置(传入流量将和 socks,mixed 等入口一样按照 mode 所指定的方式进行匹配处理) # ss-config: ss://2022-blake3-aes-256-gcm:vlmpIPSyHH6f4S8WVPdRIHIlzmB+GIRfoH3aNJ/t9Gg=@:23456 # vmess-config: vmess://1:9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68@:12345 -# tuic服务器入口(传入流量将和socks,mixed等入口一样按照mode所指定的方式进行匹配处理) +# tuic 服务器入口(传入流量将和 socks,mixed 等入口一样按照 mode 所指定的方式进行匹配处理) # tuic-server: # enable: true # listen: 127.0.0.1:10443 -# token: # tuicV4填写(可以同时填写users) +# token: # tuicV4 填写(可以同时填写 users) # - TOKEN -# users: # tuicV5填写(可以同时填写token) +# users: # tuicV5 填写(可以同时填写 token) # 00000000-0000-0000-0000-000000000000: PASSWORD_0 # 00000000-0000-0000-0000-000000000001: PASSWORD_1 # certificate: ./server.crt diff --git a/clash-meta/hub/updater/updater.go b/clash-meta/hub/updater/updater.go index 02ff07ba26..e0d3a39ca1 100644 --- a/clash-meta/hub/updater/updater.go +++ b/clash-meta/hub/updater/updater.go @@ -234,7 +234,7 @@ const MaxPackageFileSize = 32 * 1024 * 1024 func downloadPackageFile() (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return fmt.Errorf("http request failed: %w", err) } @@ -415,7 +415,7 @@ func copyFile(src, dst string) error { func getLatestVersion() (version string, err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return "", fmt.Errorf("get Latest Version fail: %w", err) } diff --git a/clash-meta/listener/inner/tcp.go b/clash-meta/listener/inner/tcp.go index dac3d72143..ee34ada661 100644 --- a/clash-meta/listener/inner/tcp.go +++ b/clash-meta/listener/inner/tcp.go @@ -16,7 +16,7 @@ func New(t C.Tunnel) { tunnel = t } -func HandleTcp(address string) (conn net.Conn, err error) { +func HandleTcp(address string, proxy string) (conn net.Conn, err error) { if tunnel == nil { return nil, errors.New("tcp uninitialized") } @@ -28,6 +28,9 @@ func HandleTcp(address string) (conn net.Conn, err error) { metadata.Type = C.INNER metadata.DNSMode = C.DNSNormal metadata.Process = C.MihomoName + if proxy != "" { + metadata.SpecialProxy = proxy + } if h, port, err := net.SplitHostPort(address); err == nil { if port, err := strconv.ParseUint(port, 10, 16); err == nil { metadata.DstPort = uint16(port) diff --git a/clash-meta/rules/provider/parse.go b/clash-meta/rules/provider/parse.go index a867d570fd..e7920adf6c 100644 --- a/clash-meta/rules/provider/parse.go +++ b/clash-meta/rules/provider/parse.go @@ -21,6 +21,7 @@ type ruleProviderSchema struct { Behavior string `provider:"behavior"` Path string `provider:"path,omitempty"` URL string `provider:"url,omitempty"` + Proxy string `provider:"proxy,omitempty"` Format string `provider:"format,omitempty"` Interval int `provider:"interval,omitempty"` } @@ -61,17 +62,17 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t path := C.Path.Resolve(schema.Path) vehicle = resource.NewFileVehicle(path) case "http": + var path string if schema.Path != "" { - path := C.Path.Resolve(schema.Path) + path = C.Path.Resolve(schema.Path) if !features.CMFA && !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } - vehicle = resource.NewHTTPVehicle(schema.URL, path) } else { - path := C.Path.GetPathByHash("rules", schema.URL) - vehicle = resource.NewHTTPVehicle(schema.URL, path) - } + path = C.Path.GetPathByHash("rules", schema.URL) + } + vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, nil) default: return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type) } diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock index 83f24b44ec..3e1670a683 100644 --- a/clash-nyanpasu/backend/Cargo.lock +++ b/clash-nyanpasu/backend/Cargo.lock @@ -2275,7 +2275,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap 2.2.6", "slab", "tokio", @@ -2345,7 +2345,7 @@ dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http", + "http 0.2.12", "httpdate", "mime", "sha1", @@ -2357,7 +2357,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", + "http 0.2.12", ] [[package]] @@ -2436,6 +2436,17 @@ dependencies = [ "itoa 1.0.11", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.11", +] + [[package]] name = "http-body" version = "0.4.6" @@ -2443,7 +2454,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", "pin-project-lite", ] @@ -2476,13 +2487,13 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "httparse", "httpdate", "itoa 1.0.11", "pin-project-lite", - "socket2 0.5.6", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -2496,7 +2507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", + "http 0.2.12", "hyper", "rustls", "tokio", @@ -3326,7 +3337,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 0.2.12", "httparse", "log", "memchr", @@ -4623,7 +4634,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "hyper", "hyper-rustls", @@ -5720,7 +5731,7 @@ dependencies = [ "glob", "gtk", "heck 0.4.1", - "http", + "http 0.2.12", "ignore", "indexmap 1.9.3", "infer 0.9.0", @@ -5844,7 +5855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf2d0652aa2891ff3e9caa2401405257ea29ab8372cce01f186a5825f1bd0e76" dependencies = [ "gtk", - "http", + "http 0.2.12", "http-range", "rand 0.8.5", "raw-window-handle 0.5.2", @@ -6164,22 +6175,11 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-tungstenite" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" dependencies = [ "futures-util", "log", @@ -6412,14 +6412,14 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 1.1.0", "httparse", "log", "rand 0.8.5", @@ -6642,15 +6642,15 @@ dependencies = [ [[package]] name = "warp" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e92e22e03ff1230c03a1a8ee37d2f89cd489e2e541b7550d6afad96faed169" +checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" dependencies = [ "bytes", "futures-channel", "futures-util", "headers", - "http", + "http 0.2.12", "hyper", "log", "mime", @@ -6658,13 +6658,11 @@ dependencies = [ "multer", "percent-encoding", "pin-project", - "rustls-pemfile", "scoped-tls", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-stream", "tokio-tungstenite", "tokio-util", "tower-service", @@ -7543,7 +7541,7 @@ dependencies = [ "glib", "gtk", "html5ever", - "http", + "http 0.2.12", "kuchikiki", "libc", "log", diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index 1fd6f9e96a..3d99d907ff 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,7 +2,7 @@ "manifest_version": 1, "latest": { "mihomo": "v1.18.3", - "mihomo_alpha": "alpha-90bf158", + "mihomo_alpha": "alpha-5bae0b6", "clash_rs": "v0.1.15", "clash_premium": "2023-09-05-gdcc8d87" }, @@ -36,5 +36,5 @@ "darwin-x64": "clash-darwin-amd64-n{}.gz" } }, - "updated_at": "2024-04-04T22:19:02.557Z" + "updated_at": "2024-04-05T22:19:27.268Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index da4903a70e..e6ebfa2d0f 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -78,7 +78,7 @@ "ahooks": "3.7.11", "axios": "1.6.8", "dayjs": "1.11.10", - "framer-motion": "11.0.24", + "framer-motion": "11.0.25", "i18next": "23.10.1", "lodash-es": "4.17.21", "monaco-editor": "0.47.0", @@ -103,7 +103,7 @@ "@types/fs-extra": "11.0.4", "@types/js-cookie": "3.0.6", "@types/lodash-es": "4.17.12", - "@types/node": "20.12.4", + "@types/node": "20.12.5", "@types/react": "18.2.74", "@types/react-dom": "18.2.24", "@types/react-transition-group": "4.4.10", diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index 9bcada81e8..c940be7fb1 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -54,8 +54,8 @@ dependencies: specifier: 1.11.10 version: 1.11.10 framer-motion: - specifier: 11.0.24 - version: 11.0.24(react-dom@18.2.0)(react@18.2.0) + specifier: 11.0.25 + version: 11.0.25(react-dom@18.2.0)(react@18.2.0) i18next: specifier: 23.10.1 version: 23.10.1 @@ -108,7 +108,7 @@ devDependencies: version: 6.0.0 '@commitlint/cli': specifier: 19.2.1 - version: 19.2.1(@types/node@20.12.4)(typescript@5.4.4) + version: 19.2.1(@types/node@20.12.5)(typescript@5.4.4) '@commitlint/config-conventional': specifier: 19.1.0 version: 19.1.0 @@ -125,8 +125,8 @@ devDependencies: specifier: 4.17.12 version: 4.17.12 '@types/node': - specifier: 20.12.4 - version: 20.12.4 + specifier: 20.12.5 + version: 20.12.5 '@types/react': specifier: 18.2.74 version: 18.2.74 @@ -273,7 +273,7 @@ devDependencies: version: 5.4.4 vite: specifier: 5.2.8 - version: 5.2.8(@types/node@20.12.4)(sass@1.74.1) + version: 5.2.8(@types/node@20.12.5)(sass@1.74.1) vite-plugin-monaco-editor: specifier: npm:vite-plugin-monaco-editor-new@1.1.3 version: /vite-plugin-monaco-editor-new@1.1.3(monaco-editor@0.47.0) @@ -549,14 +549,14 @@ packages: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 - /@commitlint/cli@19.2.1(@types/node@20.12.4)(typescript@5.4.4): + /@commitlint/cli@19.2.1(@types/node@20.12.5)(typescript@5.4.4): resolution: {integrity: sha512-cbkYUJsLqRomccNxvoJTyv5yn0bSy05BBizVyIcLACkRbVUqYorC351Diw/XFSWC/GtpwiwT2eOvQgFZa374bg==} engines: {node: '>=v18'} hasBin: true dependencies: '@commitlint/format': 19.0.3 '@commitlint/lint': 19.1.0 - '@commitlint/load': 19.2.0(@types/node@20.12.4)(typescript@5.4.4) + '@commitlint/load': 19.2.0(@types/node@20.12.5)(typescript@5.4.4) '@commitlint/read': 19.2.1 '@commitlint/types': 19.0.3 execa: 8.0.1 @@ -625,7 +625,7 @@ packages: '@commitlint/types': 19.0.3 dev: true - /@commitlint/load@19.2.0(@types/node@20.12.4)(typescript@5.4.4): + /@commitlint/load@19.2.0(@types/node@20.12.5)(typescript@5.4.4): resolution: {integrity: sha512-XvxxLJTKqZojCxaBQ7u92qQLFMMZc4+p9qrIq/9kJDy8DOrEa7P1yx7Tjdc2u2JxIalqT4KOGraVgCE7eCYJyQ==} engines: {node: '>=v18'} dependencies: @@ -635,7 +635,7 @@ packages: '@commitlint/types': 19.0.3 chalk: 5.3.0 cosmiconfig: 9.0.0(typescript@5.4.4) - cosmiconfig-typescript-loader: 5.0.0(@types/node@20.12.4)(cosmiconfig@9.0.0)(typescript@5.4.4) + cosmiconfig-typescript-loader: 5.0.0(@types/node@20.12.5)(cosmiconfig@9.0.0)(typescript@5.4.4) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -1396,7 +1396,7 @@ packages: generouted: 1.18.6(vite@5.2.8) react: 18.2.0 react-router-dom: 6.22.3(react-dom@18.2.0)(react@18.2.0) - vite: 5.2.8(@types/node@20.12.4)(sass@1.74.1) + vite: 5.2.8(@types/node@20.12.5)(sass@1.74.1) dev: false /@humanwhocodes/config-array@0.11.14: @@ -2226,7 +2226,7 @@ packages: /@types/conventional-commits-parser@5.0.0: resolution: {integrity: sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==} dependencies: - '@types/node': 20.12.4 + '@types/node': 20.12.5 dev: true /@types/debug@4.1.12: @@ -2248,7 +2248,7 @@ packages: resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 20.12.4 + '@types/node': 20.12.5 dev: true /@types/hast@3.0.4: @@ -2272,7 +2272,7 @@ packages: /@types/jsonfile@6.1.4: resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} dependencies: - '@types/node': 20.12.4 + '@types/node': 20.12.5 dev: true /@types/lodash-es@4.17.12: @@ -2295,8 +2295,8 @@ packages: resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} dev: false - /@types/node@20.12.4: - resolution: {integrity: sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==} + /@types/node@20.12.5: + resolution: {integrity: sha512-BD+BjQ9LS/D8ST9p5uqBxghlN+S42iuNxjsUGjeZobe/ciXzk2qb1B6IXc6AnRLS+yFJRpN2IPEHMzwspfDJNw==} dependencies: undici-types: 5.26.5 @@ -2482,7 +2482,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.23.6) '@types/babel__core': 7.20.5 react-refresh: 0.14.0 - vite: 5.2.8(@types/node@20.12.4)(sass@1.74.1) + vite: 5.2.8(@types/node@20.12.5)(sass@1.74.1) transitivePeerDependencies: - supports-color dev: true @@ -3115,7 +3115,7 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true - /cosmiconfig-typescript-loader@5.0.0(@types/node@20.12.4)(cosmiconfig@9.0.0)(typescript@5.4.4): + /cosmiconfig-typescript-loader@5.0.0(@types/node@20.12.5)(cosmiconfig@9.0.0)(typescript@5.4.4): resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==} engines: {node: '>=v16'} peerDependencies: @@ -3123,7 +3123,7 @@ packages: cosmiconfig: '>=8.2' typescript: '>=4' dependencies: - '@types/node': 20.12.4 + '@types/node': 20.12.5 cosmiconfig: 9.0.0(typescript@5.4.4) jiti: 1.21.0 typescript: 5.4.4 @@ -4185,8 +4185,8 @@ packages: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true - /framer-motion@11.0.24(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-l2iM8NR53qtcujgAqYvGPJJGModPNWEVUaATRDLfnaLvUoFpImovBm0AHalSSsY8tW6knP8mfJTW4WYGbnAe4w==} + /framer-motion@11.0.25(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-mRt7vQGzA7++wTgb+PW1TrlXXgndqR6hCiJ48fXr2X9alte2hPQiAq556HRwDCt0Q5X98MNvcSe4KUa27Gm5Lg==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 @@ -4246,7 +4246,7 @@ packages: peerDependencies: vite: '>=3' dependencies: - vite: 5.2.8(@types/node@20.12.4)(sass@1.74.1) + vite: 5.2.8(@types/node@20.12.5)(sass@1.74.1) dev: false /gensync@1.0.0-beta.2: @@ -7367,7 +7367,7 @@ packages: postcss-js: 4.0.1(postcss@8.4.38) prettier: 3.2.5 sass: 1.74.1 - vite: 5.2.8(@types/node@20.12.4)(sass@1.74.1) + vite: 5.2.8(@types/node@20.12.5)(sass@1.74.1) dev: true /vite-plugin-svgr@4.2.0(typescript@5.4.4)(vite@5.2.8): @@ -7378,7 +7378,7 @@ packages: '@rollup/pluginutils': 5.0.5 '@svgr/core': 8.1.0(typescript@5.4.4) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0) - vite: 5.2.8(@types/node@20.12.4)(sass@1.74.1) + vite: 5.2.8(@types/node@20.12.5)(sass@1.74.1) transitivePeerDependencies: - rollup - supports-color @@ -7396,13 +7396,13 @@ packages: debug: 4.3.4 globrex: 0.1.2 tsconfck: 3.0.3(typescript@5.4.4) - vite: 5.2.8(@types/node@20.12.4)(sass@1.74.1) + vite: 5.2.8(@types/node@20.12.5)(sass@1.74.1) transitivePeerDependencies: - supports-color - typescript dev: true - /vite@5.2.8(@types/node@20.12.4)(sass@1.74.1): + /vite@5.2.8(@types/node@20.12.5)(sass@1.74.1): resolution: {integrity: sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -7430,7 +7430,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.12.4 + '@types/node': 20.12.5 esbuild: 0.20.2 postcss: 8.4.38 rollup: 4.13.0 diff --git a/echo/go.mod b/echo/go.mod index 4c57df48d1..fc331e3b39 100644 --- a/echo/go.mod +++ b/echo/go.mod @@ -9,7 +9,6 @@ require ( github.com/getsentry/sentry-go v0.27.0 github.com/go-ping/ping v1.1.0 github.com/gobwas/ws v1.3.2 - github.com/gorilla/mux v1.8.1 github.com/labstack/echo/v4 v4.11.4 github.com/prometheus/client_golang v1.19.0 github.com/prometheus/common v0.48.0 diff --git a/echo/go.sum b/echo/go.sum index e83e69ac31..38271f76c1 100644 --- a/echo/go.sum +++ b/echo/go.sum @@ -110,8 +110,6 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= diff --git a/echo/internal/relay/conf/cfg.go b/echo/internal/relay/conf/cfg.go index 7c25929bcf..d9ad952db1 100644 --- a/echo/internal/relay/conf/cfg.go +++ b/echo/internal/relay/conf/cfg.go @@ -57,6 +57,10 @@ func (r *Config) Validate() error { if len(r.TCPRemotes) == 0 && len(r.UDPRemotes) == 0 { return errors.New("both tcp and udp remotes are empty") } + + if len(r.UDPRemotes) > 0 { + zap.S().Warn("UDP RELAY WAS DISABLED FOR NOW, THIS FEATURE WILL BE AVAILABLE IN THE FUTURE") + } return nil } @@ -111,7 +115,7 @@ func (r *Config) defaultLabel() string { func (r *Config) Adjust() error { if r.Label == "" { r.Label = r.defaultLabel() - zap.S().Warnf("label is empty, set default label:%s", r.Label) + zap.S().Debugf("label is empty, set default label:%s", r.Label) } return nil } diff --git a/echo/internal/relay/relay.go b/echo/internal/relay/relay.go index df81640853..a832f4cf19 100644 --- a/echo/internal/relay/relay.go +++ b/echo/internal/relay/relay.go @@ -7,22 +7,19 @@ import ( "github.com/Ehco1996/ehco/internal/cmgr" "github.com/Ehco1996/ehco/internal/constant" - "github.com/Ehco1996/ehco/internal/metrics" "github.com/Ehco1996/ehco/internal/relay/conf" "github.com/Ehco1996/ehco/internal/transporter" ) type Relay struct { - Name string // unique name for all relay\ + Name string // unique name for all relay TransportType string ListenType string - TP transporter.RelayTransporter + + TP transporter.RelayTransporter LocalTCPAddr *net.TCPAddr - LocalUDPAddr *net.UDPAddr - - closeTcpF func() error - closeUdpF func() error + closeTcpF func() error cfg *conf.Config l *zap.SugaredLogger @@ -33,10 +30,6 @@ func NewRelay(cfg *conf.Config, connMgr cmgr.Cmgr) (*Relay, error) { if err != nil { return nil, err } - localUDPAddr, err := net.ResolveUDPAddr("udp", cfg.Listen) - if err != nil { - return nil, err - } r := &Relay{ cfg: cfg, @@ -44,7 +37,6 @@ func NewRelay(cfg *conf.Config, connMgr cmgr.Cmgr) (*Relay, error) { Name: cfg.Label, LocalTCPAddr: localTCPAddr, - LocalUDPAddr: localUDPAddr, ListenType: cfg.ListenType, TransportType: cfg.TransportType, TP: transporter.NewRelayTransporter(cfg, connMgr), @@ -80,23 +72,11 @@ func (r *Relay) ListenAndServe() error { }() } } - - if len(r.cfg.UDPRemotes) > 0 { - go func() { - errCh <- r.RunLocalUDPServer() - }() - } return <-errCh } func (r *Relay) Close() { r.l.Infof("Close relay label: %s", r.Name) - if r.closeUdpF != nil { - err := r.closeUdpF() - if err != nil { - r.l.Errorf(err.Error()) - } - } if r.closeTcpF != nil { err := r.closeTcpF() if err != nil { @@ -106,63 +86,19 @@ func (r *Relay) Close() { } func (r *Relay) RunLocalTCPServer() error { - lis, err := net.ListenTCP("tcp", r.LocalTCPAddr) + rawServer, err := transporter.NewRawServer(r.LocalTCPAddr.String(), r.TP) if err != nil { return err } - defer lis.Close() //nolint: errcheck r.closeTcpF = func() error { - return lis.Close() + return rawServer.Close() } r.l.Infof("Start TCP relay Server: %s", r.Name) - for { - c, err := lis.AcceptTCP() - if err != nil { - return err - } - - go func(c net.Conn) { - remote := r.TP.GetRemote() - metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Inc() - defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Dec() - if err := r.TP.HandleTCPConn(c, remote); err != nil { - r.l.Errorf("HandleTCPConn meet error tp:%s from:%s to:%s err:%s", - r.TransportType, - c.RemoteAddr(), remote.Address, err) - } - }(c) - } -} - -func (r *Relay) RunLocalUDPServer() error { - lis, err := net.ListenUDP("udp", r.LocalUDPAddr) - if err != nil { - return err - } - defer lis.Close() //nolint: errcheck - r.closeUdpF = func() error { - return lis.Close() - } - r.l.Infof("Start UDP relay Server: %s", r.Name) - - buf := transporter.BufferPool.Get() - defer transporter.BufferPool.Put(buf) - for { - n, addr, err := lis.ReadFromUDP(buf) - if err != nil { - return err - } - bc := r.TP.GetOrCreateBufferCh(addr) - bc.Ch <- buf[0:n] - if !bc.Handled.Load() { - bc.Handled.Store(true) - go r.TP.HandleUDPConn(bc.UDPAddr, lis) - } - } + return rawServer.ListenAndServe() } func (r *Relay) RunLocalMTCPServer() error { - tp := r.TP.(*transporter.Raw) + tp := r.TP.(*transporter.RawClient) mTCPServer := transporter.NewMTCPServer(r.LocalTCPAddr.String(), tp, r.l.Named("MTCPServer")) r.closeTcpF = func() error { return mTCPServer.Close() @@ -172,7 +108,7 @@ func (r *Relay) RunLocalMTCPServer() error { } func (r *Relay) RunLocalWSServer() error { - tp := r.TP.(*transporter.Raw) + tp := r.TP.(*transporter.RawClient) wsServer := transporter.NewWSServer(r.LocalTCPAddr.String(), tp, r.l.Named("WSServer")) r.closeTcpF = func() error { return wsServer.Close() @@ -182,8 +118,8 @@ func (r *Relay) RunLocalWSServer() error { } func (r *Relay) RunLocalWSSServer() error { - tp := r.TP.(*transporter.Raw) - wssServer := transporter.NewWSSServer(r.LocalTCPAddr.String(), tp, r.l.Named("NewWSSServer")) + tp := r.TP.(*transporter.RawClient) + wssServer := transporter.NewWSSServer(r.LocalTCPAddr.String(), tp, r.l.Named("WSSServer")) r.closeTcpF = func() error { return wssServer.Close() } @@ -192,7 +128,7 @@ func (r *Relay) RunLocalWSSServer() error { } func (r *Relay) RunLocalMWSSServer() error { - tp := r.TP.(*transporter.Raw) + tp := r.TP.(*transporter.RawClient) mwssServer := transporter.NewMWSSServer(r.LocalTCPAddr.String(), tp, r.l.Named("MWSSServer")) r.closeTcpF = func() error { return mwssServer.Close() diff --git a/echo/internal/transporter/buffer.go b/echo/internal/transporter/buffer.go index 59d9b893b8..8edd7ebef5 100644 --- a/echo/internal/transporter/buffer.go +++ b/echo/internal/transporter/buffer.go @@ -1,10 +1,6 @@ package transporter import ( - "net" - - "go.uber.org/atomic" - "github.com/Ehco1996/ehco/internal/constant" ) @@ -51,17 +47,3 @@ func (bp *BytePool) Put(b []byte) { // buffer didn't go back into pool, just discard } } - -type BufferCh struct { - Ch chan []byte - Handled atomic.Bool - UDPAddr *net.UDPAddr -} - -func newudpBufferCh(clientUDPAddr *net.UDPAddr) *BufferCh { - return &BufferCh{ - Ch: make(chan []byte, 100), - Handled: atomic.Bool{}, - UDPAddr: clientUDPAddr, - } -} diff --git a/echo/internal/transporter/interface.go b/echo/internal/transporter/interface.go index 0a7a3fcaeb..e0fd5f430b 100644 --- a/echo/internal/transporter/interface.go +++ b/echo/internal/transporter/interface.go @@ -12,11 +12,6 @@ import ( // RelayTransporter type RelayTransporter interface { - // UDP相关 - GetOrCreateBufferCh(uaddr *net.UDPAddr) *BufferCh - HandleUDPConn(uaddr *net.UDPAddr, local *net.UDPConn) - - // TCP相关 dialRemote(remote *lb.Node) (net.Conn, error) HandleTCPConn(c net.Conn, remote *lb.Node) error GetRemote() *lb.Node @@ -30,34 +25,18 @@ func NewRelayTransporter(cfg *conf.Config, connMgr cmgr.Cmgr) RelayTransporter { Label: fmt.Sprintf("%s-%s", cfg.Label, addr), } } - udpNodeList := make([]*lb.Node, len(cfg.UDPRemotes)) - for idx, addr := range cfg.UDPRemotes { - udpNodeList[idx] = &lb.Node{ - Address: addr, - Label: fmt.Sprintf("%s-%s", cfg.Label, addr), - } - } - raw := newRaw(cfg.Label, lb.NewRoundRobin(tcpNodeList), lb.NewRoundRobin(udpNodeList), connMgr) - + raw := newRawClient(cfg.Label, lb.NewRoundRobin(tcpNodeList), connMgr) switch cfg.TransportType { case constant.Transport_RAW: return raw case constant.Transport_WS: - return &Ws{Raw: raw} + return newWsClient(raw) case constant.Transport_WSS: - return &Wss{Raw: raw} + return newWSSClient(raw) case constant.Transport_MWSS: - logger := raw.l.Named("MWSSClient") - mWSSClient := NewMWSSClient(logger) - mwss := &Mwss{mtp: NewSmuxTransporter(logger, mWSSClient.InitNewSession)} - mwss.Raw = raw - return mwss + return newMWSSClient(raw) case constant.Transport_MTCP: - logger := raw.l.Named("MTCPClient") - mTCPClient := NewMTCPClient(logger) - mtcp := &MTCP{mtp: NewSmuxTransporter(logger, mTCPClient.InitNewSession)} - mtcp.Raw = raw - return mtcp + return newMTCPClient(raw) } return nil } diff --git a/echo/internal/transporter/smux.go b/echo/internal/transporter/mux.go similarity index 98% rename from echo/internal/transporter/smux.go rename to echo/internal/transporter/mux.go index 362b6304f6..ae82212532 100644 --- a/echo/internal/transporter/smux.go +++ b/echo/internal/transporter/mux.go @@ -56,7 +56,8 @@ func (sm *SessionWithMetrics) canCloseSession(remoteAddr string, l *zap.SugaredL return true } -func NewSmuxTransporter(l *zap.SugaredLogger, +func NewSmuxTransporter( + l *zap.SugaredLogger, initSessionF func(ctx context.Context, addr string) (*smux.Session, error), ) *smuxTransporter { tr := &smuxTransporter{ diff --git a/echo/internal/transporter/raw.go b/echo/internal/transporter/raw.go index 0b5669c1bc..d9954780bd 100644 --- a/echo/internal/transporter/raw.go +++ b/echo/internal/transporter/raw.go @@ -2,9 +2,7 @@ package transporter import ( - "context" "net" - "sync" "time" "go.uber.org/zap" @@ -16,134 +14,28 @@ import ( "github.com/Ehco1996/ehco/pkg/lb" ) -type Raw struct { +type RawClient struct { relayLabel string - - // TCP cmgr cmgr.Cmgr tCPRemotes lb.RoundRobin - - // UDP todo refactor udp relay - udpmu sync.Mutex - uDPRemotes lb.RoundRobin - uDPBufferChMap map[string]*BufferCh - - l *zap.SugaredLogger + l *zap.SugaredLogger } -func newRaw( - relayLabel string, - tcpRemotes, udpRemotes lb.RoundRobin, - cmgr cmgr.Cmgr, -) *Raw { - r := &Raw{ - cmgr: cmgr, - - relayLabel: relayLabel, - tCPRemotes: tcpRemotes, - uDPRemotes: udpRemotes, - uDPBufferChMap: make(map[string]*BufferCh), - - l: zap.S().Named(relayLabel), +func newRawClient(relayLabel string, tcpRemotes lb.RoundRobin, cmgr cmgr.Cmgr) *RawClient { + r := &RawClient{ + cmgr: cmgr, + relayLabel: relayLabel, + tCPRemotes: tcpRemotes, + l: zap.S().Named(relayLabel), } return r } -func (raw *Raw) GetOrCreateBufferCh(uaddr *net.UDPAddr) *BufferCh { - raw.udpmu.Lock() - defer raw.udpmu.Unlock() - - bc, found := raw.uDPBufferChMap[uaddr.String()] - if !found { - bc := newudpBufferCh(uaddr) - raw.uDPBufferChMap[uaddr.String()] = bc - return bc - } - return bc -} - -func (raw *Raw) HandleUDPConn(uaddr *net.UDPAddr, local *net.UDPConn) { - remote := raw.uDPRemotes.Next() - metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_UDP).Inc() - defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_UDP).Dec() - - bc := raw.GetOrCreateBufferCh(uaddr) - remoteUdp, _ := net.ResolveUDPAddr("udp", remote.Address) - rc, err := net.DialUDP("udp", nil, remoteUdp) - if err != nil { - raw.l.Error(err) - return - } - defer func() { - rc.Close() - raw.udpmu.Lock() - delete(raw.uDPBufferChMap, uaddr.String()) - raw.udpmu.Unlock() - }() - - raw.l.Infof("HandleUDPConn from %s to %s", local.LocalAddr().String(), remote.Label) - - buf := BufferPool.Get() - defer BufferPool.Put(buf) - - var wg sync.WaitGroup - wg.Add(1) - ctx, cancel := context.WithCancel(context.Background()) - - go func() { - defer wg.Done() - defer cancel() - for { - _ = rc.SetDeadline(time.Now().Add(constant.IdleTimeOut)) - i, err := rc.Read(buf) - if err != nil { - raw.l.Error(err) - break - } - metrics.NetWorkTransmitBytes.WithLabelValues( - remote.Label, metrics.METRIC_CONN_TYPE_UDP, metrics.METRIC_CONN_FLOW_READ, - ).Add(float64(i)) - - if _, err := local.WriteToUDP(buf[0:i], uaddr); err != nil { - raw.l.Error(err) - break - } - metrics.NetWorkTransmitBytes.WithLabelValues( - remote.Label, metrics.METRIC_CONN_TYPE_UDP, metrics.METRIC_CONN_FLOW_WRITE, - ).Add(float64(i)) - } - }() - - wg.Add(1) - go func() { - defer wg.Done() - select { - case <-ctx.Done(): - return - case b := <-bc.Ch: - // read from local udp listener ch - metrics.NetWorkTransmitBytes.WithLabelValues( - remote.Label, metrics.METRIC_CONN_TYPE_UDP, metrics.METRIC_CONN_FLOW_READ, - ).Add(float64(len(b))) - - _ = rc.SetDeadline(time.Now().Add(constant.IdleTimeOut)) - if _, err := rc.Write(b); err != nil { - raw.l.Error(err) - return - } - metrics.NetWorkTransmitBytes.WithLabelValues( - remote.Label, metrics.METRIC_CONN_TYPE_UDP, metrics.METRIC_CONN_FLOW_WRITE, - ).Add(float64(len(b))) - } - }() - wg.Wait() -} - -func (raw *Raw) GetRemote() *lb.Node { +func (raw *RawClient) GetRemote() *lb.Node { return raw.tCPRemotes.Next() } -func (raw *Raw) dialRemote(remote *lb.Node) (net.Conn, error) { +func (raw *RawClient) dialRemote(remote *lb.Node) (net.Conn, error) { t1 := time.Now() d := net.Dialer{Timeout: constant.DialTimeOut} rc, err := d.Dial("tcp", remote.Address) @@ -156,8 +48,7 @@ func (raw *Raw) dialRemote(remote *lb.Node) (net.Conn, error) { return rc, nil } -func (raw *Raw) HandleTCPConn(c net.Conn, remote *lb.Node) error { - // todo refactor metrics to server +func (raw *RawClient) HandleTCPConn(c net.Conn, remote *lb.Node) error { metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Inc() defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Dec() @@ -172,3 +63,44 @@ func (raw *Raw) HandleTCPConn(c net.Conn, remote *lb.Node) error { defer raw.cmgr.RemoveConnection(relayConn) return relayConn.Transport(remote.Label) } + +type RawServer struct { + rtp RelayTransporter + lis *net.TCPListener + l *zap.SugaredLogger +} + +func NewRawServer(addr string, rtp RelayTransporter) (*RawServer, error) { + tcpAddr, err := net.ResolveTCPAddr("tcp", addr) + if err != nil { + return nil, err + } + lis, err := net.ListenTCP("tcp", tcpAddr) + if err != nil { + return nil, err + } + return &RawServer{lis: lis, rtp: rtp}, nil +} + +func (s *RawServer) Close() error { + return s.lis.Close() +} + +func (s *RawServer) ListenAndServe() error { + for { + c, err := s.lis.AcceptTCP() + if err != nil { + return err + } + go func(c net.Conn) { + remote := s.rtp.GetRemote() + metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Inc() + defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Dec() + if err := s.rtp.HandleTCPConn(c, remote); err != nil { + s.l.Errorf("HandleTCPConn meet error tp:%s from:%s to:%s err:%s", + s.rtp, + c.RemoteAddr(), remote.Address, err) + } + }(c) + } +} diff --git a/echo/internal/transporter/mtcp.go b/echo/internal/transporter/raw_mux.go similarity index 84% rename from echo/internal/transporter/mtcp.go rename to echo/internal/transporter/raw_mux.go index c49ee39434..ef1669d5cd 100644 --- a/echo/internal/transporter/mtcp.go +++ b/echo/internal/transporter/raw_mux.go @@ -15,12 +15,37 @@ import ( "github.com/Ehco1996/ehco/pkg/lb" ) -type MTCP struct { - *Raw - mtp *smuxTransporter +type MTCPClient struct { + *RawClient + dialer *net.Dialer + mtp *smuxTransporter } -func (s *MTCP) dialRemote(remote *lb.Node) (net.Conn, error) { +func newMTCPClient(raw *RawClient) *MTCPClient { + dialer := &net.Dialer{Timeout: constant.DialTimeOut} + c := &MTCPClient{dialer: dialer, RawClient: raw} + mtp := NewSmuxTransporter(raw.l.Named("mtcp"), c.initNewSession) + c.mtp = mtp + return c +} + +func (c *MTCPClient) initNewSession(ctx context.Context, addr string) (*smux.Session, error) { + rc, err := c.dialer.Dial("tcp", addr) + if err != nil { + return nil, err + } + // stream multiplex + cfg := smux.DefaultConfig() + cfg.KeepAliveDisabled = true + session, err := smux.Client(rc, cfg) + if err != nil { + return nil, err + } + c.l.Infof("init new session to: %s", rc.RemoteAddr()) + return session, nil +} + +func (s *MTCPClient) dialRemote(remote *lb.Node) (net.Conn, error) { t1 := time.Now() mtcpc, err := s.mtp.Dial(context.TODO(), remote.Address) if err != nil { @@ -32,7 +57,7 @@ func (s *MTCP) dialRemote(remote *lb.Node) (net.Conn, error) { return mtcpc, nil } -func (s *MTCP) HandleTCPConn(c net.Conn, remote *lb.Node) error { +func (s *MTCPClient) HandleTCPConn(c net.Conn, remote *lb.Node) error { clonedRemote := remote.Clone() mtcpc, err := s.dialRemote(clonedRemote) if err != nil { @@ -46,7 +71,7 @@ func (s *MTCP) HandleTCPConn(c net.Conn, remote *lb.Node) error { } type MTCPServer struct { - raw *Raw + raw *RawClient listenAddr string listener net.Listener l *zap.SugaredLogger @@ -55,7 +80,7 @@ type MTCPServer struct { connChan chan net.Conn } -func NewMTCPServer(listenAddr string, raw *Raw, l *zap.SugaredLogger) *MTCPServer { +func NewMTCPServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *MTCPServer { return &MTCPServer{ l: l, raw: raw, @@ -138,28 +163,3 @@ func (s *MTCPServer) ListenAndServe() error { func (s *MTCPServer) Close() error { return s.listener.Close() } - -type MTCPClient struct { - l *zap.SugaredLogger - dialer *net.Dialer -} - -func NewMTCPClient(l *zap.SugaredLogger) *MTCPClient { - return &MTCPClient{l: l, dialer: &net.Dialer{Timeout: constant.DialTimeOut}} -} - -func (c *MTCPClient) InitNewSession(ctx context.Context, addr string) (*smux.Session, error) { - rc, err := c.dialer.Dial("tcp", addr) - if err != nil { - return nil, err - } - // stream multiplex - cfg := smux.DefaultConfig() - cfg.KeepAliveDisabled = true - session, err := smux.Client(rc, cfg) - if err != nil { - return nil, err - } - c.l.Infof("init new session to: %s", rc.RemoteAddr()) - return session, nil -} diff --git a/echo/internal/transporter/ws.go b/echo/internal/transporter/ws.go index 074a608c2b..0b4608ed84 100644 --- a/echo/internal/transporter/ws.go +++ b/echo/internal/transporter/ws.go @@ -7,7 +7,7 @@ import ( "time" "github.com/gobwas/ws" - "github.com/gorilla/mux" + "github.com/labstack/echo/v4" "go.uber.org/zap" "github.com/Ehco1996/ehco/internal/conn" @@ -17,14 +17,18 @@ import ( "github.com/Ehco1996/ehco/pkg/lb" ) -type Ws struct { - *Raw +type WsClient struct { + *RawClient } -func (s *Ws) dialRemote(remote *lb.Node) (net.Conn, error) { +func newWsClient(raw *RawClient) *WsClient { + return &WsClient{RawClient: raw} +} + +func (s *WsClient) dialRemote(remote *lb.Node) (net.Conn, error) { t1 := time.Now() d := ws.Dialer{Timeout: constant.DialTimeOut} - wsc, _, _, err := d.Dial(context.TODO(), remote.Address+"/ws/") + wsc, _, _, err := d.Dial(context.TODO(), remote.Address+"/handshake/") if err != nil { return nil, err } @@ -34,7 +38,7 @@ func (s *Ws) dialRemote(remote *lb.Node) (net.Conn, error) { return wsc, nil } -func (s *Ws) HandleTCPConn(c net.Conn, remote *lb.Node) error { +func (s *WsClient) HandleTCPConn(c net.Conn, remote *lb.Node) error { clonedRemote := remote.Clone() wsc, err := s.dialRemote(clonedRemote) if err != nil { @@ -50,30 +54,32 @@ func (s *Ws) HandleTCPConn(c net.Conn, remote *lb.Node) error { } type WSServer struct { - raw *Raw - l *zap.SugaredLogger + raw *RawClient + e *echo.Echo httpServer *http.Server + l *zap.SugaredLogger } -func NewWSServer(listenAddr string, raw *Raw, l *zap.SugaredLogger) *WSServer { - s := &WSServer{raw: raw, l: l} - mux := mux.NewRouter() - mux.HandleFunc("/", web.MakeIndexF()) - mux.HandleFunc("/ws/", s.HandleRequest) - s.httpServer = &http.Server{ - Addr: listenAddr, - ReadHeaderTimeout: 30 * time.Second, - Handler: mux, +func NewWSServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *WSServer { + s := &WSServer{ + l: l, + raw: raw, + httpServer: &http.Server{Addr: listenAddr, ReadHeaderTimeout: 30 * time.Second}, } + e := web.NewEchoServer() + e.GET("/", echo.WrapHandler(web.MakeIndexF())) + e.GET("/handshake/", echo.WrapHandler(http.HandlerFunc(s.HandleRequest))) + s.e = e + s.httpServer.Handler = e return s } func (s *WSServer) ListenAndServe() error { - return s.httpServer.ListenAndServe() + return s.e.StartServer(s.httpServer) } func (s *WSServer) Close() error { - return s.httpServer.Close() + return s.e.Close() } func (s *WSServer) HandleRequest(w http.ResponseWriter, req *http.Request) { @@ -81,7 +87,6 @@ func (s *WSServer) HandleRequest(w http.ResponseWriter, req *http.Request) { if err != nil { return } - remote := s.raw.GetRemote() if err := s.raw.HandleTCPConn(wsc, remote); err != nil { s.l.Errorf("HandleTCPConn meet error from:%s to:%s err:%s", wsc.RemoteAddr(), remote.Address, err) diff --git a/echo/internal/transporter/wss.go b/echo/internal/transporter/wss.go index 5e7f286c93..a8915ae93c 100644 --- a/echo/internal/transporter/wss.go +++ b/echo/internal/transporter/wss.go @@ -3,31 +3,32 @@ package transporter import ( "context" - "crypto/tls" "net" - "net/http" "time" "github.com/gobwas/ws" - "github.com/gorilla/mux" "go.uber.org/zap" "github.com/Ehco1996/ehco/internal/conn" "github.com/Ehco1996/ehco/internal/metrics" mytls "github.com/Ehco1996/ehco/internal/tls" - "github.com/Ehco1996/ehco/internal/web" "github.com/Ehco1996/ehco/pkg/lb" ) -type Wss struct { - *Raw +type WSSClient struct { + WsClient } -func (s *Wss) dialRemote(remote *lb.Node) (net.Conn, error) { +func newWSSClient(raw *RawClient) *WSSClient { + return &WSSClient{*newWsClient(raw)} +} + +func (s *WSSClient) dialRemote(remote *lb.Node) (net.Conn, error) { t1 := time.Now() d := ws.Dialer{TLSConfig: mytls.DefaultTLSConfig} - wssc, _, _, err := d.Dial(context.TODO(), remote.Address+"/wss/") + wssc, _, _, err := d.Dial(context.TODO(), remote.Address+"/handshake/") if err != nil { + println("wss called", err.Error()) return nil, err } latency := time.Since(t1) @@ -36,7 +37,7 @@ func (s *Wss) dialRemote(remote *lb.Node) (net.Conn, error) { return wssc, nil } -func (s *Wss) HandleTCPConn(c net.Conn, remote *lb.Node) error { +func (s *WSSClient) HandleTCPConn(c net.Conn, remote *lb.Node) error { clonedRemote := remote.Clone() wssc, err := s.dialRemote(clonedRemote) if err != nil { @@ -50,48 +51,14 @@ func (s *Wss) HandleTCPConn(c net.Conn, remote *lb.Node) error { return relayConn.Transport(remote.Label) } -type WSSServer struct { - raw *Raw - l *zap.SugaredLogger - httpServer *http.Server -} +type WSSServer struct{ WSServer } -func NewWSSServer(listenAddr string, raw *Raw, l *zap.SugaredLogger) *WSSServer { - s := &WSSServer{raw: raw, l: l} - mux := mux.NewRouter() - mux.HandleFunc("/", web.MakeIndexF()) - mux.HandleFunc("/wss/", s.HandleRequest) - - s.httpServer = &http.Server{ - Handler: mux, - Addr: listenAddr, - ReadHeaderTimeout: 30 * time.Second, - TLSConfig: mytls.DefaultTLSConfig, - } - return s +func NewWSSServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *WSSServer { + wsServer := NewWSServer(listenAddr, raw, l) + return &WSSServer{WSServer: *wsServer} } func (s *WSSServer) ListenAndServe() error { - lis, err := net.Listen("tcp", s.httpServer.Addr) - if err != nil { - return err - } - defer lis.Close() - return s.httpServer.Serve(tls.NewListener(lis, s.httpServer.TLSConfig)) -} - -func (s *WSSServer) Close() error { - return s.httpServer.Close() -} - -func (s *WSSServer) HandleRequest(w http.ResponseWriter, req *http.Request) { - wsc, _, _, err := ws.UpgradeHTTP(req, w) - if err != nil { - return - } - - remote := s.raw.GetRemote() - if err := s.raw.HandleTCPConn(wsc, remote); err != nil { - s.l.Errorf("HandleTCPConn meet error from:%s to:%s err:%s", wsc.RemoteAddr(), remote.Address, err) - } + s.httpServer.TLSConfig = mytls.DefaultTLSConfig + return s.WSServer.ListenAndServe() } diff --git a/echo/internal/transporter/mwss.go b/echo/internal/transporter/wss_mux.go similarity index 81% rename from echo/internal/transporter/mwss.go rename to echo/internal/transporter/wss_mux.go index f92adade3a..d180c5f2f6 100644 --- a/echo/internal/transporter/mwss.go +++ b/echo/internal/transporter/wss_mux.go @@ -9,7 +9,7 @@ import ( "time" "github.com/gobwas/ws" - "github.com/gorilla/mux" + "github.com/labstack/echo/v4" "github.com/xtaci/smux" "go.uber.org/zap" @@ -21,14 +21,39 @@ import ( "github.com/Ehco1996/ehco/pkg/lb" ) -type Mwss struct { - *Raw - mtp *smuxTransporter +type MWSSClient struct { + *RawClient + dialer *ws.Dialer + mtp *smuxTransporter } -func (s *Mwss) dialRemote(remote *lb.Node) (net.Conn, error) { +func newMWSSClient(raw *RawClient) *MWSSClient { + dialer := &ws.Dialer{TLSConfig: mytls.DefaultTLSConfig, Timeout: constant.DialTimeOut} + c := &MWSSClient{dialer: dialer, RawClient: raw} + mtp := NewSmuxTransporter(raw.l.Named("mwss"), c.initNewSession) + c.mtp = mtp + return c +} + +func (c *MWSSClient) initNewSession(ctx context.Context, addr string) (*smux.Session, error) { + rc, _, _, err := c.dialer.Dial(ctx, addr) + if err != nil { + return nil, err + } + // stream multiplex + cfg := smux.DefaultConfig() + cfg.KeepAliveDisabled = true + session, err := smux.Client(rc, cfg) + if err != nil { + return nil, err + } + c.l.Infof("init new session to: %s", rc.RemoteAddr()) + return session, nil +} + +func (s *MWSSClient) dialRemote(remote *lb.Node) (net.Conn, error) { t1 := time.Now() - mwssc, err := s.mtp.Dial(context.TODO(), remote.Address+"/mwss/") + mwssc, err := s.mtp.Dial(context.TODO(), remote.Address+"/handshake/") if err != nil { return nil, err } @@ -39,7 +64,7 @@ func (s *Mwss) dialRemote(remote *lb.Node) (net.Conn, error) { return mwssc, nil } -func (s *Mwss) HandleTCPConn(c net.Conn, remote *lb.Node) error { +func (s *MWSSClient) HandleTCPConn(c net.Conn, remote *lb.Node) error { clonedRemote := remote.Clone() mwsc, err := s.dialRemote(clonedRemote) if err != nil { @@ -53,7 +78,7 @@ func (s *Mwss) HandleTCPConn(c net.Conn, remote *lb.Node) error { } type MWSSServer struct { - raw *Raw + raw *RawClient httpServer *http.Server l *zap.SugaredLogger @@ -61,7 +86,7 @@ type MWSSServer struct { errChan chan error } -func NewMWSSServer(listenAddr string, raw *Raw, l *zap.SugaredLogger) *MWSSServer { +func NewMWSSServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *MWSSServer { s := &MWSSServer{ raw: raw, l: l, @@ -69,12 +94,12 @@ func NewMWSSServer(listenAddr string, raw *Raw, l *zap.SugaredLogger) *MWSSServe connChan: make(chan net.Conn, 1024), } - mux := mux.NewRouter() - mux.Handle("/", web.MakeIndexF()) - mux.Handle("/mwss/", http.HandlerFunc(s.HandleRequest)) + e := web.NewEchoServer() + e.GET("/", echo.WrapHandler(web.MakeIndexF())) + e.GET("/handshake/", echo.WrapHandler(http.HandlerFunc(s.HandleRequest))) s.httpServer = &http.Server{ Addr: listenAddr, - Handler: mux, + Handler: e, TLSConfig: mytls.DefaultTLSConfig, ReadHeaderTimeout: 30 * time.Second, } @@ -154,32 +179,3 @@ func (s *MWSSServer) Accept() (conn net.Conn, err error) { func (s *MWSSServer) Close() error { return s.httpServer.Close() } - -type MWSSClient struct { - dialer *ws.Dialer - l *zap.SugaredLogger -} - -func NewMWSSClient(l *zap.SugaredLogger) *MWSSClient { - dialer := &ws.Dialer{TLSConfig: mytls.DefaultTLSConfig, Timeout: constant.DialTimeOut} - return &MWSSClient{ - dialer: dialer, - l: l, - } -} - -func (c *MWSSClient) InitNewSession(ctx context.Context, addr string) (*smux.Session, error) { - rc, _, _, err := c.dialer.Dial(ctx, addr) - if err != nil { - return nil, err - } - // stream multiplex - cfg := smux.DefaultConfig() - cfg.KeepAliveDisabled = true - session, err := smux.Client(rc, cfg) - if err != nil { - return nil, err - } - c.l.Infof("init new session to: %s", rc.RemoteAddr()) - return session, nil -} diff --git a/echo/internal/web/server.go b/echo/internal/web/server.go index 598de860c2..60391e1dc2 100644 --- a/echo/internal/web/server.go +++ b/echo/internal/web/server.go @@ -49,10 +49,7 @@ func NewServer(cfg *config.Config, relayReloader reloader.Reloader, connMgr cmgr for _, temp := range templates.Templates() { l.Debug("template name: ", temp.Name()) } - e := echo.New() - e.Debug = true - e.HidePort = true - e.HideBanner = true + e := NewEchoServer() e.Use(NginxLogMiddleware(l)) e.Renderer = &echoTemplate{templates: templates} if cfg.WebToken != "" { diff --git a/echo/internal/web/utils.go b/echo/internal/web/utils.go new file mode 100644 index 0000000000..2e1bfd9fd5 --- /dev/null +++ b/echo/internal/web/utils.go @@ -0,0 +1,11 @@ +package web + +import "github.com/labstack/echo/v4" + +func NewEchoServer() *echo.Echo { + e := echo.New() + e.Debug = true + e.HidePort = true + e.HideBanner = true + return e +} diff --git a/echo/test/relay_test.go b/echo/test/relay_test.go index 0eba3db39e..a01410c4b8 100644 --- a/echo/test/relay_test.go +++ b/echo/test/relay_test.go @@ -148,11 +148,11 @@ func TestRelayOverRaw(t *testing.T) { t.Log("test tcp done!") // test udp - res = echo.SendUdpMsg(msg, RAW_LISTEN) - if string(res) != string(msg) { - t.Fatal(res) - } - t.Log("test udp done!") + // res = echo.SendUdpMsg(msg, RAW_LISTEN) + // if string(res) != string(msg) { + // t.Fatal(res) + // } + // t.Log("test udp done!") } func TestRelayWithDeadline(t *testing.T) { diff --git a/lede/package/kernel/linux/modules/netdevices.mk b/lede/package/kernel/linux/modules/netdevices.mk index 65e44dab8e..203bbdda18 100644 --- a/lede/package/kernel/linux/modules/netdevices.mk +++ b/lede/package/kernel/linux/modules/netdevices.mk @@ -1721,6 +1721,23 @@ endef $(eval $(call KernelPackage,mhi-wwan-mbim)) + +define KernelPackage/mtk-t7xx + SUBMENU:=$(NETWORK_DEVICES_MENU) + TITLE:=MediaTek T7xx 5G modem + DEPENDS:=@(LINUX_6_1||LINUX_6_6) @PCI_SUPPORT +kmod-wwan + KCONFIG:=CONFIG_MTK_T7XX + FILES:=$(LINUX_DIR)/drivers/net/wwan/t7xx/mtk_t7xx.ko + AUTOLOAD:=$(call AutoProbe,mtk_t7xx) +endef + +define KernelPackage/mtk-t7xx/description + Driver for MediaTek PCIe 5G WWAN modem T7xx device +endef + +$(eval $(call KernelPackage,mtk-t7xx)) + + define KernelPackage/atlantic SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Aquantia AQtion 10Gbps Ethernet NIC diff --git a/lede/target/linux/generic/backport-6.1/850-v6.2-bus-mhi-host-pci_generic-add-support-for-sc8280xp-cr.patch b/lede/target/linux/generic/backport-6.1/850-v6.2-bus-mhi-host-pci_generic-add-support-for-sc8280xp-cr.patch new file mode 100644 index 0000000000..1bf5196790 --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/850-v6.2-bus-mhi-host-pci_generic-add-support-for-sc8280xp-cr.patch @@ -0,0 +1,32 @@ +From a38a6e5d2dc41feeaa839cd61196f86c0ee223b8 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Fri, 4 Nov 2022 10:39:13 +0100 +Subject: [PATCH 01/13] bus: mhi: host: pci_generic: add support for + sc8280xp-crd SDX55 variant + +The SC8280XP Compute Reference Design (CRD) has an on-PCB SDX55 modem +which uses MBIM. + +The exact channel configuration is not known but the Foxconn SDX55 +configuration allows the modem to be used so reuse that one for now. + +Signed-off-by: Johan Hovold +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20221104093913.23347-1-johan+linaro@kernel.org +[mani: modified the subject to format "bus: mhi: host"] +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -542,6 +542,8 @@ static const struct mhi_pci_dev_info mhi + static const struct pci_device_id mhi_pci_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info }, ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, PCI_VENDOR_ID_QCOM, 0x010c), ++ .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + /* EM919x (sdx55), use the same vid:pid as qcom-sdx55m */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x18d7, 0x0200), + .driver_data = (kernel_ulong_t) &mhi_sierra_em919x_info }, diff --git a/lede/target/linux/generic/backport-6.1/851-v6.2-bus-mhi-host-pci_generic-Add-HP-variant-of-T99W175.patch b/lede/target/linux/generic/backport-6.1/851-v6.2-bus-mhi-host-pci_generic-Add-HP-variant-of-T99W175.patch new file mode 100644 index 0000000000..0dabc48bfa --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/851-v6.2-bus-mhi-host-pci_generic-Add-HP-variant-of-T99W175.patch @@ -0,0 +1,34 @@ +From 6a150325917a6df9467beeaa6518ab91ada81d97 Mon Sep 17 00:00:00 2001 +From: Song Fuchang +Date: Mon, 7 Nov 2022 19:18:35 +0530 +Subject: [PATCH 02/13] bus: mhi: host: pci_generic: Add HP variant of T99W175 + +The Foxconn T99W175 modem has an HP variant, which has +the following output from lspci: + +01:00.0 Wireless controller [0d40]: Device 03f0:0a6c + +It also has some HP-specific serial numbers on the +metal case. It works well with this driver, so add +support for this to the pci_generic driver. + +Signed-off-by: Song Fuchang +Reviewed-by: Manivannan Sadhasivam +[mani: manually applied the patch] +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -596,6 +596,9 @@ static const struct pci_device_id mhi_pc + /* MV32-WB (Cinterion) */ + { PCI_DEVICE(0x1269, 0x00bb), + .driver_data = (kernel_ulong_t) &mhi_mv32_info }, ++ /* T99W175 (sdx55), HP variant */ ++ { PCI_DEVICE(0x03f0, 0x0a6c), ++ .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + { } + }; + MODULE_DEVICE_TABLE(pci, mhi_pci_id_table); diff --git a/lede/target/linux/generic/backport-6.1/852-v6.2-bus-mhi-host-pci_generic-Add-definition-for-some-VID.patch b/lede/target/linux/generic/backport-6.1/852-v6.2-bus-mhi-host-pci_generic-Add-definition-for-some-VID.patch new file mode 100644 index 0000000000..fbf6c8a501 --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/852-v6.2-bus-mhi-host-pci_generic-Add-definition-for-some-VID.patch @@ -0,0 +1,66 @@ +From e8bc362f158f45185778e2bec081146aeeb283b5 Mon Sep 17 00:00:00 2001 +From: Slark Xiao +Date: Mon, 7 Nov 2022 19:27:00 +0800 +Subject: [PATCH 03/13] bus: mhi: host: pci_generic: Add definition for some + VIDs + +To make code neat and for convenience purpose, add definition for some +VIDs. Adding it locally until these VIDs are used in multiple places. + +Signed-off-by: Slark Xiao +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20221107112700.773-1-slark_xiao@163.com +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -24,6 +24,10 @@ + + #define HEALTH_CHECK_PERIOD (HZ * 2) + ++/* PCI VID definitions */ ++#define PCI_VENDOR_ID_THALES 0x1269 ++#define PCI_VENDOR_ID_QUECTEL 0x1eac ++ + /** + * struct mhi_pci_dev_info - MHI PCI device specific information + * @config: MHI controller configuration +@@ -557,11 +561,11 @@ static const struct pci_device_id mhi_pc + .driver_data = (kernel_ulong_t) &mhi_telit_fn990_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, +- { PCI_DEVICE(0x1eac, 0x1001), /* EM120R-GL (sdx24) */ ++ { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, +- { PCI_DEVICE(0x1eac, 0x1002), /* EM160R-GL (sdx24) */ ++ { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, +- { PCI_DEVICE(0x1eac, 0x2001), /* EM120R-GL for FCCL (sdx24) */ ++ { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x2001), /* EM120R-GL for FCCL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + /* T99W175 (sdx55), Both for eSIM and Non-eSIM */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0ab), +@@ -585,16 +589,16 @@ static const struct pci_device_id mhi_pc + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0d9), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info }, + /* MV31-W (Cinterion) */ +- { PCI_DEVICE(0x1269, 0x00b3), ++ { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b3), + .driver_data = (kernel_ulong_t) &mhi_mv31_info }, + /* MV31-W (Cinterion), based on new baseline */ +- { PCI_DEVICE(0x1269, 0x00b4), ++ { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b4), + .driver_data = (kernel_ulong_t) &mhi_mv31_info }, + /* MV32-WA (Cinterion) */ +- { PCI_DEVICE(0x1269, 0x00ba), ++ { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00ba), + .driver_data = (kernel_ulong_t) &mhi_mv32_info }, + /* MV32-WB (Cinterion) */ +- { PCI_DEVICE(0x1269, 0x00bb), ++ { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00bb), + .driver_data = (kernel_ulong_t) &mhi_mv32_info }, + /* T99W175 (sdx55), HP variant */ + { PCI_DEVICE(0x03f0, 0x0a6c), diff --git a/lede/target/linux/generic/backport-6.1/853-v6.2-bus-mhi-host-pci_generic-Drop-redundant-pci_enable_p.patch b/lede/target/linux/generic/backport-6.1/853-v6.2-bus-mhi-host-pci_generic-Drop-redundant-pci_enable_p.patch new file mode 100644 index 0000000000..2f5a0ac11d --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/853-v6.2-bus-mhi-host-pci_generic-Drop-redundant-pci_enable_p.patch @@ -0,0 +1,68 @@ +From 6c00e1e4e9817e85b8ba83024cfa88382f898841 Mon Sep 17 00:00:00 2001 +From: Bjorn Helgaas +Date: Tue, 7 Mar 2023 14:16:25 -0600 +Subject: [PATCH 04/13] bus: mhi: host: pci_generic: Drop redundant + pci_enable_pcie_error_reporting() + +pci_enable_pcie_error_reporting() enables the device to send ERR_* +Messages. Since commit ("PCI/AER: Enable error reporting +when AER is native"), the PCI core does this for all devices during +enumeration, so the driver doesn't need to do it itself. + +Remove the redundant pci_enable_pcie_error_reporting() call from the +driver. Also remove the corresponding pci_disable_pcie_error_reporting() +from the driver .remove() path. + +Note that this only controls ERR_* Messages from the device. An ERR_* +Message may cause the Root Port to generate an interrupt, depending on the +AER Root Error Command register managed by the AER service driver. + +Signed-off-by: Bjorn Helgaas +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Jeffrey Hugo +Link: https://lore.kernel.org/r/20230307201625.879567-1-helgaas@kernel.org +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -8,7 +8,6 @@ + * Copyright (C) 2020 Linaro Ltd + */ + +-#include + #include + #include + #include +@@ -901,11 +900,9 @@ static int mhi_pci_probe(struct pci_dev + mhi_pdev->pci_state = pci_store_saved_state(pdev); + pci_load_saved_state(pdev, NULL); + +- pci_enable_pcie_error_reporting(pdev); +- + err = mhi_register_controller(mhi_cntrl, mhi_cntrl_config); + if (err) +- goto err_disable_reporting; ++ return err; + + /* MHI bus does not power up the controller by default */ + err = mhi_prepare_for_power_up(mhi_cntrl); +@@ -939,8 +936,6 @@ err_unprepare: + mhi_unprepare_after_power_down(mhi_cntrl); + err_unregister: + mhi_unregister_controller(mhi_cntrl); +-err_disable_reporting: +- pci_disable_pcie_error_reporting(pdev); + + return err; + } +@@ -963,7 +958,6 @@ static void mhi_pci_remove(struct pci_de + pm_runtime_get_noresume(&pdev->dev); + + mhi_unregister_controller(mhi_cntrl); +- pci_disable_pcie_error_reporting(pdev); + } + + static void mhi_pci_shutdown(struct pci_dev *pdev) diff --git a/lede/target/linux/generic/backport-6.1/854-v6.4-bus-mhi-pci_generic-Add-Foxconn-T99W510.patch b/lede/target/linux/generic/backport-6.1/854-v6.4-bus-mhi-pci_generic-Add-Foxconn-T99W510.patch new file mode 100644 index 0000000000..f757ca28e5 --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/854-v6.4-bus-mhi-pci_generic-Add-Foxconn-T99W510.patch @@ -0,0 +1,49 @@ +From 537350abfcc6b639884d1ef7bff35d31a624549b Mon Sep 17 00:00:00 2001 +From: Slark Xiao +Date: Wed, 29 Mar 2023 15:22:39 +0800 +Subject: [PATCH 05/13] bus: mhi: pci_generic: Add Foxconn T99W510 + +The Foxconn T99W510 device is designed based on Qualcomm +SDX24. Add 3 variants for different potential customer. + +Signed-off-by: Slark Xiao +Link: https://lore.kernel.org/r/20230329072239.93632-1-slark_xiao@163.com +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -363,6 +363,15 @@ static const struct mhi_controller_confi + .event_cfg = mhi_foxconn_sdx55_events, + }; + ++static const struct mhi_pci_dev_info mhi_foxconn_sdx24_info = { ++ .name = "foxconn-sdx24", ++ .config = &modem_foxconn_sdx55_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .mru_default = 32768, ++ .sideband_wake = false, ++}; ++ + static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = { + .name = "foxconn-sdx55", + .fw = "qcom/sdx55m/sbl1.mbn", +@@ -587,6 +596,15 @@ static const struct pci_device_id mhi_pc + /* T99W373 (sdx62) */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0d9), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info }, ++ /* T99W510 (sdx24), variant 1 */ ++ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f0), ++ .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info }, ++ /* T99W510 (sdx24), variant 2 */ ++ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f1), ++ .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info }, ++ /* T99W510 (sdx24), variant 3 */ ++ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f2), ++ .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info }, + /* MV31-W (Cinterion) */ + { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b3), + .driver_data = (kernel_ulong_t) &mhi_mv31_info }, diff --git a/lede/target/linux/generic/backport-6.1/855-v6.6-bus-mhi-host-pci_generic-Add-support-for-IP_SW0-chan.patch b/lede/target/linux/generic/backport-6.1/855-v6.6-bus-mhi-host-pci_generic-Add-support-for-IP_SW0-chan.patch new file mode 100644 index 0000000000..8c319ebeb7 --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/855-v6.6-bus-mhi-host-pci_generic-Add-support-for-IP_SW0-chan.patch @@ -0,0 +1,67 @@ +From 440b01a2a9a62352cfa355354d3a4de6c5d96adf Mon Sep 17 00:00:00 2001 +From: Manivannan Sadhasivam +Date: Fri, 19 May 2023 19:28:03 +0530 +Subject: [PATCH 06/13] bus: mhi: host: pci_generic: Add support for IP_SW0 + channels + +IP_SW0 channels are used to transfer data over the networking interface +between MHI endpoint and the host. Define the channels in the MHI v1 +channel config along with dedicated event rings. + +Reviewed-by: Loic Poulain +Link: https://lore.kernel.org/r/20230519135803.13850-1-manivannan.sadhasivam@linaro.org +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -212,6 +212,19 @@ struct mhi_pci_dev_info { + .offload_channel = false, \ + } + ++#define MHI_EVENT_CONFIG_SW_DATA(ev_ring, el_count) \ ++ { \ ++ .num_elements = el_count, \ ++ .irq_moderation_ms = 0, \ ++ .irq = (ev_ring) + 1, \ ++ .priority = 1, \ ++ .mode = MHI_DB_BRST_DISABLE, \ ++ .data_type = MHI_ER_DATA, \ ++ .hardware_event = false, \ ++ .client_managed = false, \ ++ .offload_channel = false, \ ++ } ++ + #define MHI_EVENT_CONFIG_HW_DATA(ev_ring, el_count, ch_num) \ + { \ + .num_elements = el_count, \ +@@ -237,8 +250,10 @@ static const struct mhi_channel_config m + MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 8, 0), + MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0), + MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0), +- MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2), +- MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3), ++ MHI_CHANNEL_CONFIG_UL(46, "IP_SW0", 64, 2), ++ MHI_CHANNEL_CONFIG_DL(47, "IP_SW0", 64, 3), ++ MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 4), ++ MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 5), + }; + + static struct mhi_event_config modem_qcom_v1_mhi_events[] = { +@@ -246,9 +261,12 @@ static struct mhi_event_config modem_qco + MHI_EVENT_CONFIG_CTRL(0, 64), + /* DIAG dedicated event ring */ + MHI_EVENT_CONFIG_DATA(1, 128), ++ /* Software channels dedicated event ring */ ++ MHI_EVENT_CONFIG_SW_DATA(2, 64), ++ MHI_EVENT_CONFIG_SW_DATA(3, 64), + /* Hardware channels request dedicated hardware event rings */ +- MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100), +- MHI_EVENT_CONFIG_HW_DATA(3, 2048, 101) ++ MHI_EVENT_CONFIG_HW_DATA(4, 1024, 100), ++ MHI_EVENT_CONFIG_HW_DATA(5, 2048, 101) + }; + + static const struct mhi_controller_config modem_qcom_v1_mhiv_config = { diff --git a/lede/target/linux/generic/backport-6.1/856-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-EM1.patch b/lede/target/linux/generic/backport-6.1/856-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-EM1.patch new file mode 100644 index 0000000000..5c15eec712 --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/856-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-EM1.patch @@ -0,0 +1,34 @@ +From 2dc36ddb6ca4eeda21204dc9e57750494c74c06d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Duke=20Xin=20=28=E8=BE=9B=E5=AE=89=E6=96=87=29?= + +Date: Thu, 8 Jun 2023 02:29:27 -0700 +Subject: [PATCH 07/13] bus: mhi: host: pci_generic: Add support for Quectel + EM160R-GL modem +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This modem is identical to the previous EM160R-GL modem with same product +name. But this one is designed for a specific laptop usecase, hence Quectel +got a new PID. + +Signed-off-by: Duke Xin(辛安文) +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20230608092927.2893-1-duke_xinanwen@163.com +[mani: modified the commit message and subject] +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -591,6 +591,8 @@ static const struct pci_device_id mhi_pc + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, ++ { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x100d), /* EM160R-GL (sdx24) */ ++ .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x2001), /* EM120R-GL for FCCL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + /* T99W175 (sdx55), Both for eSIM and Non-eSIM */ diff --git a/lede/target/linux/generic/backport-6.1/857-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-RM5.patch b/lede/target/linux/generic/backport-6.1/857-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-RM5.patch new file mode 100644 index 0000000000..5922207e29 --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/857-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-RM5.patch @@ -0,0 +1,49 @@ +From 7e2f6cb11c24799b6851142c4a5ce69bdc630364 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Duke=20Xin=20=28=E8=BE=9B=E5=AE=89=E6=96=87=29?= + +Date: Thu, 29 Jun 2023 23:23:18 -0700 +Subject: [PATCH 08/13] bus: mhi: host: pci_generic: Add support for Quectel + RM520N-GL modem +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add MHI interface definition for RM520 product based on Qualcomm SDX6X chip + +Signed-off-by: Duke Xin(辛安文) +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20230630062318.12114-1-duke_xinanwen@163.com +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -352,6 +352,16 @@ static const struct mhi_pci_dev_info mhi + .sideband_wake = true, + }; + ++static const struct mhi_pci_dev_info mhi_quectel_rm5xx_info = { ++ .name = "quectel-rm5xx", ++ .edl = "qcom/prog_firehose_sdx6x.elf", ++ .config = &modem_quectel_em1xx_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .mru_default = 32768, ++ .sideband_wake = true, ++}; ++ + static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = { + MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 32, 0), + MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 32, 0), +@@ -591,6 +601,9 @@ static const struct pci_device_id mhi_pc + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, ++ /* RM520N-GL (sdx6x), eSIM */ ++ { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1004), ++ .driver_data = (kernel_ulong_t) &mhi_quectel_rm5xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x100d), /* EM160R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x2001), /* EM120R-GL for FCCL (sdx24) */ diff --git a/lede/target/linux/generic/backport-6.1/858-v6.6-bus-mhi-host-pci_generic-Add-support-for-Dell-DW5932.patch b/lede/target/linux/generic/backport-6.1/858-v6.6-bus-mhi-host-pci_generic-Add-support-for-Dell-DW5932.patch new file mode 100644 index 0000000000..bb7b3c3ffc --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/858-v6.6-bus-mhi-host-pci_generic-Add-support-for-Dell-DW5932.patch @@ -0,0 +1,34 @@ +From 5e20ac8e7d3221e079e87066c4e8f4b64bd58ccb Mon Sep 17 00:00:00 2001 +From: Slark Xiao +Date: Wed, 12 Jul 2023 16:37:41 +0800 +Subject: [PATCH 09/13] bus: mhi: host: pci_generic: Add support for Dell + DW5932e + +The DW5932e has 2 variants: eSIM(DW5932e-eSIM) and non-eSIM(DW5932e). +Both of them are designed based on Qualcomm SDX62 and it will +align with the Foxconn sdx65 settings. + +Signed-off-by: Slark Xiao +Reviewed-by: Loic Poulain +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20230712083741.7615-1-slark_xiao@163.com +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -638,6 +638,12 @@ static const struct pci_device_id mhi_pc + /* T99W510 (sdx24), variant 3 */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f2), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info }, ++ /* DW5932e-eSIM (sdx62), With eSIM */ ++ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f5), ++ .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info }, ++ /* DW5932e (sdx62), Non-eSIM */ ++ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f9), ++ .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info }, + /* MV31-W (Cinterion) */ + { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b3), + .driver_data = (kernel_ulong_t) &mhi_mv31_info }, diff --git a/lede/target/linux/generic/backport-6.1/859-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-RM5.patch b/lede/target/linux/generic/backport-6.1/859-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-RM5.patch new file mode 100644 index 0000000000..c0dfe01e32 --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/859-v6.6-bus-mhi-host-pci_generic-Add-support-for-Quectel-RM5.patch @@ -0,0 +1,36 @@ +From 8be9e92a2c8f26fd7482acc2323c6dc2a4ad43aa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Duke=20Xin=20=28=E8=BE=9B=E5=AE=89=E6=96=87=29?= + +Date: Sun, 6 Aug 2023 20:04:54 -0700 +Subject: [PATCH 10/13] bus: mhi: host: pci_generic: Add support for Quectel + RM520N-GL Lenovo variant +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Quectel's RM520N-GL Lenovo variant is same as that of the existing +RM520N-GL modem and uses the same config. But this one is designed for +Lenovo laptop usecase, hence Quectel got a new PID. + +Signed-off-by: Duke Xin(辛安文) +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Loic Poulain +Link: https://lore.kernel.org/r/20230807030454.37255-1-duke_xinanwen@163.com +[mani: tweaked subject and commit message a bit] +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -604,6 +604,9 @@ static const struct pci_device_id mhi_pc + /* RM520N-GL (sdx6x), eSIM */ + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1004), + .driver_data = (kernel_ulong_t) &mhi_quectel_rm5xx_info }, ++ /* RM520N-GL (sdx6x), Lenovo variant */ ++ { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1007), ++ .driver_data = (kernel_ulong_t) &mhi_quectel_rm5xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x100d), /* EM160R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x2001), /* EM120R-GL for FCCL (sdx24) */ diff --git a/lede/target/linux/generic/backport-6.1/860-v6.6-bus-mhi-host-pci_generic-add-support-for-Telit-FE990.patch b/lede/target/linux/generic/backport-6.1/860-v6.6-bus-mhi-host-pci_generic-add-support-for-Telit-FE990.patch new file mode 100644 index 0000000000..40fdfc613b --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/860-v6.6-bus-mhi-host-pci_generic-add-support-for-Telit-FE990.patch @@ -0,0 +1,33 @@ +From 30001cf3a19a2f676a0e23c2c3a511c4a8903284 Mon Sep 17 00:00:00 2001 +From: Daniele Palmas +Date: Fri, 4 Aug 2023 11:40:39 +0200 +Subject: [PATCH 11/13] bus: mhi: host: pci_generic: add support for Telit + FE990 modem + +Add support for Telit FE990 that has the same configuration as FN990: + +$ lspci -vv +04:00.0 Unassigned class [ff00]: Qualcomm Device 0308 + Subsystem: Device 1c5d:2015 + +Signed-off-by: Daniele Palmas +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20230804094039.365102-1-dnlplm@gmail.com +[mani: minor update to commit subject and adjusted comment] +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -595,6 +595,9 @@ static const struct pci_device_id mhi_pc + /* Telit FN990 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x1c5d, 0x2010), + .driver_data = (kernel_ulong_t) &mhi_telit_fn990_info }, ++ /* Telit FE990 */ ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x1c5d, 0x2015), ++ .driver_data = (kernel_ulong_t) &mhi_telit_fn990_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */ diff --git a/lede/target/linux/generic/backport-6.1/861-v6.8-bus-mhi-host-Add-a-separate-timeout-parameter-for-wa.patch b/lede/target/linux/generic/backport-6.1/861-v6.8-bus-mhi-host-Add-a-separate-timeout-parameter-for-wa.patch new file mode 100644 index 0000000000..2b83d0396a --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/861-v6.8-bus-mhi-host-Add-a-separate-timeout-parameter-for-wa.patch @@ -0,0 +1,175 @@ +From 6ab3d50b106c9aea123a80551a6c9deace83b914 Mon Sep 17 00:00:00 2001 +From: Qiang Yu +Date: Tue, 7 Nov 2023 16:14:49 +0800 +Subject: [PATCH] bus: mhi: host: Add a separate timeout parameter for waiting + ready + +Some devices(eg. SDX75) take longer than expected (default, 8 seconds) to +set ready after reboot. Hence add optional ready timeout parameter and pass +the appropriate timeout value to mhi_poll_reg_field() to wait enough for +device ready as part of power up sequence. + +Signed-off-by: Qiang Yu +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1699344890-87076-2-git-send-email-quic_qianyu@quicinc.com +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/init.c | 1 + + drivers/bus/mhi/host/internal.h | 2 +- + drivers/bus/mhi/host/main.c | 5 +++-- + drivers/bus/mhi/host/pm.c | 24 +++++++++++++++++------- + include/linux/mhi.h | 4 ++++ + 5 files changed, 26 insertions(+), 10 deletions(-) + +--- a/drivers/bus/mhi/host/init.c ++++ b/drivers/bus/mhi/host/init.c +@@ -881,6 +881,7 @@ static int parse_config(struct mhi_contr + if (!mhi_cntrl->timeout_ms) + mhi_cntrl->timeout_ms = MHI_TIMEOUT_MS; + ++ mhi_cntrl->ready_timeout_ms = config->ready_timeout_ms; + mhi_cntrl->bounce_buf = config->use_bounce_buf; + mhi_cntrl->buffer_len = config->buf_len; + if (!mhi_cntrl->buffer_len) +--- a/drivers/bus/mhi/host/internal.h ++++ b/drivers/bus/mhi/host/internal.h +@@ -321,7 +321,7 @@ int __must_check mhi_read_reg_field(stru + u32 *out); + int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl, + void __iomem *base, u32 offset, u32 mask, +- u32 val, u32 delayus); ++ u32 val, u32 delayus, u32 timeout_ms); + void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base, + u32 offset, u32 val); + int __must_check mhi_write_reg_field(struct mhi_controller *mhi_cntrl, +--- a/drivers/bus/mhi/host/main.c ++++ b/drivers/bus/mhi/host/main.c +@@ -40,10 +40,11 @@ int __must_check mhi_read_reg_field(stru + + int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl, + void __iomem *base, u32 offset, +- u32 mask, u32 val, u32 delayus) ++ u32 mask, u32 val, u32 delayus, ++ u32 timeout_ms) + { + int ret; +- u32 out, retry = (mhi_cntrl->timeout_ms * 1000) / delayus; ++ u32 out, retry = (timeout_ms * 1000) / delayus; + + while (retry--) { + ret = mhi_read_reg_field(mhi_cntrl, base, offset, mask, &out); +--- a/drivers/bus/mhi/host/pm.c ++++ b/drivers/bus/mhi/host/pm.c +@@ -163,6 +163,7 @@ int mhi_ready_state_transition(struct mh + enum mhi_pm_state cur_state; + struct device *dev = &mhi_cntrl->mhi_dev->dev; + u32 interval_us = 25000; /* poll register field every 25 milliseconds */ ++ u32 timeout_ms; + int ret, i; + + /* Check if device entered error state */ +@@ -173,14 +174,18 @@ int mhi_ready_state_transition(struct mh + + /* Wait for RESET to be cleared and READY bit to be set by the device */ + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, +- MHICTRL_RESET_MASK, 0, interval_us); ++ MHICTRL_RESET_MASK, 0, interval_us, ++ mhi_cntrl->timeout_ms); + if (ret) { + dev_err(dev, "Device failed to clear MHI Reset\n"); + return ret; + } + ++ timeout_ms = mhi_cntrl->ready_timeout_ms ? ++ mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms; + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHISTATUS, +- MHISTATUS_READY_MASK, 1, interval_us); ++ MHISTATUS_READY_MASK, 1, interval_us, ++ timeout_ms); + if (ret) { + dev_err(dev, "Device failed to enter MHI Ready\n"); + return ret; +@@ -479,7 +484,7 @@ static void mhi_pm_disable_transition(st + + /* Wait for the reset bit to be cleared by the device */ + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, +- MHICTRL_RESET_MASK, 0, 25000); ++ MHICTRL_RESET_MASK, 0, 25000, mhi_cntrl->timeout_ms); + if (ret) + dev_err(dev, "Device failed to clear MHI Reset\n"); + +@@ -492,8 +497,8 @@ static void mhi_pm_disable_transition(st + if (!MHI_IN_PBL(mhi_get_exec_env(mhi_cntrl))) { + /* wait for ready to be set */ + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, +- MHISTATUS, +- MHISTATUS_READY_MASK, 1, 25000); ++ MHISTATUS, MHISTATUS_READY_MASK, ++ 1, 25000, mhi_cntrl->timeout_ms); + if (ret) + dev_err(dev, "Device failed to enter READY state\n"); + } +@@ -1111,7 +1116,8 @@ int mhi_async_power_up(struct mhi_contro + if (state == MHI_STATE_SYS_ERR) { + mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET); + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, +- MHICTRL_RESET_MASK, 0, interval_us); ++ MHICTRL_RESET_MASK, 0, interval_us, ++ mhi_cntrl->timeout_ms); + if (ret) { + dev_info(dev, "Failed to reset MHI due to syserr state\n"); + goto error_exit; +@@ -1202,14 +1208,18 @@ EXPORT_SYMBOL_GPL(mhi_power_down); + int mhi_sync_power_up(struct mhi_controller *mhi_cntrl) + { + int ret = mhi_async_power_up(mhi_cntrl); ++ u32 timeout_ms; + + if (ret) + return ret; + ++ /* Some devices need more time to set ready during power up */ ++ timeout_ms = mhi_cntrl->ready_timeout_ms ? ++ mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms; + wait_event_timeout(mhi_cntrl->state_event, + MHI_IN_MISSION_MODE(mhi_cntrl->ee) || + MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), +- msecs_to_jiffies(mhi_cntrl->timeout_ms)); ++ msecs_to_jiffies(timeout_ms)); + + ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT; + if (ret) +--- a/include/linux/mhi.h ++++ b/include/linux/mhi.h +@@ -266,6 +266,7 @@ struct mhi_event_config { + * struct mhi_controller_config - Root MHI controller configuration + * @max_channels: Maximum number of channels supported + * @timeout_ms: Timeout value for operations. 0 means use default ++ * @ready_timeout_ms: Timeout value for waiting device to be ready (optional) + * @buf_len: Size of automatically allocated buffers. 0 means use default + * @num_channels: Number of channels defined in @ch_cfg + * @ch_cfg: Array of defined channels +@@ -277,6 +278,7 @@ struct mhi_event_config { + struct mhi_controller_config { + u32 max_channels; + u32 timeout_ms; ++ u32 ready_timeout_ms; + u32 buf_len; + u32 num_channels; + const struct mhi_channel_config *ch_cfg; +@@ -326,6 +328,7 @@ struct mhi_controller_config { + * @pm_mutex: Mutex for suspend/resume operation + * @pm_lock: Lock for protecting MHI power management state + * @timeout_ms: Timeout in ms for state transitions ++ * @ready_timeout_ms: Timeout in ms for waiting device to be ready (optional) + * @pm_state: MHI power management state + * @db_access: DB access states + * @ee: MHI device execution environment +@@ -413,6 +416,7 @@ struct mhi_controller { + struct mutex pm_mutex; + rwlock_t pm_lock; + u32 timeout_ms; ++ u32 ready_timeout_ms; + u32 pm_state; + u32 db_access; + enum mhi_ee_type ee; diff --git a/lede/target/linux/generic/backport-6.1/862-v6.8-bus-mhi-host-pci_generic-Add-SDX75-based-modem-suppo.patch b/lede/target/linux/generic/backport-6.1/862-v6.8-bus-mhi-host-pci_generic-Add-SDX75-based-modem-suppo.patch new file mode 100644 index 0000000000..944747ac56 --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/862-v6.8-bus-mhi-host-pci_generic-Add-SDX75-based-modem-suppo.patch @@ -0,0 +1,62 @@ +From b2f401efbff8878be31b2bce6e8d7bdad23e6f12 Mon Sep 17 00:00:00 2001 +From: Qiang Yu +Date: Tue, 7 Nov 2023 16:14:50 +0800 +Subject: [PATCH 12/13] bus: mhi: host: pci_generic: Add SDX75 based modem + support + +Add generic info for SDX75 based modems. SDX75 takes longer to set ready +during power up. Hence use separate configuration. + +Signed-off-by: Qiang Yu +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1699344890-87076-3-git-send-email-quic_qianyu@quicinc.com +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -269,6 +269,16 @@ static struct mhi_event_config modem_qco + MHI_EVENT_CONFIG_HW_DATA(5, 2048, 101) + }; + ++static const struct mhi_controller_config modem_qcom_v2_mhiv_config = { ++ .max_channels = 128, ++ .timeout_ms = 8000, ++ .ready_timeout_ms = 50000, ++ .num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels), ++ .ch_cfg = modem_qcom_v1_mhi_channels, ++ .num_events = ARRAY_SIZE(modem_qcom_v1_mhi_events), ++ .event_cfg = modem_qcom_v1_mhi_events, ++}; ++ + static const struct mhi_controller_config modem_qcom_v1_mhiv_config = { + .max_channels = 128, + .timeout_ms = 8000, +@@ -278,6 +288,16 @@ static const struct mhi_controller_confi + .event_cfg = modem_qcom_v1_mhi_events, + }; + ++static const struct mhi_pci_dev_info mhi_qcom_sdx75_info = { ++ .name = "qcom-sdx75m", ++ .fw = "qcom/sdx75m/xbl.elf", ++ .edl = "qcom/sdx75m/edl.mbn", ++ .config = &modem_qcom_v2_mhiv_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .sideband_wake = false, ++}; ++ + static const struct mhi_pci_dev_info mhi_qcom_sdx65_info = { + .name = "qcom-sdx65m", + .fw = "qcom/sdx65m/xbl.elf", +@@ -600,6 +620,8 @@ static const struct pci_device_id mhi_pc + .driver_data = (kernel_ulong_t) &mhi_telit_fn990_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, ++ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0309), ++ .driver_data = (kernel_ulong_t) &mhi_qcom_sdx75_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */ diff --git a/lede/target/linux/generic/backport-6.1/863-stable-bus-mhi-host-pci_generic-constify-modem_telit_fn980_.patch b/lede/target/linux/generic/backport-6.1/863-stable-bus-mhi-host-pci_generic-constify-modem_telit_fn980_.patch new file mode 100644 index 0000000000..085e8862ae --- /dev/null +++ b/lede/target/linux/generic/backport-6.1/863-stable-bus-mhi-host-pci_generic-constify-modem_telit_fn980_.patch @@ -0,0 +1,28 @@ +From 5f157aa89b876e82d6aafb2d009979118d0bdd2b Mon Sep 17 00:00:00 2001 +From: Jeff Johnson +Date: Thu, 22 Feb 2024 18:00:23 -0800 +Subject: [PATCH 13/13] bus: mhi: host: pci_generic: constify + modem_telit_fn980_hw_v1_config + +MHI expects the controller configs to be const, and all of the other ones +in this file already are, so constify modem_telit_fn980_hw_v1_config. + +Signed-off-by: Jeff Johnson +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20240222-mhi-const-bus-mhi-host-pci_generic-v1-1-d4c9b0b0a7a5@quicinc.com +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -538,7 +538,7 @@ static struct mhi_event_config mhi_telit + MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101) + }; + +-static struct mhi_controller_config modem_telit_fn980_hw_v1_config = { ++static const struct mhi_controller_config modem_telit_fn980_hw_v1_config = { + .max_channels = 128, + .timeout_ms = 20000, + .num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels), diff --git a/lede/target/linux/generic/backport-6.6/850-v6.8-bus-mhi-host-Add-a-separate-timeout-parameter-for-wa.patch b/lede/target/linux/generic/backport-6.6/850-v6.8-bus-mhi-host-Add-a-separate-timeout-parameter-for-wa.patch new file mode 100644 index 0000000000..23f20ed65e --- /dev/null +++ b/lede/target/linux/generic/backport-6.6/850-v6.8-bus-mhi-host-Add-a-separate-timeout-parameter-for-wa.patch @@ -0,0 +1,175 @@ +From 6ab3d50b106c9aea123a80551a6c9deace83b914 Mon Sep 17 00:00:00 2001 +From: Qiang Yu +Date: Tue, 7 Nov 2023 16:14:49 +0800 +Subject: [PATCH] bus: mhi: host: Add a separate timeout parameter for waiting + ready + +Some devices(eg. SDX75) take longer than expected (default, 8 seconds) to +set ready after reboot. Hence add optional ready timeout parameter and pass +the appropriate timeout value to mhi_poll_reg_field() to wait enough for +device ready as part of power up sequence. + +Signed-off-by: Qiang Yu +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1699344890-87076-2-git-send-email-quic_qianyu@quicinc.com +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/init.c | 1 + + drivers/bus/mhi/host/internal.h | 2 +- + drivers/bus/mhi/host/main.c | 5 +++-- + drivers/bus/mhi/host/pm.c | 24 +++++++++++++++++------- + include/linux/mhi.h | 4 ++++ + 5 files changed, 26 insertions(+), 10 deletions(-) + +--- a/drivers/bus/mhi/host/init.c ++++ b/drivers/bus/mhi/host/init.c +@@ -881,6 +881,7 @@ static int parse_config(struct mhi_contr + if (!mhi_cntrl->timeout_ms) + mhi_cntrl->timeout_ms = MHI_TIMEOUT_MS; + ++ mhi_cntrl->ready_timeout_ms = config->ready_timeout_ms; + mhi_cntrl->bounce_buf = config->use_bounce_buf; + mhi_cntrl->buffer_len = config->buf_len; + if (!mhi_cntrl->buffer_len) +--- a/drivers/bus/mhi/host/internal.h ++++ b/drivers/bus/mhi/host/internal.h +@@ -321,7 +321,7 @@ int __must_check mhi_read_reg_field(stru + u32 *out); + int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl, + void __iomem *base, u32 offset, u32 mask, +- u32 val, u32 delayus); ++ u32 val, u32 delayus, u32 timeout_ms); + void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base, + u32 offset, u32 val); + int __must_check mhi_write_reg_field(struct mhi_controller *mhi_cntrl, +--- a/drivers/bus/mhi/host/main.c ++++ b/drivers/bus/mhi/host/main.c +@@ -40,10 +40,11 @@ int __must_check mhi_read_reg_field(stru + + int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl, + void __iomem *base, u32 offset, +- u32 mask, u32 val, u32 delayus) ++ u32 mask, u32 val, u32 delayus, ++ u32 timeout_ms) + { + int ret; +- u32 out, retry = (mhi_cntrl->timeout_ms * 1000) / delayus; ++ u32 out, retry = (timeout_ms * 1000) / delayus; + + while (retry--) { + ret = mhi_read_reg_field(mhi_cntrl, base, offset, mask, &out); +--- a/drivers/bus/mhi/host/pm.c ++++ b/drivers/bus/mhi/host/pm.c +@@ -163,6 +163,7 @@ int mhi_ready_state_transition(struct mh + enum mhi_pm_state cur_state; + struct device *dev = &mhi_cntrl->mhi_dev->dev; + u32 interval_us = 25000; /* poll register field every 25 milliseconds */ ++ u32 timeout_ms; + int ret, i; + + /* Check if device entered error state */ +@@ -173,14 +174,18 @@ int mhi_ready_state_transition(struct mh + + /* Wait for RESET to be cleared and READY bit to be set by the device */ + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, +- MHICTRL_RESET_MASK, 0, interval_us); ++ MHICTRL_RESET_MASK, 0, interval_us, ++ mhi_cntrl->timeout_ms); + if (ret) { + dev_err(dev, "Device failed to clear MHI Reset\n"); + return ret; + } + ++ timeout_ms = mhi_cntrl->ready_timeout_ms ? ++ mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms; + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHISTATUS, +- MHISTATUS_READY_MASK, 1, interval_us); ++ MHISTATUS_READY_MASK, 1, interval_us, ++ timeout_ms); + if (ret) { + dev_err(dev, "Device failed to enter MHI Ready\n"); + return ret; +@@ -479,7 +484,7 @@ static void mhi_pm_disable_transition(st + + /* Wait for the reset bit to be cleared by the device */ + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, +- MHICTRL_RESET_MASK, 0, 25000); ++ MHICTRL_RESET_MASK, 0, 25000, mhi_cntrl->timeout_ms); + if (ret) + dev_err(dev, "Device failed to clear MHI Reset\n"); + +@@ -492,8 +497,8 @@ static void mhi_pm_disable_transition(st + if (!MHI_IN_PBL(mhi_get_exec_env(mhi_cntrl))) { + /* wait for ready to be set */ + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, +- MHISTATUS, +- MHISTATUS_READY_MASK, 1, 25000); ++ MHISTATUS, MHISTATUS_READY_MASK, ++ 1, 25000, mhi_cntrl->timeout_ms); + if (ret) + dev_err(dev, "Device failed to enter READY state\n"); + } +@@ -1111,7 +1116,8 @@ int mhi_async_power_up(struct mhi_contro + if (state == MHI_STATE_SYS_ERR) { + mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET); + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, +- MHICTRL_RESET_MASK, 0, interval_us); ++ MHICTRL_RESET_MASK, 0, interval_us, ++ mhi_cntrl->timeout_ms); + if (ret) { + dev_info(dev, "Failed to reset MHI due to syserr state\n"); + goto error_exit; +@@ -1202,14 +1208,18 @@ EXPORT_SYMBOL_GPL(mhi_power_down); + int mhi_sync_power_up(struct mhi_controller *mhi_cntrl) + { + int ret = mhi_async_power_up(mhi_cntrl); ++ u32 timeout_ms; + + if (ret) + return ret; + ++ /* Some devices need more time to set ready during power up */ ++ timeout_ms = mhi_cntrl->ready_timeout_ms ? ++ mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms; + wait_event_timeout(mhi_cntrl->state_event, + MHI_IN_MISSION_MODE(mhi_cntrl->ee) || + MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), +- msecs_to_jiffies(mhi_cntrl->timeout_ms)); ++ msecs_to_jiffies(timeout_ms)); + + ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT; + if (ret) +--- a/include/linux/mhi.h ++++ b/include/linux/mhi.h +@@ -266,6 +266,7 @@ struct mhi_event_config { + * struct mhi_controller_config - Root MHI controller configuration + * @max_channels: Maximum number of channels supported + * @timeout_ms: Timeout value for operations. 0 means use default ++ * @ready_timeout_ms: Timeout value for waiting device to be ready (optional) + * @buf_len: Size of automatically allocated buffers. 0 means use default + * @num_channels: Number of channels defined in @ch_cfg + * @ch_cfg: Array of defined channels +@@ -277,6 +278,7 @@ struct mhi_event_config { + struct mhi_controller_config { + u32 max_channels; + u32 timeout_ms; ++ u32 ready_timeout_ms; + u32 buf_len; + u32 num_channels; + const struct mhi_channel_config *ch_cfg; +@@ -330,6 +332,7 @@ struct mhi_controller_config { + * @pm_mutex: Mutex for suspend/resume operation + * @pm_lock: Lock for protecting MHI power management state + * @timeout_ms: Timeout in ms for state transitions ++ * @ready_timeout_ms: Timeout in ms for waiting device to be ready (optional) + * @pm_state: MHI power management state + * @db_access: DB access states + * @ee: MHI device execution environment +@@ -419,6 +422,7 @@ struct mhi_controller { + struct mutex pm_mutex; + rwlock_t pm_lock; + u32 timeout_ms; ++ u32 ready_timeout_ms; + u32 pm_state; + u32 db_access; + enum mhi_ee_type ee; diff --git a/lede/target/linux/generic/backport-6.6/851-v6.8-bus-mhi-host-pci_generic-Add-SDX75-based-modem-suppo.patch b/lede/target/linux/generic/backport-6.6/851-v6.8-bus-mhi-host-pci_generic-Add-SDX75-based-modem-suppo.patch new file mode 100644 index 0000000000..d0f7df5007 --- /dev/null +++ b/lede/target/linux/generic/backport-6.6/851-v6.8-bus-mhi-host-pci_generic-Add-SDX75-based-modem-suppo.patch @@ -0,0 +1,62 @@ +From 4dc9c850a974ba7db2091ce73bcffe631aafe144 Mon Sep 17 00:00:00 2001 +From: Qiang Yu +Date: Tue, 7 Nov 2023 16:14:50 +0800 +Subject: [PATCH 1/2] bus: mhi: host: pci_generic: Add SDX75 based modem + support + +Add generic info for SDX75 based modems. SDX75 takes longer to set ready +during power up. Hence use separate configuration. + +Signed-off-by: Qiang Yu +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1699344890-87076-3-git-send-email-quic_qianyu@quicinc.com +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -269,6 +269,16 @@ static struct mhi_event_config modem_qco + MHI_EVENT_CONFIG_HW_DATA(5, 2048, 101) + }; + ++static const struct mhi_controller_config modem_qcom_v2_mhiv_config = { ++ .max_channels = 128, ++ .timeout_ms = 8000, ++ .ready_timeout_ms = 50000, ++ .num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels), ++ .ch_cfg = modem_qcom_v1_mhi_channels, ++ .num_events = ARRAY_SIZE(modem_qcom_v1_mhi_events), ++ .event_cfg = modem_qcom_v1_mhi_events, ++}; ++ + static const struct mhi_controller_config modem_qcom_v1_mhiv_config = { + .max_channels = 128, + .timeout_ms = 8000, +@@ -278,6 +288,16 @@ static const struct mhi_controller_confi + .event_cfg = modem_qcom_v1_mhi_events, + }; + ++static const struct mhi_pci_dev_info mhi_qcom_sdx75_info = { ++ .name = "qcom-sdx75m", ++ .fw = "qcom/sdx75m/xbl.elf", ++ .edl = "qcom/sdx75m/edl.mbn", ++ .config = &modem_qcom_v2_mhiv_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .sideband_wake = false, ++}; ++ + static const struct mhi_pci_dev_info mhi_qcom_sdx65_info = { + .name = "qcom-sdx65m", + .fw = "qcom/sdx65m/xbl.elf", +@@ -600,6 +620,8 @@ static const struct pci_device_id mhi_pc + .driver_data = (kernel_ulong_t) &mhi_telit_fn990_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, ++ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0309), ++ .driver_data = (kernel_ulong_t) &mhi_qcom_sdx75_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */ diff --git a/lede/target/linux/generic/backport-6.6/852-stable-bus-mhi-host-pci_generic-constify-modem_telit_fn980_.patch b/lede/target/linux/generic/backport-6.6/852-stable-bus-mhi-host-pci_generic-constify-modem_telit_fn980_.patch new file mode 100644 index 0000000000..e6df7895ce --- /dev/null +++ b/lede/target/linux/generic/backport-6.6/852-stable-bus-mhi-host-pci_generic-constify-modem_telit_fn980_.patch @@ -0,0 +1,28 @@ +From 2f5e59d70566902d7b4e13c6af3f042f5d28b78b Mon Sep 17 00:00:00 2001 +From: Jeff Johnson +Date: Thu, 22 Feb 2024 18:00:23 -0800 +Subject: [PATCH 2/2] bus: mhi: host: pci_generic: constify + modem_telit_fn980_hw_v1_config + +MHI expects the controller configs to be const, and all of the other ones +in this file already are, so constify modem_telit_fn980_hw_v1_config. + +Signed-off-by: Jeff Johnson +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20240222-mhi-const-bus-mhi-host-pci_generic-v1-1-d4c9b0b0a7a5@quicinc.com +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -538,7 +538,7 @@ static struct mhi_event_config mhi_telit + MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101) + }; + +-static struct mhi_controller_config modem_telit_fn980_hw_v1_config = { ++static const struct mhi_controller_config modem_telit_fn980_hw_v1_config = { + .max_channels = 128, + .timeout_ms = 20000, + .num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels), diff --git a/lede/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch b/lede/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch index f239355594..fe0f260ae3 100644 --- a/lede/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch +++ b/lede/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch @@ -20,7 +20,7 @@ Signed-off-by: Robert Marko --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c -@@ -905,6 +905,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_ +@@ -906,6 +906,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_ switch (event) { case MHI_EE_SBL: st = DEV_ST_TRANSITION_SBL; diff --git a/lede/target/linux/generic/pending-6.6/790-bus-mhi-core-add-SBL-state-callback.patch b/lede/target/linux/generic/pending-6.6/790-bus-mhi-core-add-SBL-state-callback.patch index f239355594..fe0f260ae3 100644 --- a/lede/target/linux/generic/pending-6.6/790-bus-mhi-core-add-SBL-state-callback.patch +++ b/lede/target/linux/generic/pending-6.6/790-bus-mhi-core-add-SBL-state-callback.patch @@ -20,7 +20,7 @@ Signed-off-by: Robert Marko --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c -@@ -905,6 +905,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_ +@@ -906,6 +906,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_ switch (event) { case MHI_EE_SBL: st = DEV_ST_TRANSITION_SBL; diff --git a/mihomo/adapter/outboundgroup/parser.go b/mihomo/adapter/outboundgroup/parser.go index ac4546d822..876c92fa32 100644 --- a/mihomo/adapter/outboundgroup/parser.go +++ b/mihomo/adapter/outboundgroup/parser.go @@ -108,7 +108,6 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide } else { addTestUrlToProviders(PDs, groupOption.URL, expectedStatus, groupOption.Filter, uint(groupOption.Interval)) } - providers = append(providers, PDs...) } @@ -140,7 +139,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide return nil, fmt.Errorf("%s: %w", groupName, err) } - providers = append(providers, pd) + providers = append([]types.ProxyProvider{pd}, providers...) providersMap[groupName] = pd } diff --git a/mihomo/adapter/provider/parser.go b/mihomo/adapter/provider/parser.go index 2e4366691e..bbaf29be31 100644 --- a/mihomo/adapter/provider/parser.go +++ b/mihomo/adapter/provider/parser.go @@ -44,14 +44,16 @@ type proxyProviderSchema struct { Type string `provider:"type"` Path string `provider:"path,omitempty"` URL string `provider:"url,omitempty"` + Proxy string `provider:"proxy,omitempty"` Interval int `provider:"interval,omitempty"` Filter string `provider:"filter,omitempty"` ExcludeFilter string `provider:"exclude-filter,omitempty"` ExcludeType string `provider:"exclude-type,omitempty"` DialerProxy string `provider:"dialer-proxy,omitempty"` - HealthCheck healthCheckSchema `provider:"health-check,omitempty"` - Override OverrideSchema `provider:"override,omitempty"` + HealthCheck healthCheckSchema `provider:"health-check,omitempty"` + Override OverrideSchema `provider:"override,omitempty"` + Header map[string][]string `provider:"header,omitempty"` } func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvider, error) { @@ -86,16 +88,17 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide path := C.Path.Resolve(schema.Path) vehicle = resource.NewFileVehicle(path) case "http": + var path string if schema.Path != "" { - path := C.Path.Resolve(schema.Path) + path = C.Path.Resolve(schema.Path) if !features.CMFA && !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } - vehicle = resource.NewHTTPVehicle(schema.URL, path) } else { - path := C.Path.GetPathByHash("proxies", schema.URL) - vehicle = resource.NewHTTPVehicle(schema.URL, path) + path = C.Path.GetPathByHash("proxies", schema.URL) } + + vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, schema.Header) default: return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type) } diff --git a/mihomo/adapter/provider/provider.go b/mihomo/adapter/provider/provider.go index 2715a30972..aa5b823350 100644 --- a/mihomo/adapter/provider/provider.go +++ b/mihomo/adapter/provider/provider.go @@ -125,7 +125,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() resp, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), - http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return } @@ -134,7 +134,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() { userInfoStr := strings.TrimSpace(resp.Header.Get("subscription-userinfo")) if userInfoStr == "" { resp2, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), - http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil) + http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil, "") if err != nil { return } diff --git a/mihomo/component/geodata/init.go b/mihomo/component/geodata/init.go index 834567a447..64022f013b 100644 --- a/mihomo/component/geodata/init.go +++ b/mihomo/component/geodata/init.go @@ -47,7 +47,7 @@ func InitGeoSite() error { func downloadGeoSite(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return } @@ -66,7 +66,7 @@ func downloadGeoSite(path string) (err error) { func downloadGeoIP(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return } diff --git a/mihomo/component/http/http.go b/mihomo/component/http/http.go index 455db681d2..ef37e328b8 100644 --- a/mihomo/component/http/http.go +++ b/mihomo/component/http/http.go @@ -16,8 +16,7 @@ import ( "github.com/metacubex/mihomo/listener/inner" ) -func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) { - UA := C.UA +func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader, specialProxy string) (*http.Response, error) { method = strings.ToUpper(method) urlRes, err := URL.Parse(url) if err != nil { @@ -32,7 +31,7 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st } if _, ok := header["User-Agent"]; !ok { - req.Header.Set("User-Agent", UA) + req.Header.Set("User-Agent", C.UA) } if err != nil { @@ -54,7 +53,7 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { - if conn, err := inner.HandleTcp(address); err == nil { + if conn, err := inner.HandleTcp(address, specialProxy); err == nil { return conn, nil } else { d := net.Dialer{} @@ -66,5 +65,4 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st client := http.Client{Transport: transport} return client.Do(req) - } diff --git a/mihomo/component/mmdb/mmdb.go b/mihomo/component/mmdb/mmdb.go index 81156bc62d..120739fc15 100644 --- a/mihomo/component/mmdb/mmdb.go +++ b/mihomo/component/mmdb/mmdb.go @@ -82,7 +82,7 @@ func IPInstance() IPReader { func DownloadMMDB(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return } @@ -115,7 +115,7 @@ func ASNInstance() ASNReader { func DownloadASN(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.ASNUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.ASNUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return } diff --git a/mihomo/component/resource/vehicle.go b/mihomo/component/resource/vehicle.go index b2e2941823..2f71c2e6c6 100644 --- a/mihomo/component/resource/vehicle.go +++ b/mihomo/component/resource/vehicle.go @@ -33,8 +33,10 @@ func NewFileVehicle(path string) *FileVehicle { } type HTTPVehicle struct { - url string - path string + url string + path string + proxy string + header http.Header } func (h *HTTPVehicle) Url() string { @@ -52,7 +54,7 @@ func (h *HTTPVehicle) Path() string { func (h *HTTPVehicle) Read() ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*20) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, nil, nil) + resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, h.header, nil, h.proxy) if err != nil { return nil, err } @@ -67,6 +69,6 @@ func (h *HTTPVehicle) Read() ([]byte, error) { return buf, nil } -func NewHTTPVehicle(url string, path string) *HTTPVehicle { - return &HTTPVehicle{url, path} +func NewHTTPVehicle(url string, path string, proxy string, header http.Header) *HTTPVehicle { + return &HTTPVehicle{url, path, proxy, header} } diff --git a/mihomo/config/config.go b/mihomo/config/config.go index c793157372..c5c4fa88f4 100644 --- a/mihomo/config/config.go +++ b/mihomo/config/config.go @@ -413,7 +413,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { ProxyGroup: []map[string]any{}, TCPConcurrent: false, FindProcessMode: P.FindProcessStrict, - GlobalUA: "clash.meta", + GlobalUA: "clash.meta/" + C.Version, Tun: RawTun{ Enable: false, Device: "", diff --git a/mihomo/config/utils.go b/mihomo/config/utils.go index 66bf3441f2..596199ca18 100644 --- a/mihomo/config/utils.go +++ b/mihomo/config/utils.go @@ -20,7 +20,7 @@ import ( func downloadForBytes(url string) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return nil, err } diff --git a/mihomo/docs/config.yaml b/mihomo/docs/config.yaml index 6aa0686223..869b5231f7 100644 --- a/mihomo/docs/config.yaml +++ b/mihomo/docs/config.yaml @@ -8,15 +8,15 @@ mixed-port: 10801 # HTTP(S) 和 SOCKS 代理混合端口 allow-lan: true # 允许局域网连接 bind-address: "*" # 绑定 IP 地址,仅作用于 allow-lan 为 true,'*'表示所有地址 -authentication: # http,socks入口的验证用户名,密码 +authentication: # http,socks 入口的验证用户名,密码 - "username:password" -skip-auth-prefixes: # 设置跳过验证的IP段 +skip-auth-prefixes: # 设置跳过验证的 IP 段 - 127.0.0.1/8 - ::1/128 -lan-allowed-ips: # 允许连接的 IP 地址段,仅作用于 allow-lan 为 true, 默认值为0.0.0.0/0和::/0 +lan-allowed-ips: # 允许连接的 IP 地址段,仅作用于 allow-lan 为 true, 默认值为 0.0.0.0/0 和::/0 - 0.0.0.0/0 - ::/0 -lan-disallowed-ips: # 禁止连接的 IP 地址段, 黑名单优先级高于白名单, 默认值为空 +lan-disallowed-ips: # 禁止连接的 IP 地址段,黑名单优先级高于白名单,默认值为空 - 192.168.0.3/32 # find-process-mode has 3 values:always, strict, off @@ -109,9 +109,9 @@ tun: # auto-detect-interface: true # 自动识别出口网卡 # auto-route: true # 配置路由表 # mtu: 9000 # 最大传输单元 - # gso: false # 启用通用分段卸载, 仅支持 Linux + # gso: false # 启用通用分段卸载,仅支持 Linux # gso-max-size: 65536 # 通用分段卸载包的最大大小 - # strict-route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 + # strict-route: true # 将所有连接路由到 tun 来防止泄漏,但你的设备将无法其他设备被访问 inet4-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 - 0.0.0.0/1 - 128.0.0.0/1 @@ -119,9 +119,9 @@ tun: - "::/1" - "8000::/1" # endpoint-independent-nat: false # 启用独立于端点的 NAT - # include-interface: # 限制被路由的接口。默认不限制, 与 `exclude-interface` 冲突 + # include-interface: # 限制被路由的接口。默认不限制,与 `exclude-interface` 冲突 # - "lan0" - # exclude-interface: # 排除路由的接口, 与 `include-interface` 冲突 + # exclude-interface: # 排除路由的接口,与 `include-interface` 冲突 # - "lan1" # include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto-route # - 0 @@ -143,7 +143,7 @@ tun: # exclude-package: # 排除被路由的 Android 应用包名 # - com.android.captiveportallogin -#ebpf配置 +#ebpf 配置 ebpf: auto-redir: # redirect 模式,仅支持 TCP - eth0 @@ -200,7 +200,7 @@ tunnels: # one line config target: target.com proxy: proxy -# DNS配置 +# DNS 配置 dns: cache-algorithm: arc enable: false # 关闭将使用系统 DNS @@ -208,7 +208,7 @@ dns: listen: 0.0.0.0:53 # 开启 DNS 服务器监听 # ipv6: false # false 将返回 AAAA 的空结果 # ipv6-timeout: 300 # 单位:ms,内部双栈并发时,向上游查询 AAAA 时,等待 AAAA 的时间,默认 100ms - # 用于解析 nameserver,fallback 以及其他DNS服务器配置的,DNS 服务域名 + # 用于解析 nameserver,fallback 以及其他 DNS 服务器配置的,DNS 服务域名 # 只能使用纯 IP 地址,可使用加密 DNS default-nameserver: - 114.114.114.114 @@ -222,12 +222,12 @@ dns: # use-hosts: true # 查询 hosts - # 配置不使用fake-ip的域名 + # 配置不使用 fake-ip 的域名 # fake-ip-filter: # - '*.lan' # - localhost.ptlogin2.qq.com - # DNS主要域名配置 + # DNS 主要域名配置 # 支持 UDP,TCP,DoT,DoH,DoQ # 这部分为主要 DNS 配置,影响所有直连,确保使用对大陆解析精准的 DNS nameserver: @@ -239,7 +239,7 @@ dns: - https://mozilla.cloudflare-dns.com/dns-query#DNS&h3=true # 指定策略组和使用 HTTP/3 - dhcp://en0 # dns from dhcp - quic://dns.adguard.com:784 # DNS over QUIC - # - '8.8.8.8#en0' # 兼容指定DNS出口网卡 + # - '8.8.8.8#en0' # 兼容指定 DNS 出口网卡 # 当配置 fallback 时,会查询 nameserver 中返回的 IP 是否为 CN,非必要配置 # 当不是 CN,则使用 fallback 中的 DNS 查询结果 @@ -338,7 +338,7 @@ proxies: # socks5 # udp-over-tcp: false # ip-version: ipv4 # 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer。默认使用 dual # ipv4:仅使用 IPv4 ipv6:仅使用 IPv6 - # ipv4-prefer:优先使用 IPv4 对于 TCP 会进行双栈解析,并发链接但是优先使用 IPv4 链接, + # ipv4-prefer:优先使用 IPv4 对于 TCP 会进行双栈解析,并发链接但是优先使用 IPv4 链接, # UDP 则为双栈解析,获取结果中的第一个 IPv4 # ipv6-prefer 同 ipv4-prefer # 现有协议都支持此参数,TCP 效果仅在开启 tcp-concurrent 生效 @@ -350,7 +350,7 @@ proxies: # socks5 # max-streams: 0 # Maximum multiplexed streams in a connection before opening a new connection. Conflict with max-connections and min-streams. # padding: false # Enable padding. Requires sing-box server version 1.3-beta9 or later. # statistic: false # 控制是否将底层连接显示在面板中,方便打断底层连接 - # only-tcp: false # 如果设置为true, smux的设置将不会对udp生效,udp连接会直接走底层协议 + # only-tcp: false # 如果设置为 true, smux 的设置将不会对 udp 生效,udp 连接会直接走底层协议 - name: "ss2" type: ss @@ -406,18 +406,18 @@ proxies: # socks5 password: [YOUR_SS_PASSWORD] client-fingerprint: chrome # One of: chrome, ios, firefox or safari - # 可以是chrome, ios, firefox, safari中的一个 + # 可以是 chrome, ios, firefox, safari 中的一个 plugin: restls plugin-opts: host: "www.microsoft.com" # Must be a TLS 1.3 server - # 应当是一个TLS 1.3 服务器 + # 应当是一个 TLS 1.3 服务器 password: [YOUR_RESTLS_PASSWORD] version-hint: "tls13" # Control your post-handshake traffic through restls-script # Hide proxy behaviors like "tls in tls". # see https://github.com/3andne/restls/blob/main/Restls-Script:%20Hide%20Your%20Proxy%20Traffic%20Behavior.md - # 用restls剧本来控制握手后的行为,隐藏"tls in tls"等特征 + # 用 restls 剧本来控制握手后的行为,隐藏"tls in tls"等特征 # 详情:https://github.com/3andne/restls/blob/main/Restls-Script:%20%E9%9A%90%E8%97%8F%E4%BD%A0%E7%9A%84%E4%BB%A3%E7%90%86%E8%A1%8C%E4%B8%BA.md restls-script: "300?100<1,400~100,350~100,600~100,300~200,300~100" @@ -429,18 +429,18 @@ proxies: # socks5 password: [YOUR_SS_PASSWORD] client-fingerprint: chrome # One of: chrome, ios, firefox or safari - # 可以是chrome, ios, firefox, safari中的一个 + # 可以是 chrome, ios, firefox, safari 中的一个 plugin: restls plugin-opts: host: "vscode.dev" # Must be a TLS 1.2 server - # 应当是一个TLS 1.2 服务器 + # 应当是一个 TLS 1.2 服务器 password: [YOUR_RESTLS_PASSWORD] version-hint: "tls12" restls-script: "1000?100<1,500~100,350~100,600~100,400~200" # vmess - # cipher支持 auto/aes-128-gcm/chacha20-poly1305/none + # cipher 支持 auto/aes-128-gcm/chacha20-poly1305/none - name: "vmess" type: vmess server: server @@ -680,11 +680,11 @@ proxies: # socks5 port: 443 # ports: 1000,2000-3000,5000 # port 不可省略 # hop-interval: 15 - # up和down均不写或为0则使用BBR流控 + # up 和 down 均不写或为 0 则使用 BBR 流控 # up: "30 Mbps" # 若不写单位,默认为 Mbps # down: "200 Mbps" # 若不写单位,默认为 Mbps password: yourpassword - # obfs: salamander # 默认为空,如果填写则开启obfs,目前仅支持salamander + # obfs: salamander # 默认为空,如果填写则开启 obfs,目前仅支持 salamander # obfs-password: yourpassword # sni: server.com # skip-cert-verify: false @@ -710,9 +710,9 @@ proxies: # socks5 # reserved: [209,98,59] # 一个出站代理的标识。当值不为空时,将使用指定的 proxy 发出连接 # dialer-proxy: "ss1" - # remote-dns-resolve: true # 强制dns远程解析,默认值为false - # dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在remote-dns-resolve为true时生效 - # 如果peers不为空,该段落中的allowed-ips不可为空;前面段落的server,port,public-key,pre-shared-key均会被忽略,但private-key会被保留且只能在顶层指定 + # remote-dns-resolve: true # 强制 dns 远程解析,默认值为 false + # dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在 remote-dns-resolve 为 true 时生效 + # 如果 peers 不为空,该段落中的 allowed-ips 不可为空;前面段落的 server,port,public-key,pre-shared-key 均会被忽略,但 private-key 会被保留且只能在顶层指定 # peers: # - server: 162.159.192.1 # port: 2480 @@ -726,9 +726,9 @@ proxies: # socks5 server: www.example.com port: 10443 type: tuic - # tuicV4必须填写token (不可同时填写uuid和password) + # tuicV4 必须填写 token(不可同时填写 uuid 和 password) token: TOKEN - # tuicV5必须填写uuid和password(不可同时填写token) + # tuicV5 必须填写 uuid 和 password(不可同时填写 token) uuid: 00000000-0000-0000-0000-000000000001 password: PASSWORD_1 # ip: 127.0.0.1 # for overwriting the DNS lookup result of the server address set in option 'server' @@ -746,8 +746,8 @@ proxies: # socks5 # max-open-streams: 20 # default 100, too many open streams may hurt performance # sni: example.com # - # meta和sing-box私有扩展,将ss-uot用于udp中继,开启此选项后udp-relay-mode将失效 - # 警告,与原版tuic不兼容!!! + # meta 和 sing-box 私有扩展,将 ss-uot 用于 udp 中继,开启此选项后 udp-relay-mode 将失效 + # 警告,与原版 tuic 不兼容!!! # udp-over-stream: false # udp-over-stream-version: 1 @@ -780,12 +780,12 @@ proxies: # socks5 password: password privateKey: path -# dns出站会将请求劫持到内部dns模块,所有请求均在内部处理 +# dns 出站会将请求劫持到内部 dns 模块,所有请求均在内部处理 - name: "dns-out" type: dns proxy-groups: - # 代理链,目前relay可以支持udp的只有vmess/vless/trojan/ss/ssr/tuic - # wireguard目前不支持在relay中使用,请使用proxy中的dialer-proxy配置项 + # 代理链,目前 relay 可以支持 udp 的只有 vmess/vless/trojan/ss/ssr/tuic + # wireguard 目前不支持在 relay 中使用,请使用 proxy 中的 dialer-proxy 配置项 # Traffic: mihomo <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet - name: "relay" type: relay @@ -859,10 +859,19 @@ proxy-groups: # Mihomo 格式的节点或支持 *ray 的分享格式 proxy-providers: provider1: - type: http # http 的 path 可空置,默认储存路径为 homedir的proxies文件夹,文件名为url的md5 + type: http # http 的 path 可空置,默认储存路径为 homedir 的 proxies 文件夹,文件名为 url 的 md5 url: "url" interval: 3600 path: ./provider1.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 + proxy: DIRECT + header: + User-Agent: + - "Clash/v1.18.0" + - "mihomo/1.18.3" + # Accept: + # - 'application/vnd.github.v3.raw' + # Authorization: + # - 'token 1231231' health-check: enable: true interval: 600 @@ -892,8 +901,9 @@ rule-providers: behavior: classical # domain ipcidr interval: 259200 path: /path/to/save/file.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 - type: http # http 的 path 可空置,默认储存路径为 homedir的rules文件夹,文件名为url的md5 + type: http # http 的 path 可空置,默认储存路径为 homedir 的 rules 文件夹,文件名为 url 的 md5 url: "url" + proxy: DIRECT rule2: behavior: classical interval: 259200 @@ -942,7 +952,7 @@ listeners: port: 10808 #listen: 0.0.0.0 # 默认监听 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理 + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 # udp: false # 默认 true - name: http-in-1 @@ -950,14 +960,14 @@ listeners: port: 10809 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) - name: mixed-in-1 type: mixed # HTTP(S) 和 SOCKS 代理混合 port: 10810 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) # udp: false # 默认 true - name: reidr-in-1 @@ -965,14 +975,14 @@ listeners: port: 10811 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) - name: tproxy-in-1 type: tproxy port: 10812 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) # udp: false # 默认 true - name: shadowsocks-in-1 @@ -980,7 +990,7 @@ listeners: port: 10813 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) password: vlmpIPSyHH6f4S8WVPdRIHIlzmB+GIRfoH3aNJ/t9Gg= cipher: 2022-blake3-aes-256-gcm @@ -989,13 +999,13 @@ listeners: port: 10814 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) users: - username: 1 uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 alterId: 1 - # ws-path: "/" # 如果不为空则开启websocket传输层 - # 下面两项如果填写则开启tls(需要同时填写) + # ws-path: "/" # 如果不为空则开启 websocket 传输层 + # 下面两项如果填写则开启 tls(需要同时填写) # certificate: ./server.crt # private-key: ./server.key @@ -1004,10 +1014,10 @@ listeners: port: 10815 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) - # token: # tuicV4填写(可以同时填写users) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) + # token: # tuicV4 填写(可以同时填写 users) # - TOKEN - # users: # tuicV5填写(可以同时填写token) + # users: # tuicV5 填写(可以同时填写 token) # 00000000-0000-0000-0000-000000000000: PASSWORD_0 # 00000000-0000-0000-0000-000000000001: PASSWORD_1 # certificate: ./server.crt @@ -1024,25 +1034,25 @@ listeners: port: 10816 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) network: [tcp, udp] target: target.com - name: tun-in-1 type: tun # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules - # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) + # proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错) stack: system # gvisor / mixed dns-hijack: - 0.0.0.0:53 # 需要劫持的 DNS # auto-detect-interface: false # 自动识别出口网卡 # auto-route: false # 配置路由表 # mtu: 9000 # 最大传输单元 - inet4-address: # 必须手动设置ipv4地址段 + inet4-address: # 必须手动设置 ipv4 地址段 - 198.19.0.1/30 - inet6-address: # 必须手动设置ipv6地址段 + inet6-address: # 必须手动设置 ipv6 地址段 - "fdfe:dcba:9877::1/126" - # strict-route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 + # strict-route: true # 将所有连接路由到 tun 来防止泄漏,但你的设备将无法其他设备被访问 # inet4-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 # - 0.0.0.0/1 # - 128.0.0.0/1 @@ -1070,17 +1080,17 @@ listeners: # exclude-package: # 排除被路由的 Android 应用包名 # - com.android.captiveportallogin # 入口配置与 Listener 等价,传入流量将和 socks,mixed 等入口一样按照 mode 所指定的方式进行匹配处理 -# shadowsocks,vmess 入口配置(传入流量将和socks,mixed等入口一样按照mode所指定的方式进行匹配处理) +# shadowsocks,vmess 入口配置(传入流量将和 socks,mixed 等入口一样按照 mode 所指定的方式进行匹配处理) # ss-config: ss://2022-blake3-aes-256-gcm:vlmpIPSyHH6f4S8WVPdRIHIlzmB+GIRfoH3aNJ/t9Gg=@:23456 # vmess-config: vmess://1:9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68@:12345 -# tuic服务器入口(传入流量将和socks,mixed等入口一样按照mode所指定的方式进行匹配处理) +# tuic 服务器入口(传入流量将和 socks,mixed 等入口一样按照 mode 所指定的方式进行匹配处理) # tuic-server: # enable: true # listen: 127.0.0.1:10443 -# token: # tuicV4填写(可以同时填写users) +# token: # tuicV4 填写(可以同时填写 users) # - TOKEN -# users: # tuicV5填写(可以同时填写token) +# users: # tuicV5 填写(可以同时填写 token) # 00000000-0000-0000-0000-000000000000: PASSWORD_0 # 00000000-0000-0000-0000-000000000001: PASSWORD_1 # certificate: ./server.crt diff --git a/mihomo/hub/updater/updater.go b/mihomo/hub/updater/updater.go index 02ff07ba26..e0d3a39ca1 100644 --- a/mihomo/hub/updater/updater.go +++ b/mihomo/hub/updater/updater.go @@ -234,7 +234,7 @@ const MaxPackageFileSize = 32 * 1024 * 1024 func downloadPackageFile() (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return fmt.Errorf("http request failed: %w", err) } @@ -415,7 +415,7 @@ func copyFile(src, dst string) error { func getLatestVersion() (version string, err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "") if err != nil { return "", fmt.Errorf("get Latest Version fail: %w", err) } diff --git a/mihomo/listener/inner/tcp.go b/mihomo/listener/inner/tcp.go index dac3d72143..ee34ada661 100644 --- a/mihomo/listener/inner/tcp.go +++ b/mihomo/listener/inner/tcp.go @@ -16,7 +16,7 @@ func New(t C.Tunnel) { tunnel = t } -func HandleTcp(address string) (conn net.Conn, err error) { +func HandleTcp(address string, proxy string) (conn net.Conn, err error) { if tunnel == nil { return nil, errors.New("tcp uninitialized") } @@ -28,6 +28,9 @@ func HandleTcp(address string) (conn net.Conn, err error) { metadata.Type = C.INNER metadata.DNSMode = C.DNSNormal metadata.Process = C.MihomoName + if proxy != "" { + metadata.SpecialProxy = proxy + } if h, port, err := net.SplitHostPort(address); err == nil { if port, err := strconv.ParseUint(port, 10, 16); err == nil { metadata.DstPort = uint16(port) diff --git a/mihomo/rules/provider/parse.go b/mihomo/rules/provider/parse.go index a867d570fd..e7920adf6c 100644 --- a/mihomo/rules/provider/parse.go +++ b/mihomo/rules/provider/parse.go @@ -21,6 +21,7 @@ type ruleProviderSchema struct { Behavior string `provider:"behavior"` Path string `provider:"path,omitempty"` URL string `provider:"url,omitempty"` + Proxy string `provider:"proxy,omitempty"` Format string `provider:"format,omitempty"` Interval int `provider:"interval,omitempty"` } @@ -61,17 +62,17 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t path := C.Path.Resolve(schema.Path) vehicle = resource.NewFileVehicle(path) case "http": + var path string if schema.Path != "" { - path := C.Path.Resolve(schema.Path) + path = C.Path.Resolve(schema.Path) if !features.CMFA && !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } - vehicle = resource.NewHTTPVehicle(schema.URL, path) } else { - path := C.Path.GetPathByHash("rules", schema.URL) - vehicle = resource.NewHTTPVehicle(schema.URL, path) - } + path = C.Path.GetPathByHash("rules", schema.URL) + } + vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, nil) default: return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type) } diff --git a/ryujinx/Directory.Packages.props b/ryujinx/Directory.Packages.props index 455735fc46..5d6adcb367 100644 --- a/ryujinx/Directory.Packages.props +++ b/ryujinx/Directory.Packages.props @@ -13,7 +13,7 @@ - + diff --git a/ryujinx/docs/README.md b/ryujinx/docs/README.md index 2213086f67..a22da3c7cf 100644 --- a/ryujinx/docs/README.md +++ b/ryujinx/docs/README.md @@ -33,8 +33,3 @@ Project Docs ================= To be added. Many project files will contain basic XML docs for key functions and classes in the meantime. - -Other Information -================= - -- N/A diff --git a/ryujinx/src/Ryujinx.Cpu/AddressSpace.cs b/ryujinx/src/Ryujinx.Cpu/AddressSpace.cs index beea14beec..6664ed1345 100644 --- a/ryujinx/src/Ryujinx.Cpu/AddressSpace.cs +++ b/ryujinx/src/Ryujinx.Cpu/AddressSpace.cs @@ -1,5 +1,3 @@ -using Ryujinx.Common; -using Ryujinx.Common.Collections; using Ryujinx.Memory; using System; @@ -7,175 +5,23 @@ namespace Ryujinx.Cpu { public class AddressSpace : IDisposable { - private const int DefaultBlockAlignment = 1 << 20; - - private enum MappingType : byte - { - None, - Private, - Shared, - } - - private class Mapping : IntrusiveRedBlackTreeNode, IComparable - { - public ulong Address { get; private set; } - public ulong Size { get; private set; } - public ulong EndAddress => Address + Size; - public MappingType Type { get; private set; } - - public Mapping(ulong address, ulong size, MappingType type) - { - Address = address; - Size = size; - Type = type; - } - - public Mapping Split(ulong splitAddress) - { - ulong leftSize = splitAddress - Address; - ulong rightSize = EndAddress - splitAddress; - - Mapping left = new(Address, leftSize, Type); - - Address = splitAddress; - Size = rightSize; - - return left; - } - - public void UpdateState(MappingType newType) - { - Type = newType; - } - - public void Extend(ulong sizeDelta) - { - Size += sizeDelta; - } - - public int CompareTo(Mapping other) - { - if (Address < other.Address) - { - return -1; - } - else if (Address <= other.EndAddress - 1UL) - { - return 0; - } - else - { - return 1; - } - } - } - - private class PrivateMapping : IntrusiveRedBlackTreeNode, IComparable - { - public ulong Address { get; private set; } - public ulong Size { get; private set; } - public ulong EndAddress => Address + Size; - public PrivateMemoryAllocation PrivateAllocation { get; private set; } - - public PrivateMapping(ulong address, ulong size, PrivateMemoryAllocation privateAllocation) - { - Address = address; - Size = size; - PrivateAllocation = privateAllocation; - } - - public PrivateMapping Split(ulong splitAddress) - { - ulong leftSize = splitAddress - Address; - ulong rightSize = EndAddress - splitAddress; - - (var leftAllocation, PrivateAllocation) = PrivateAllocation.Split(leftSize); - - PrivateMapping left = new(Address, leftSize, leftAllocation); - - Address = splitAddress; - Size = rightSize; - - return left; - } - - public void Map(MemoryBlock baseBlock, MemoryBlock mirrorBlock, PrivateMemoryAllocation newAllocation) - { - baseBlock.MapView(newAllocation.Memory, newAllocation.Offset, Address, Size); - mirrorBlock.MapView(newAllocation.Memory, newAllocation.Offset, Address, Size); - PrivateAllocation = newAllocation; - } - - public void Unmap(MemoryBlock baseBlock, MemoryBlock mirrorBlock) - { - if (PrivateAllocation.IsValid) - { - baseBlock.UnmapView(PrivateAllocation.Memory, Address, Size); - mirrorBlock.UnmapView(PrivateAllocation.Memory, Address, Size); - PrivateAllocation.Dispose(); - } - - PrivateAllocation = default; - } - - public void Extend(ulong sizeDelta) - { - Size += sizeDelta; - } - - public int CompareTo(PrivateMapping other) - { - if (Address < other.Address) - { - return -1; - } - else if (Address <= other.EndAddress - 1UL) - { - return 0; - } - else - { - return 1; - } - } - } - private readonly MemoryBlock _backingMemory; - private readonly PrivateMemoryAllocator _privateMemoryAllocator; - private readonly IntrusiveRedBlackTree _mappingTree; - private readonly IntrusiveRedBlackTree _privateTree; - - private readonly object _treeLock; - - private readonly bool _supports4KBPages; public MemoryBlock Base { get; } public MemoryBlock Mirror { get; } public ulong AddressSpaceSize { get; } - public AddressSpace(MemoryBlock backingMemory, MemoryBlock baseMemory, MemoryBlock mirrorMemory, ulong addressSpaceSize, bool supports4KBPages) + public AddressSpace(MemoryBlock backingMemory, MemoryBlock baseMemory, MemoryBlock mirrorMemory, ulong addressSpaceSize) { - if (!supports4KBPages) - { - _privateMemoryAllocator = new PrivateMemoryAllocator(DefaultBlockAlignment, MemoryAllocationFlags.Mirrorable | MemoryAllocationFlags.NoMap); - _mappingTree = new IntrusiveRedBlackTree(); - _privateTree = new IntrusiveRedBlackTree(); - _treeLock = new object(); - - _mappingTree.Add(new Mapping(0UL, addressSpaceSize, MappingType.None)); - _privateTree.Add(new PrivateMapping(0UL, addressSpaceSize, default)); - } - _backingMemory = backingMemory; - _supports4KBPages = supports4KBPages; Base = baseMemory; Mirror = mirrorMemory; AddressSpaceSize = addressSpaceSize; } - public static bool TryCreate(MemoryBlock backingMemory, ulong asSize, bool supports4KBPages, out AddressSpace addressSpace) + public static bool TryCreate(MemoryBlock backingMemory, ulong asSize, out AddressSpace addressSpace) { addressSpace = null; @@ -193,7 +39,7 @@ namespace Ryujinx.Cpu { baseMemory = new MemoryBlock(addressSpaceSize, AsFlags); mirrorMemory = new MemoryBlock(addressSpaceSize, AsFlags); - addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, addressSpaceSize, supports4KBPages); + addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, addressSpaceSize); break; } @@ -209,289 +55,20 @@ namespace Ryujinx.Cpu public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags) { - if (_supports4KBPages) - { - Base.MapView(_backingMemory, pa, va, size); - Mirror.MapView(_backingMemory, pa, va, size); - - return; - } - - lock (_treeLock) - { - ulong alignment = MemoryBlock.GetPageSize(); - bool isAligned = ((va | pa | size) & (alignment - 1)) == 0; - - if (flags.HasFlag(MemoryMapFlags.Private) && !isAligned) - { - Update(va, pa, size, MappingType.Private); - } - else - { - // The update method assumes that shared mappings are already aligned. - - if (!flags.HasFlag(MemoryMapFlags.Private)) - { - if ((va & (alignment - 1)) != (pa & (alignment - 1))) - { - throw new InvalidMemoryRegionException($"Virtual address 0x{va:X} and physical address 0x{pa:X} are misaligned and can't be aligned."); - } - - ulong endAddress = va + size; - va = BitUtils.AlignDown(va, alignment); - pa = BitUtils.AlignDown(pa, alignment); - size = BitUtils.AlignUp(endAddress, alignment) - va; - } - - Update(va, pa, size, MappingType.Shared); - } - } + Base.MapView(_backingMemory, pa, va, size); + Mirror.MapView(_backingMemory, pa, va, size); } public void Unmap(ulong va, ulong size) { - if (_supports4KBPages) - { - Base.UnmapView(_backingMemory, va, size); - Mirror.UnmapView(_backingMemory, va, size); - - return; - } - - lock (_treeLock) - { - Update(va, 0UL, size, MappingType.None); - } - } - - private void Update(ulong va, ulong pa, ulong size, MappingType type) - { - Mapping map = _mappingTree.GetNode(new Mapping(va, 1UL, MappingType.None)); - - Update(map, va, pa, size, type); - } - - private Mapping Update(Mapping map, ulong va, ulong pa, ulong size, MappingType type) - { - ulong endAddress = va + size; - - for (; map != null; map = map.Successor) - { - if (map.Address < va) - { - _mappingTree.Add(map.Split(va)); - } - - if (map.EndAddress > endAddress) - { - Mapping newMap = map.Split(endAddress); - _mappingTree.Add(newMap); - map = newMap; - } - - switch (type) - { - case MappingType.None: - if (map.Type == MappingType.Shared) - { - ulong startOffset = map.Address - va; - ulong mapVa = va + startOffset; - ulong mapSize = Math.Min(size - startOffset, map.Size); - ulong mapEndAddress = mapVa + mapSize; - ulong alignment = MemoryBlock.GetPageSize(); - - mapVa = BitUtils.AlignDown(mapVa, alignment); - mapEndAddress = BitUtils.AlignUp(mapEndAddress, alignment); - - mapSize = mapEndAddress - mapVa; - - Base.UnmapView(_backingMemory, mapVa, mapSize); - Mirror.UnmapView(_backingMemory, mapVa, mapSize); - } - else - { - UnmapPrivate(va, size); - } - break; - case MappingType.Private: - if (map.Type == MappingType.Shared) - { - throw new InvalidMemoryRegionException($"Private mapping request at 0x{va:X} with size 0x{size:X} overlaps shared mapping at 0x{map.Address:X} with size 0x{map.Size:X}."); - } - else - { - MapPrivate(va, size); - } - break; - case MappingType.Shared: - if (map.Type != MappingType.None) - { - throw new InvalidMemoryRegionException($"Shared mapping request at 0x{va:X} with size 0x{size:X} overlaps mapping at 0x{map.Address:X} with size 0x{map.Size:X}."); - } - else - { - ulong startOffset = map.Address - va; - ulong mapPa = pa + startOffset; - ulong mapVa = va + startOffset; - ulong mapSize = Math.Min(size - startOffset, map.Size); - - Base.MapView(_backingMemory, mapPa, mapVa, mapSize); - Mirror.MapView(_backingMemory, mapPa, mapVa, mapSize); - } - break; - } - - map.UpdateState(type); - map = TryCoalesce(map); - - if (map.EndAddress >= endAddress) - { - break; - } - } - - return map; - } - - private Mapping TryCoalesce(Mapping map) - { - Mapping previousMap = map.Predecessor; - Mapping nextMap = map.Successor; - - if (previousMap != null && CanCoalesce(previousMap, map)) - { - previousMap.Extend(map.Size); - _mappingTree.Remove(map); - map = previousMap; - } - - if (nextMap != null && CanCoalesce(map, nextMap)) - { - map.Extend(nextMap.Size); - _mappingTree.Remove(nextMap); - } - - return map; - } - - private static bool CanCoalesce(Mapping left, Mapping right) - { - return left.Type == right.Type; - } - - private void MapPrivate(ulong va, ulong size) - { - ulong endAddress = va + size; - - ulong alignment = MemoryBlock.GetPageSize(); - - // Expand the range outwards based on page size to ensure that at least the requested region is mapped. - ulong vaAligned = BitUtils.AlignDown(va, alignment); - ulong endAddressAligned = BitUtils.AlignUp(endAddress, alignment); - - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default)); - - for (; map != null; map = map.Successor) - { - if (!map.PrivateAllocation.IsValid) - { - if (map.Address < vaAligned) - { - _privateTree.Add(map.Split(vaAligned)); - } - - if (map.EndAddress > endAddressAligned) - { - PrivateMapping newMap = map.Split(endAddressAligned); - _privateTree.Add(newMap); - map = newMap; - } - - map.Map(Base, Mirror, _privateMemoryAllocator.Allocate(map.Size, MemoryBlock.GetPageSize())); - } - - if (map.EndAddress >= endAddressAligned) - { - break; - } - } - } - - private void UnmapPrivate(ulong va, ulong size) - { - ulong endAddress = va + size; - - ulong alignment = MemoryBlock.GetPageSize(); - - // Shrink the range inwards based on page size to ensure we won't unmap memory that might be still in use. - ulong vaAligned = BitUtils.AlignUp(va, alignment); - ulong endAddressAligned = BitUtils.AlignDown(endAddress, alignment); - - if (endAddressAligned <= vaAligned) - { - return; - } - - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default)); - - for (; map != null; map = map.Successor) - { - if (map.PrivateAllocation.IsValid) - { - if (map.Address < vaAligned) - { - _privateTree.Add(map.Split(vaAligned)); - } - - if (map.EndAddress > endAddressAligned) - { - PrivateMapping newMap = map.Split(endAddressAligned); - _privateTree.Add(newMap); - map = newMap; - } - - map.Unmap(Base, Mirror); - map = TryCoalesce(map); - } - - if (map.EndAddress >= endAddressAligned) - { - break; - } - } - } - - private PrivateMapping TryCoalesce(PrivateMapping map) - { - PrivateMapping previousMap = map.Predecessor; - PrivateMapping nextMap = map.Successor; - - if (previousMap != null && CanCoalesce(previousMap, map)) - { - previousMap.Extend(map.Size); - _privateTree.Remove(map); - map = previousMap; - } - - if (nextMap != null && CanCoalesce(map, nextMap)) - { - map.Extend(nextMap.Size); - _privateTree.Remove(nextMap); - } - - return map; - } - - private static bool CanCoalesce(PrivateMapping left, PrivateMapping right) - { - return !left.PrivateAllocation.IsValid && !right.PrivateAllocation.IsValid; + Base.UnmapView(_backingMemory, va, size); + Mirror.UnmapView(_backingMemory, va, size); } public void Dispose() { GC.SuppressFinalize(this); - _privateMemoryAllocator?.Dispose(); Base.Dispose(); Mirror.Dispose(); } diff --git a/ryujinx/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs b/ryujinx/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs index 0c2e5f33a0..abdddb31c3 100644 --- a/ryujinx/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs +++ b/ryujinx/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs @@ -28,7 +28,7 @@ namespace Ryujinx.Cpu.AppleHv private readonly ManagedPageFlags _pages; - public bool Supports4KBPages => true; + public bool UsesPrivateAllocations => false; public int AddressSpaceBits { get; } diff --git a/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManager.cs b/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManager.cs index dfa5b93539..6f594ec2fd 100644 --- a/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManager.cs +++ b/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManager.cs @@ -25,7 +25,7 @@ namespace Ryujinx.Cpu.Jit private readonly InvalidAccessHandler _invalidAccessHandler; /// - public bool Supports4KBPages => true; + public bool UsesPrivateAllocations => false; /// /// Address space width in bits. diff --git a/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs b/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs index c60ab6b246..4639ab913d 100644 --- a/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs +++ b/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs @@ -27,7 +27,7 @@ namespace Ryujinx.Cpu.Jit private readonly ManagedPageFlags _pages; /// - public bool Supports4KBPages => MemoryBlock.GetPageSize() == PageSize; + public bool UsesPrivateAllocations => false; public int AddressSpaceBits { get; } diff --git a/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs b/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs index b2964cd29c..6dffcd295b 100644 --- a/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs +++ b/ryujinx/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs @@ -33,7 +33,7 @@ namespace Ryujinx.Cpu.Jit protected override ulong AddressSpaceSize { get; } /// - public bool Supports4KBPages => false; + public bool UsesPrivateAllocations => true; public IntPtr PageTablePointer => _nativePageTable.PageTablePointer; diff --git a/ryujinx/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/ryujinx/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index 2bcab51436..d5169a6884 100644 --- a/ryujinx/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/ryujinx/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -981,6 +981,7 @@ namespace Ryujinx.Graphics.Vulkan _bindingBarriersDirty = true; _newState.PipelineLayout = internalProgram.PipelineLayout; + _newState.HasTessellationControlShader = internalProgram.HasTessellationControlShader; _newState.StagesCount = (uint)stages.Length; stages.CopyTo(_newState.Stages.AsSpan()[..stages.Length]); diff --git a/ryujinx/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/ryujinx/src/Ryujinx.Graphics.Vulkan/PipelineState.cs index 25fd7168fb..49c12b3768 100644 --- a/ryujinx/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/ryujinx/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -311,6 +311,7 @@ namespace Ryujinx.Graphics.Vulkan set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6); } + public bool HasTessellationControlShader; public NativeArray Stages; public PipelineLayout PipelineLayout; public SpecData SpecializationData; @@ -319,6 +320,7 @@ namespace Ryujinx.Graphics.Vulkan public void Initialize() { + HasTessellationControlShader = false; Stages = new NativeArray(Constants.MaxShaderStages); AdvancedBlendSrcPreMultiplied = true; @@ -419,6 +421,15 @@ namespace Ryujinx.Graphics.Vulkan PVertexBindingDescriptions = pVertexBindingDescriptions, }; + // Using patches topology without a tessellation shader is invalid. + // If we find such a case, return null pipeline to skip the draw. + if (Topology == PrimitiveTopology.PatchList && !HasTessellationControlShader) + { + program.AddGraphicsPipeline(ref Internal, null); + + return null; + } + bool primitiveRestartEnable = PrimitiveRestartEnable; bool topologySupportsRestart; diff --git a/ryujinx/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs b/ryujinx/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs index 3d883b2d51..9edea5788d 100644 --- a/ryujinx/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs +++ b/ryujinx/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs @@ -122,7 +122,6 @@ namespace Ryujinx.Graphics.Vulkan gd.Api.CreateRenderPass(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError(); - _renderPass?.Dispose(); _renderPass = new Auto(new DisposableRenderPass(gd.Api, device, renderPass)); } @@ -162,7 +161,7 @@ namespace Ryujinx.Graphics.Vulkan public void Dispose() { - // Dispose all framebuffers + // Dispose all framebuffers. foreach (var fb in _framebuffers.Values) { @@ -175,6 +174,10 @@ namespace Ryujinx.Graphics.Vulkan { texture.RemoveRenderPass(_key); } + + // Dispose render pass. + + _renderPass.Dispose(); } } } diff --git a/ryujinx/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/ryujinx/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs index e4ea0e4e61..b2be541bf7 100644 --- a/ryujinx/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs +++ b/ryujinx/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs @@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.Vulkan public bool HasMinimalLayout { get; } public bool UsePushDescriptors { get; } public bool IsCompute { get; } + public bool HasTessellationControlShader => (Stages & (1u << 3)) != 0; public uint Stages { get; } @@ -461,6 +462,7 @@ namespace Ryujinx.Graphics.Vulkan stages[i] = _shaders[i].GetInfo(); } + pipeline.HasTessellationControlShader = HasTessellationControlShader; pipeline.StagesCount = (uint)_shaders.Length; pipeline.PipelineLayout = PipelineLayout; diff --git a/ryujinx/src/Ryujinx.Graphics.Vulkan/TextureView.cs b/ryujinx/src/Ryujinx.Graphics.Vulkan/TextureView.cs index 31d1396526..d918f965fa 100644 --- a/ryujinx/src/Ryujinx.Graphics.Vulkan/TextureView.cs +++ b/ryujinx/src/Ryujinx.Graphics.Vulkan/TextureView.cs @@ -4,6 +4,7 @@ using Silk.NET.Vulkan; using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using Format = Ryujinx.Graphics.GAL.Format; using VkBuffer = Silk.NET.Vulkan.Buffer; using VkFormat = Silk.NET.Vulkan.Format; @@ -36,7 +37,8 @@ namespace Ryujinx.Graphics.Vulkan public int FirstLayer { get; } public int FirstLevel { get; } public VkFormat VkFormat { get; } - public bool Valid { get; private set; } + private int _isValid; + public bool Valid => Volatile.Read(ref _isValid) != 0; public TextureView( VulkanRenderer gd, @@ -158,7 +160,7 @@ namespace Ryujinx.Graphics.Vulkan } } - Valid = true; + _isValid = 1; } /// @@ -178,7 +180,7 @@ namespace Ryujinx.Graphics.Vulkan VkFormat = format; - Valid = true; + _isValid = 1; } public Auto GetImage() @@ -1017,10 +1019,11 @@ namespace Ryujinx.Graphics.Vulkan { if (disposing) { - Valid = false; - - if (_gd.Textures.Remove(this)) + bool wasValid = Interlocked.Exchange(ref _isValid, 0) != 0; + if (wasValid) { + _gd.Textures.Remove(this); + _imageView.Dispose(); _imageView2dArray?.Dispose(); @@ -1034,7 +1037,7 @@ namespace Ryujinx.Graphics.Vulkan _imageViewDraw.Dispose(); } - Storage.DecrementViewsCount(); + Storage?.DecrementViewsCount(); if (_renderPasses != null) { @@ -1045,22 +1048,22 @@ namespace Ryujinx.Graphics.Vulkan pass.Dispose(); } } + + if (_selfManagedViews != null) + { + foreach (var view in _selfManagedViews.Values) + { + view.Dispose(); + } + + _selfManagedViews = null; + } } } } public void Dispose() { - if (_selfManagedViews != null) - { - foreach (var view in _selfManagedViews.Values) - { - view.Dispose(); - } - - _selfManagedViews = null; - } - Dispose(true); } diff --git a/ryujinx/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs b/ryujinx/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs index e8c433269e..6646826cb0 100644 --- a/ryujinx/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs +++ b/ryujinx/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs @@ -75,7 +75,7 @@ namespace Ryujinx.HLE.HOS // We want to use host tracked mode if the host page size is > 4KB. if ((mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe) && MemoryBlock.GetPageSize() <= 0x1000) { - if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, MemoryBlock.GetPageSize() == MemoryManagerHostMapped.PageSize, out addressSpace)) + if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, out addressSpace)) { Logger.Warning?.Print(LogClass.Cpu, "Address space creation failed, falling back to software page table"); diff --git a/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs b/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs index d7b601d1c5..d262c159d7 100644 --- a/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs +++ b/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTable.cs @@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory { private readonly IVirtualMemoryManager _cpuMemory; - protected override bool Supports4KBPages => _cpuMemory.Supports4KBPages; + protected override bool UsesPrivateAllocations => _cpuMemory.UsesPrivateAllocations; public KPageTable(KernelContext context, IVirtualMemoryManager cpuMemory, ulong reservedAddressSpaceSize) : base(context, reservedAddressSpaceSize) { diff --git a/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs b/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs index 6470742d92..ae99a434ad 100644 --- a/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs +++ b/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs @@ -32,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory private const int MaxBlocksNeededForInsertion = 2; protected readonly KernelContext Context; - protected virtual bool Supports4KBPages => true; + protected virtual bool UsesPrivateAllocations => false; public ulong AddrSpaceStart { get; private set; } public ulong AddrSpaceEnd { get; private set; } @@ -1947,17 +1947,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory Result result; - if (srcPageTable.Supports4KBPages) + if (srcPageTable.UsesPrivateAllocations) + { + result = MapForeign(srcPageTable.GetHostRegions(addressRounded, alignedSize), currentVa, alignedSize); + } + else { KPageList pageList = new(); srcPageTable.GetPhysicalRegions(addressRounded, alignedSize, pageList); result = MapPages(currentVa, pageList, permission, MemoryMapFlags.None); } - else - { - result = MapForeign(srcPageTable.GetHostRegions(addressRounded, alignedSize), currentVa, alignedSize); - } if (result != Result.Success) { diff --git a/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs b/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs index e302ee4434..e593a7e13f 100644 --- a/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs +++ b/ryujinx/src/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs @@ -2,7 +2,6 @@ using Ryujinx.Common; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.Horizon.Common; -using Ryujinx.Memory; namespace Ryujinx.HLE.HOS.Kernel.Memory { @@ -49,17 +48,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory return KernelResult.InvalidPermission; } - // On platforms with page size > 4 KB, this can fail due to the address not being page aligned, - // we can return an error to force the application to retry with a different address. - - try - { - return memoryManager.MapPages(address, _pageList, MemoryState.SharedMemory, permission); - } - catch (InvalidMemoryRegionException) - { - return KernelResult.InvalidMemState; - } + return memoryManager.MapPages(address, _pageList, MemoryState.SharedMemory, permission); } public Result UnmapFromProcess(KPageTableBase memoryManager, ulong address, ulong size, KProcess process) diff --git a/ryujinx/src/Ryujinx.HLE/HOS/ModLoader.cs b/ryujinx/src/Ryujinx.HLE/HOS/ModLoader.cs index 8ae529655c..de9d2a5039 100644 --- a/ryujinx/src/Ryujinx.HLE/HOS/ModLoader.cs +++ b/ryujinx/src/Ryujinx.HLE/HOS/ModLoader.cs @@ -218,7 +218,7 @@ namespace Ryujinx.HLE.HOS if (types.Length > 0) { - Logger.Info?.Print(LogClass.ModLoader, $"Found mod '{mod.Name}' [{types}]"); + Logger.Info?.Print(LogClass.ModLoader, $"Found {(mod.Enabled ? "enabled" : "disabled")} mod '{mod.Name}' [{types}]"); } } } diff --git a/ryujinx/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs b/ryujinx/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs deleted file mode 100644 index 66ffd0a49e..0000000000 --- a/ryujinx/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/IMeasurementServer.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Services.Ptm.Ts.Types; - -namespace Ryujinx.HLE.HOS.Services.Ptm.Ts -{ - [Service("ts")] - class IMeasurementServer : IpcService - { - private const uint DefaultTemperature = 42u; - - public IMeasurementServer(ServiceCtx context) { } - - [CommandCmif(1)] - // GetTemperature(Location location) -> u32 - public ResultCode GetTemperature(ServiceCtx context) - { - Location location = (Location)context.RequestData.ReadByte(); - - Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location }); - - context.ResponseData.Write(DefaultTemperature); - - return ResultCode.Success; - } - - [CommandCmif(3)] - // GetTemperatureMilliC(Location location) -> u32 - public ResultCode GetTemperatureMilliC(ServiceCtx context) - { - Location location = (Location)context.RequestData.ReadByte(); - - Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location }); - - context.ResponseData.Write(DefaultTemperature * 1000); - - return ResultCode.Success; - } - } -} diff --git a/ryujinx/src/Ryujinx.Horizon/Ptm/Ipc/MeasurementServer.cs b/ryujinx/src/Ryujinx.Horizon/Ptm/Ipc/MeasurementServer.cs new file mode 100644 index 0000000000..ce7c0474a7 --- /dev/null +++ b/ryujinx/src/Ryujinx.Horizon/Ptm/Ipc/MeasurementServer.cs @@ -0,0 +1,63 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Ts; +using Ryujinx.Horizon.Ts.Ipc; + +namespace Ryujinx.Horizon.Ptm.Ipc +{ + partial class MeasurementServer : IMeasurementServer + { + // NOTE: Values are randomly choosen. + public const int DefaultTemperature = 42; + public const int MinimumTemperature = 0; + public const int MaximumTemperature = 100; + + [CmifCommand(0)] // 1.0.0-16.1.0 + public Result GetTemperatureRange(out int minimumTemperature, out int maximumTemperature, Location location) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location }); + + minimumTemperature = MinimumTemperature; + maximumTemperature = MaximumTemperature; + + return Result.Success; + } + + [CmifCommand(1)] // 1.0.0-16.1.0 + public Result GetTemperature(out int temperature, Location location) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location }); + + temperature = DefaultTemperature; + + return Result.Success; + } + + [CmifCommand(2)] // 1.0.0-13.2.1 + public Result SetMeasurementMode(Location location, byte measurementMode) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location, measurementMode }); + + return Result.Success; + } + + [CmifCommand(3)] // 1.0.0-13.2.1 + public Result GetTemperatureMilliC(out int temperatureMilliC, Location location) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { location }); + + temperatureMilliC = DefaultTemperature * 1000; + + return Result.Success; + } + + [CmifCommand(4)] // 8.0.0+ + public Result OpenSession(out ISession session, DeviceCode deviceCode) + { + session = new Session(deviceCode); + + return Result.Success; + } + } +} diff --git a/ryujinx/src/Ryujinx.Horizon/Ptm/Ipc/Session.cs b/ryujinx/src/Ryujinx.Horizon/Ptm/Ipc/Session.cs new file mode 100644 index 0000000000..191a4b3af6 --- /dev/null +++ b/ryujinx/src/Ryujinx.Horizon/Ptm/Ipc/Session.cs @@ -0,0 +1,47 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Ptm.Ipc; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Ts; + +namespace Ryujinx.Horizon.Ts.Ipc +{ + partial class Session : ISession + { + private readonly DeviceCode _deviceCode; + + public Session(DeviceCode deviceCode) + { + _deviceCode = deviceCode; + } + + [CmifCommand(0)] + public Result GetTemperatureRange(out int minimumTemperature, out int maximumTemperature) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { _deviceCode }); + + minimumTemperature = MeasurementServer.MinimumTemperature; + maximumTemperature = MeasurementServer.MaximumTemperature; + + return Result.Success; + } + + [CmifCommand(2)] + public Result SetMeasurementMode(byte measurementMode) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { _deviceCode, measurementMode }); + + return Result.Success; + } + + [CmifCommand(4)] + public Result GetTemperature(out int temperature) + { + Logger.Stub?.PrintStub(LogClass.ServicePtm, new { _deviceCode }); + + temperature = MeasurementServer.DefaultTemperature; + + return Result.Success; + } + } +} diff --git a/ryujinx/src/Ryujinx.Horizon/Ptm/TsIpcServer.cs b/ryujinx/src/Ryujinx.Horizon/Ptm/TsIpcServer.cs new file mode 100644 index 0000000000..db25d8e2e9 --- /dev/null +++ b/ryujinx/src/Ryujinx.Horizon/Ptm/TsIpcServer.cs @@ -0,0 +1,44 @@ +using Ryujinx.Horizon.Ptm.Ipc; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Ptm +{ + class TsIpcServer + { + private const int MaxSessionsCount = 4; + + private const int PointerBufferSize = 0; + private const int MaxDomains = 0; + private const int MaxDomainObjects = 0; + private const int MaxPortsCount = 1; + + private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); + + private SmApi _sm; + private ServerManager _serverManager; + + public void Initialize() + { + HeapAllocator allocator = new(); + + _sm = new SmApi(); + _sm.Initialize().AbortOnFailure(); + + _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _managerOptions, MaxSessionsCount); + + _serverManager.RegisterObjectForServer(new MeasurementServer(), ServiceName.Encode("ts"), MaxSessionsCount); + } + + public void ServiceRequests() + { + _serverManager.ServiceRequests(); + } + + public void Shutdown() + { + _serverManager.Dispose(); + _sm.Dispose(); + } + } +} diff --git a/ryujinx/src/Ryujinx.Horizon/Ptm/TsMain.cs b/ryujinx/src/Ryujinx.Horizon/Ptm/TsMain.cs new file mode 100644 index 0000000000..237d52cd4c --- /dev/null +++ b/ryujinx/src/Ryujinx.Horizon/Ptm/TsMain.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Horizon.Ptm +{ + class TsMain : IService + { + public static void Main(ServiceTable serviceTable) + { + TsIpcServer ipcServer = new(); + + ipcServer.Initialize(); + + serviceTable.SignalServiceReady(); + + ipcServer.ServiceRequests(); + ipcServer.Shutdown(); + } + } +} diff --git a/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/DeviceCode.cs b/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/DeviceCode.cs new file mode 100644 index 0000000000..4fce4238ee --- /dev/null +++ b/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/DeviceCode.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sdk.Ts +{ + enum DeviceCode : uint + { + Internal = 0x41000001, + External = 0x41000002, + } +} diff --git a/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/IMeasurementServer.cs b/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/IMeasurementServer.cs new file mode 100644 index 0000000000..ba9c2a748d --- /dev/null +++ b/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/IMeasurementServer.cs @@ -0,0 +1,14 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Ts +{ + interface IMeasurementServer : IServiceObject + { + Result GetTemperatureRange(out int minimumTemperature, out int maximumTemperature, Location location); + Result GetTemperature(out int temperature, Location location); + Result SetMeasurementMode(Location location, byte measurementMode); + Result GetTemperatureMilliC(out int temperatureMilliC, Location location); + Result OpenSession(out ISession session, DeviceCode deviceCode); + } +} diff --git a/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/ISession.cs b/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/ISession.cs new file mode 100644 index 0000000000..23c0d94f64 --- /dev/null +++ b/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/ISession.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Ts +{ + interface ISession : IServiceObject + { + Result GetTemperatureRange(out int minimumTemperature, out int maximumTemperature); + Result GetTemperature(out int temperature); + Result SetMeasurementMode(byte measurementMode); + } +} diff --git a/ryujinx/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/Types/Location.cs b/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/Location.cs similarity index 61% rename from ryujinx/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/Types/Location.cs rename to ryujinx/src/Ryujinx.Horizon/Sdk/Ts/Location.cs index 409188a979..177b0ee880 100644 --- a/ryujinx/src/Ryujinx.HLE/HOS/Services/Ptm/Ts/Types/Location.cs +++ b/ryujinx/src/Ryujinx.Horizon/Sdk/Ts/Location.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Ptm.Ts.Types +namespace Ryujinx.Horizon.Sdk.Ts { enum Location : byte { diff --git a/ryujinx/src/Ryujinx.Horizon/ServiceTable.cs b/ryujinx/src/Ryujinx.Horizon/ServiceTable.cs index b81e62a474..28c43a716f 100644 --- a/ryujinx/src/Ryujinx.Horizon/ServiceTable.cs +++ b/ryujinx/src/Ryujinx.Horizon/ServiceTable.cs @@ -11,6 +11,7 @@ using Ryujinx.Horizon.Ngc; using Ryujinx.Horizon.Ovln; using Ryujinx.Horizon.Prepo; using Ryujinx.Horizon.Psc; +using Ryujinx.Horizon.Ptm; using Ryujinx.Horizon.Sdk.Arp; using Ryujinx.Horizon.Srepo; using Ryujinx.Horizon.Usb; @@ -54,6 +55,7 @@ namespace Ryujinx.Horizon RegisterService(); RegisterService(); RegisterService(); + RegisterService(); RegisterService(); RegisterService(); diff --git a/ryujinx/src/Ryujinx.Memory/AddressSpaceManager.cs b/ryujinx/src/Ryujinx.Memory/AddressSpaceManager.cs index f089c85736..807c5c0f40 100644 --- a/ryujinx/src/Ryujinx.Memory/AddressSpaceManager.cs +++ b/ryujinx/src/Ryujinx.Memory/AddressSpaceManager.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Memory public sealed class AddressSpaceManager : VirtualMemoryManagerBase, IVirtualMemoryManager { /// - public bool Supports4KBPages => true; + public bool UsesPrivateAllocations => false; /// /// Address space width in bits. diff --git a/ryujinx/src/Ryujinx.Memory/IVirtualMemoryManager.cs b/ryujinx/src/Ryujinx.Memory/IVirtualMemoryManager.cs index 96d3e85797..102cedc94e 100644 --- a/ryujinx/src/Ryujinx.Memory/IVirtualMemoryManager.cs +++ b/ryujinx/src/Ryujinx.Memory/IVirtualMemoryManager.cs @@ -8,10 +8,10 @@ namespace Ryujinx.Memory public interface IVirtualMemoryManager { /// - /// Indicates whenever the memory manager supports aliasing pages at 4KB granularity. + /// Indicates whether the memory manager creates private allocations when the flag is set on map. /// - /// True if 4KB pages are supported by the memory manager, false otherwise - bool Supports4KBPages { get; } + /// True if private mappings might be used, false otherwise + bool UsesPrivateAllocations { get; } /// /// Maps a virtual memory range into a physical memory range. diff --git a/ryujinx/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs b/ryujinx/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs index 15e7d9b89a..3fe44db218 100644 --- a/ryujinx/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs +++ b/ryujinx/src/Ryujinx.Tests.Memory/MockVirtualMemoryManager.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Tests.Memory { public class MockVirtualMemoryManager : IVirtualMemoryManager { - public bool Supports4KBPages => true; + public bool UsesPrivateAllocations => false; public bool NoMappings = false; diff --git a/ryujinx/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs b/ryujinx/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs index 0f6c21ef24..3387e1be13 100644 --- a/ryujinx/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs +++ b/ryujinx/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs @@ -15,7 +15,7 @@ namespace Ryujinx.UI.Common.Configuration /// /// The current version of the file format /// - public const int CurrentVersion = 49; + public const int CurrentVersion = 50; /// /// Version of the configuration file format @@ -162,6 +162,11 @@ namespace Ryujinx.UI.Common.Configuration /// public bool ShowConfirmExit { get; set; } + /// + /// Enables hardware-accelerated rendering for Avalonia + /// + public bool EnableHardwareAcceleration { get; set; } + /// /// Whether to hide cursor on idle, always or never /// diff --git a/ryujinx/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs b/ryujinx/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs index b7f36087cb..2609dc9baa 100644 --- a/ryujinx/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs +++ b/ryujinx/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs @@ -626,6 +626,11 @@ namespace Ryujinx.UI.Common.Configuration /// public ReactiveObject ShowConfirmExit { get; private set; } + /// + /// Enables hardware-accelerated rendering for Avalonia + /// + public ReactiveObject EnableHardwareAcceleration { get; private set; } + /// /// Hide Cursor on Idle /// @@ -642,6 +647,7 @@ namespace Ryujinx.UI.Common.Configuration EnableDiscordIntegration = new ReactiveObject(); CheckUpdatesOnStart = new ReactiveObject(); ShowConfirmExit = new ReactiveObject(); + EnableHardwareAcceleration = new ReactiveObject(); HideCursor = new ReactiveObject(); } @@ -678,6 +684,7 @@ namespace Ryujinx.UI.Common.Configuration EnableDiscordIntegration = EnableDiscordIntegration, CheckUpdatesOnStart = CheckUpdatesOnStart, ShowConfirmExit = ShowConfirmExit, + EnableHardwareAcceleration = EnableHardwareAcceleration, HideCursor = HideCursor, EnableVsync = Graphics.EnableVsync, EnableShaderCache = Graphics.EnableShaderCache, @@ -785,6 +792,7 @@ namespace Ryujinx.UI.Common.Configuration EnableDiscordIntegration.Value = true; CheckUpdatesOnStart.Value = true; ShowConfirmExit.Value = true; + EnableHardwareAcceleration.Value = true; HideCursor.Value = HideCursorMode.OnIdle; Graphics.EnableVsync.Value = true; Graphics.EnableShaderCache.Value = true; @@ -1442,6 +1450,15 @@ namespace Ryujinx.UI.Common.Configuration configurationFileUpdated = true; } + if (configurationFileFormat.Version < 50) + { + Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 50."); + + configurationFileFormat.EnableHardwareAcceleration = true; + + configurationFileUpdated = true; + } + Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog; Graphics.ResScale.Value = configurationFileFormat.ResScale; Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom; @@ -1472,6 +1489,7 @@ namespace Ryujinx.UI.Common.Configuration EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration; CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart; ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit; + EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration; HideCursor.Value = configurationFileFormat.HideCursor; Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync; Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache; diff --git a/ryujinx/src/Ryujinx.UI.Common/Helper/CommandLineState.cs b/ryujinx/src/Ryujinx.UI.Common/Helper/CommandLineState.cs index c3c5bd37e9..6de963a74a 100644 --- a/ryujinx/src/Ryujinx.UI.Common/Helper/CommandLineState.cs +++ b/ryujinx/src/Ryujinx.UI.Common/Helper/CommandLineState.cs @@ -8,6 +8,7 @@ namespace Ryujinx.UI.Common.Helper public static string[] Arguments { get; private set; } public static bool? OverrideDockedMode { get; private set; } + public static bool? OverrideHardwareAcceleration { get; private set; } public static string OverrideGraphicsBackend { get; private set; } public static string OverrideHideCursor { get; private set; } public static string BaseDirPathArg { get; private set; } @@ -87,6 +88,12 @@ namespace Ryujinx.UI.Common.Helper OverrideHideCursor = args[++i]; break; + case "--software-gui": + OverrideHardwareAcceleration = false; + break; + case "--hardware-gui": + OverrideHardwareAcceleration = true; + break; default: LaunchPathArg = arg; break; diff --git a/ryujinx/src/Ryujinx/Program.cs b/ryujinx/src/Ryujinx/Program.cs index aecc585fcb..4a30aee9ca 100644 --- a/ryujinx/src/Ryujinx/Program.cs +++ b/ryujinx/src/Ryujinx/Program.cs @@ -60,12 +60,16 @@ namespace Ryujinx.Ava EnableMultiTouch = true, EnableIme = true, EnableInputFocusProxy = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP") == "gamescope", - RenderingMode = new[] { X11RenderingMode.Glx, X11RenderingMode.Software }, + RenderingMode = ConfigurationState.Instance.EnableHardwareAcceleration ? + new[] { X11RenderingMode.Glx, X11RenderingMode.Software } : + new[] { X11RenderingMode.Software }, }) .With(new Win32PlatformOptions { WinUICompositionBackdropCornerRadius = 8.0f, - RenderingMode = new[] { Win32RenderingMode.AngleEgl, Win32RenderingMode.Software }, + RenderingMode = ConfigurationState.Instance.EnableHardwareAcceleration ? + new[] { Win32RenderingMode.AngleEgl, Win32RenderingMode.Software } : + new[] { Win32RenderingMode.Software }, }) .UseSkia(); } @@ -191,6 +195,12 @@ namespace Ryujinx.Ava _ => ConfigurationState.Instance.HideCursor.Value, }; } + + // Check if hardware-acceleration was overridden. + if (CommandLineState.OverrideHardwareAcceleration != null) + { + ConfigurationState.Instance.EnableHardwareAcceleration.Value = CommandLineState.OverrideHardwareAcceleration.Value; + } } private static void PrintSystemInfo() diff --git a/ryujinx/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/ryujinx/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index 17bd69b14c..036a536e5c 100644 --- a/ryujinx/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/ryujinx/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -36,6 +36,7 @@ using SixLabors.ImageSharp.PixelFormats; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -980,7 +981,14 @@ namespace Ryujinx.Ava.UI.ViewModels { if (arg is ApplicationData app) { - return string.IsNullOrWhiteSpace(_searchText) || app.TitleName.ToLower().Contains(_searchText.ToLower()); + if (string.IsNullOrWhiteSpace(_searchText)) + { + return true; + } + + CompareInfo compareInfo = CultureInfo.CurrentCulture.CompareInfo; + + return compareInfo.IndexOf(app.TitleName, _searchText, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0; } return false; diff --git a/ryujinx/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/ryujinx/src/Ryujinx/UI/Windows/MainWindow.axaml.cs index 33a9af5b61..37e2e71a8c 100644 --- a/ryujinx/src/Ryujinx/UI/Windows/MainWindow.axaml.cs +++ b/ryujinx/src/Ryujinx/UI/Windows/MainWindow.axaml.cs @@ -285,7 +285,7 @@ namespace Ryujinx.Ava.UI.Windows { _deferLoad = false; - ViewModel.LoadApplication(_launchPath, _startFullscreen).Wait(); + await ViewModel.LoadApplication(_launchPath, _startFullscreen); } } else diff --git a/shadowsocks-rust/Cargo.lock b/shadowsocks-rust/Cargo.lock index 39d9debccb..8cc41c00d2 100644 --- a/shadowsocks-rust/Cargo.lock +++ b/shadowsocks-rust/Cargo.lock @@ -785,9 +785,9 @@ dependencies = [ [[package]] name = "etherparse" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24890603eb4b43aa788f02261ce21714449033e3e2ab93692f0ab18480c3c9b1" +checksum = "095ab548cf452be5813424558a18af88f0a620d0f4a3d8793aa09311a3b6fa5f" dependencies = [ "arrayvec", ] @@ -1219,15 +1219,6 @@ dependencies = [ "digest", ] -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "hostname" version = "0.3.1" @@ -2190,12 +2181,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettyplease" -version = "0.1.25" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" dependencies = [ "proc-macro2", - "syn 1.0.109", + "syn 2.0.57", ] [[package]] @@ -2242,9 +2233,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.9" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" dependencies = [ "bytes", "prost-derive", @@ -2252,44 +2243,43 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.9" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", "heck", "itertools", - "lazy_static", "log", "multimap", + "once_cell", "petgraph", "prettyplease", "prost", "prost-types", "regex", - "syn 1.0.109", + "syn 2.0.57", "tempfile", - "which", ] [[package]] name = "prost-derive" -version = "0.11.9" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.57", ] [[package]] name = "prost-types" -version = "0.11.9" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" dependencies = [ "prost", ] @@ -3842,18 +3832,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "widestring" version = "1.0.2" diff --git a/shadowsocks-rust/crates/shadowsocks-service/Cargo.toml b/shadowsocks-rust/crates/shadowsocks-service/Cargo.toml index 72577c9fd2..d223e01895 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/Cargo.toml +++ b/shadowsocks-rust/crates/shadowsocks-service/Cargo.toml @@ -131,7 +131,7 @@ byte_string = "1.0" byteorder = "1.5" rand = { version = "0.8", features = ["small_rng"] } sled = { version = "0.34.7", features = ["compression"], optional = true } -prost = { version = "0.11.9", optional = true } +prost = { version = "0.12.4", optional = true } futures = "0.3" tokio = { version = "1.5", features = [ @@ -191,7 +191,7 @@ nix = { version = "0.28", features = ["ioctl"] } windows-sys = { version = "0.52", features = ["Win32_Networking_WinSock"] } [build-dependencies] -prost-build = { version = "0.11.9", optional = true } +prost-build = { version = "0.12.4", optional = true } [dev-dependencies] byteorder = "1.5" diff --git a/shadowsocks-rust/crates/shadowsocks/Cargo.toml b/shadowsocks-rust/crates/shadowsocks/Cargo.toml index 20250235b8..4c8161ccce 100644 --- a/shadowsocks-rust/crates/shadowsocks/Cargo.toml +++ b/shadowsocks-rust/crates/shadowsocks/Cargo.toml @@ -81,7 +81,6 @@ tokio = { version = "1.9.0", features = [ "sync", "time", ] } -tokio-tfo = "0.2.0" hickory-resolver = { version = "0.24", optional = true } arc-swap = { version = "1.7", optional = true } @@ -96,6 +95,9 @@ shadowsocks-crypto = { version = "0.5.4", features = ["ring"] } [target.'cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))'.dependencies] shadowsocks-crypto = { version = "0.5.4", features = [] } +[target.'cfg(any(windows, target_os = "linux", target_os = "android", target_os = "freebsd", target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))'.dependencies] +tokio-tfo = "0.2.0" + [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.52", features = [ "Win32_Foundation", diff --git a/v2rayn/v2rayN/v2rayN/Models/ConfigItems.cs b/v2rayn/v2rayN/v2rayN/Models/ConfigItems.cs index 729d024ff9..5e3b8d584e 100644 --- a/v2rayn/v2rayN/v2rayN/Models/ConfigItems.cs +++ b/v2rayn/v2rayN/v2rayN/Models/ConfigItems.cs @@ -122,7 +122,7 @@ namespace v2rayN.Models public int currentFontSize { get; set; } public bool enableDragDropSort { get; set; } public bool doubleClick2Activate { get; set; } - public bool autoHideStartup { get; set; } = true; + public bool autoHideStartup { get; set; } public string mainMsgFilter { get; set; } public List mainColumnItem { get; set; } } diff --git a/yt-dlp/README.md b/yt-dlp/README.md index d4dd2c7be5..ee1b599900 100644 --- a/yt-dlp/README.md +++ b/yt-dlp/README.md @@ -1784,8 +1784,7 @@ The following extractors use this feature: * `version`: The video version to extract - `uncut` or `simulcast` #### crunchyrollbeta (Crunchyroll) -* `format`: Which stream type(s) to extract (default: `adaptive_hls`). Potentially useful values include `adaptive_hls`, `adaptive_dash`, `vo_adaptive_hls`, `vo_adaptive_dash`, `download_hls`, `download_dash`, `multitrack_adaptive_hls_v2` -* `hardsub`: Preference order for which hardsub versions to extract, or `all` (default: `None` = no hardsubs), e.g. `crunchyrollbeta:hardsub=en-US,None` +* `hardsub`: One or more hardsub versions to extract (in order of preference), or `all` (default: `None` = no hardsubs will be extracted), e.g. `crunchyrollbeta:hardsub=en-US,de-DE` #### vikichannel * `video_types`: Types of videos to download - one or more of `episodes`, `movies`, `clips`, `trailers` diff --git a/yt-dlp/yt_dlp/extractor/afreecatv.py b/yt-dlp/yt_dlp/extractor/afreecatv.py index 86e69a68ec..2c33c90dbb 100644 --- a/yt-dlp/yt_dlp/extractor/afreecatv.py +++ b/yt-dlp/yt_dlp/extractor/afreecatv.py @@ -1,20 +1,16 @@ import functools -import re from .common import InfoExtractor from ..utils import ( ExtractorError, OnDemandPagedList, UserNotLive, - date_from_str, determine_ext, filter_dict, int_or_none, - unified_strdate, unified_timestamp, url_or_none, urlencode_postdata, - xpath_text, ) from ..utils.traversal import traverse_obj @@ -76,7 +72,6 @@ class AfreecaTVIE(AfreecaTVBaseIE): ) (?P\d+) ''' - _NETRC_MACHINE = 'afreecatv' _TESTS = [{ 'url': 'http://live.afreecatv.com:8079/app/index.cgi?szType=read_ucc_bbs&szBjId=dailyapril&nStationNo=16711924&nBbsNo=18605867&nTitleNo=36164052&szSkin=', 'md5': 'f72c89fe7ecc14c1b5ce506c4996046e', @@ -129,6 +124,7 @@ class AfreecaTVIE(AfreecaTVBaseIE): 'uploader': '♥이슬이', 'uploader_id': 'dasl8121', 'upload_date': '20170411', + 'timestamp': 1491929865, 'duration': 213, }, 'params': { @@ -162,176 +158,97 @@ class AfreecaTVIE(AfreecaTVBaseIE): 'uploader_id': 'rlantnghks', 'uploader': '페이즈으', 'duration': 10840, - 'thumbnail': 'http://videoimg.afreecatv.com/php/SnapshotLoad.php?rowKey=20230108_9FF5BEE1_244432674_1_r', + 'thumbnail': r're:https?://videoimg\.afreecatv\.com/.+', 'upload_date': '20230108', + 'timestamp': 1673218805, 'title': '젠지 페이즈', }, 'params': { 'skip_download': True, }, + }, { + # adult content + 'url': 'https://vod.afreecatv.com/player/70395877', + 'only_matching': True, + }, { + # subscribers only + 'url': 'https://vod.afreecatv.com/player/104647403', + 'only_matching': True, + }, { + # private + 'url': 'https://vod.afreecatv.com/player/81669846', + 'only_matching': True, }] - @staticmethod - def parse_video_key(key): - video_key = {} - m = re.match(r'^(?P\d{8})_\w+_(?P\d+)$', key) - if m: - video_key['upload_date'] = m.group('upload_date') - video_key['part'] = int(m.group('part')) - return video_key - def _real_extract(self, url): video_id = self._match_id(url) - - partial_view = False - adult_view = False - for _ in range(2): - data = self._download_json( - 'https://api.m.afreecatv.com/station/video/a/view', - video_id, headers={'Referer': url}, data=urlencode_postdata({ - 'nTitleNo': video_id, - 'nApiLevel': 10, - }))['data'] - if traverse_obj(data, ('code', {int})) == -6221: - raise ExtractorError('The VOD does not exist', expected=True) - query = { + data = self._download_json( + 'https://api.m.afreecatv.com/station/video/a/view', video_id, + headers={'Referer': url}, data=urlencode_postdata({ 'nTitleNo': video_id, - 'nStationNo': data['station_no'], - 'nBbsNo': data['bbs_no'], - } - if partial_view: - query['partialView'] = 'SKIP_ADULT' - if adult_view: - query['adultView'] = 'ADULT_VIEW' - video_xml = self._download_xml( - 'http://afbbs.afreecatv.com:8080/api/video/get_video_info.php', - video_id, 'Downloading video info XML%s' - % (' (skipping adult)' if partial_view else ''), - video_id, headers={ - 'Referer': url, - }, query=query) + 'nApiLevel': 10, + }))['data'] - flag = xpath_text(video_xml, './track/flag', 'flag', default=None) - if flag and flag == 'SUCCEED': - break - if flag == 'PARTIAL_ADULT': - self.report_warning( - 'In accordance with local laws and regulations, underage users are restricted from watching adult content. ' - 'Only content suitable for all ages will be downloaded. ' - 'Provide account credentials if you wish to download restricted content.') - partial_view = True - continue - elif flag == 'ADULT': - if not adult_view: - adult_view = True - continue - error = 'Only users older than 19 are able to watch this video. Provide account credentials to download this content.' - else: - error = flag - raise ExtractorError( - '%s said: %s' % (self.IE_NAME, error), expected=True) - else: - raise ExtractorError('Unable to download video info') + error_code = traverse_obj(data, ('code', {int})) + if error_code == -6221: + raise ExtractorError('The VOD does not exist', expected=True) + elif error_code == -6205: + raise ExtractorError('This VOD is private', expected=True) - video_element = video_xml.findall('./track/video')[-1] - if video_element is None or video_element.text is None: - raise ExtractorError( - 'Video %s does not exist' % video_id, expected=True) - - video_url = video_element.text.strip() - - title = xpath_text(video_xml, './track/title', 'title', fatal=True) - - uploader = xpath_text(video_xml, './track/nickname', 'uploader') - uploader_id = xpath_text(video_xml, './track/bj_id', 'uploader id') - duration = int_or_none(xpath_text( - video_xml, './track/duration', 'duration')) - thumbnail = xpath_text(video_xml, './track/titleImage', 'thumbnail') - - common_entry = { - 'uploader': uploader, - 'uploader_id': uploader_id, - 'thumbnail': thumbnail, - } - - info = common_entry.copy() - info.update({ - 'id': video_id, - 'title': title, - 'duration': duration, + common_info = traverse_obj(data, { + 'title': ('title', {str}), + 'uploader': ('writer_nick', {str}), + 'uploader_id': ('bj_id', {str}), + 'duration': ('total_file_duration', {functools.partial(int_or_none, scale=1000)}), + 'thumbnail': ('thumb', {url_or_none}), }) - if not video_url: - entries = [] - file_elements = video_element.findall('./file') - one = len(file_elements) == 1 - for file_num, file_element in enumerate(file_elements, start=1): - file_url = url_or_none(file_element.text) - if not file_url: - continue - key = file_element.get('key', '') - upload_date = unified_strdate(self._search_regex( - r'^(\d{8})_', key, 'upload date', default=None)) - if upload_date is not None: - # sometimes the upload date isn't included in the file name - # instead, another random ID is, which may parse as a valid - # date but be wildly out of a reasonable range - parsed_date = date_from_str(upload_date) - if parsed_date.year < 2000 or parsed_date.year >= 2100: - upload_date = None - file_duration = int_or_none(file_element.get('duration')) - format_id = key if key else '%s_%s' % (video_id, file_num) - if determine_ext(file_url) == 'm3u8': - formats = self._extract_m3u8_formats( - file_url, video_id, 'mp4', entry_protocol='m3u8_native', - m3u8_id='hls', - note='Downloading part %d m3u8 information' % file_num) - else: - formats = [{ - 'url': file_url, - 'format_id': 'http', - }] - if not formats and not self.get_param('ignore_no_formats'): - continue - file_info = common_entry.copy() - file_info.update({ - 'id': format_id, - 'title': title if one else '%s (part %d)' % (title, file_num), - 'upload_date': upload_date, - 'duration': file_duration, - 'formats': formats, + entries = [] + for file_num, file_element in enumerate( + traverse_obj(data, ('files', lambda _, v: url_or_none(v['file']))), start=1): + file_url = file_element['file'] + if determine_ext(file_url) == 'm3u8': + formats = self._extract_m3u8_formats( + file_url, video_id, 'mp4', m3u8_id='hls', + note=f'Downloading part {file_num} m3u8 information') + else: + formats = [{ + 'url': file_url, + 'format_id': 'http', + }] + + entries.append({ + **common_info, + 'id': file_element.get('file_info_key') or f'{video_id}_{file_num}', + 'title': f'{common_info.get("title") or "Untitled"} (part {file_num})', + 'formats': formats, + **traverse_obj(file_element, { + 'duration': ('duration', {functools.partial(int_or_none, scale=1000)}), + 'timestamp': ('file_start', {unified_timestamp}), }) - entries.append(file_info) - entries_info = info.copy() - entries_info.update({ - '_type': 'multi_video', - 'entries': entries, - }) - return entries_info - - info = { - 'id': video_id, - 'title': title, - 'uploader': uploader, - 'uploader_id': uploader_id, - 'duration': duration, - 'thumbnail': thumbnail, - } - - if determine_ext(video_url) == 'm3u8': - info['formats'] = self._extract_m3u8_formats( - video_url, video_id, 'mp4', entry_protocol='m3u8_native', - m3u8_id='hls') - else: - app, playpath = video_url.split('mp4:') - info.update({ - 'url': app, - 'ext': 'flv', - 'play_path': 'mp4:' + playpath, - 'rtmp_live': True, # downloading won't end without this }) - return info + if traverse_obj(data, ('adult_status', {str})) == 'notLogin': + if not entries: + self.raise_login_required( + 'Only users older than 19 are able to watch this video', method='password') + self.report_warning( + 'In accordance with local laws and regulations, underage users are ' + 'restricted from watching adult content. Only content suitable for all ' + f'ages will be downloaded. {self._login_hint("password")}') + + if not entries and traverse_obj(data, ('sub_upload_type', {str})): + self.raise_login_required('This VOD is for subscribers only', method='password') + + if len(entries) == 1: + return { + **entries[0], + 'title': common_info.get('title'), + } + + common_info['timestamp'] = traverse_obj(entries, (..., 'timestamp'), get_all=False) + + return self.playlist_result(entries, video_id, multi_video=True, **common_info) class AfreecaTVLiveIE(AfreecaTVBaseIE): diff --git a/yt-dlp/yt_dlp/extractor/crunchyroll.py b/yt-dlp/yt_dlp/extractor/crunchyroll.py index d35e9995ab..118b575ab2 100644 --- a/yt-dlp/yt_dlp/extractor/crunchyroll.py +++ b/yt-dlp/yt_dlp/extractor/crunchyroll.py @@ -1,4 +1,5 @@ import base64 +import uuid from .common import InfoExtractor from ..networking.exceptions import HTTPError @@ -7,12 +8,11 @@ from ..utils import ( float_or_none, format_field, int_or_none, - join_nonempty, + jwt_decode_hs256, parse_age_limit, parse_count, parse_iso8601, qualities, - remove_start, time_seconds, traverse_obj, url_or_none, @@ -27,6 +27,7 @@ class CrunchyrollBaseIE(InfoExtractor): _AUTH_HEADERS = None _API_ENDPOINT = None _BASIC_AUTH = None + _IS_PREMIUM = None _CLIENT_ID = ('cr_web', 'noaihdevm_6iyg0a8l0q') _LOCALE_LOOKUP = { 'ar': 'ar-SA', @@ -84,11 +85,16 @@ class CrunchyrollBaseIE(InfoExtractor): self.write_debug(f'Using cxApiParam={cx_api_param}') CrunchyrollBaseIE._BASIC_AUTH = 'Basic ' + base64.b64encode(f'{cx_api_param}:'.encode()).decode() - grant_type = 'etp_rt_cookie' if self.is_logged_in else 'client_id' + auth_headers = {'Authorization': CrunchyrollBaseIE._BASIC_AUTH} + if self.is_logged_in: + grant_type = 'etp_rt_cookie' + else: + grant_type = 'client_id' + auth_headers['ETP-Anonymous-ID'] = uuid.uuid4() try: auth_response = self._download_json( f'{self._BASE_URL}/auth/v1/token', None, note=f'Authenticating with grant_type={grant_type}', - headers={'Authorization': CrunchyrollBaseIE._BASIC_AUTH}, data=f'grant_type={grant_type}'.encode()) + headers=auth_headers, data=f'grant_type={grant_type}'.encode()) except ExtractorError as error: if isinstance(error.cause, HTTPError) and error.cause.status == 403: raise ExtractorError( @@ -97,6 +103,7 @@ class CrunchyrollBaseIE(InfoExtractor): 'and your browser\'s User-Agent (with --user-agent)', expected=True) raise + CrunchyrollBaseIE._IS_PREMIUM = 'cr_premium' in traverse_obj(auth_response, ('access_token', {jwt_decode_hs256}, 'benefits', ...)) CrunchyrollBaseIE._AUTH_HEADERS = {'Authorization': auth_response['token_type'] + ' ' + auth_response['access_token']} CrunchyrollBaseIE._AUTH_REFRESH = time_seconds(seconds=traverse_obj(auth_response, ('expires_in', {float_or_none}), default=300) - 10) @@ -135,62 +142,72 @@ class CrunchyrollBaseIE(InfoExtractor): raise ExtractorError(f'Unexpected response when downloading {note} JSON') return result - def _extract_formats(self, stream_response, display_id=None): - requested_formats = self._configuration_arg('format') or ['vo_adaptive_hls'] - available_formats = {} - for stream_type, streams in traverse_obj( - stream_response, (('streams', ('data', 0)), {dict.items}, ...)): - if stream_type not in requested_formats: + def _extract_chapters(self, internal_id): + # if no skip events are available, a 403 xml error is returned + skip_events = self._download_json( + f'https://static.crunchyroll.com/skip-events/production/{internal_id}.json', + internal_id, note='Downloading chapter info', fatal=False, errnote=False) + if not skip_events: + return None + + chapters = [] + for event in ('recap', 'intro', 'credits', 'preview'): + start = traverse_obj(skip_events, (event, 'start', {float_or_none})) + end = traverse_obj(skip_events, (event, 'end', {float_or_none})) + # some chapters have no start and/or ending time, they will just be ignored + if start is None or end is None: continue - for stream in traverse_obj(streams, lambda _, v: v['url']): - hardsub_lang = stream.get('hardsub_locale') or '' - format_id = join_nonempty(stream_type, format_field(stream, 'hardsub_locale', 'hardsub-%s')) - available_formats[hardsub_lang] = (stream_type, format_id, hardsub_lang, stream['url']) + chapters.append({'title': event.capitalize(), 'start_time': start, 'end_time': end}) + + return chapters + + def _extract_stream(self, identifier, display_id=None): + if not display_id: + display_id = identifier + + self._update_auth() + stream_response = self._download_json( + f'https://cr-play-service.prd.crunchyrollsvc.com/v1/{identifier}/console/switch/play', + display_id, note='Downloading stream info', headers=CrunchyrollBaseIE._AUTH_HEADERS) + + available_formats = {'': ('', '', stream_response['url'])} + for hardsub_lang, stream in traverse_obj(stream_response, ('hardSubs', {dict.items}, lambda _, v: v[1]['url'])): + available_formats[hardsub_lang] = (f'hardsub-{hardsub_lang}', hardsub_lang, stream['url']) requested_hardsubs = [('' if val == 'none' else val) for val in (self._configuration_arg('hardsub') or ['none'])] - if '' in available_formats and 'all' not in requested_hardsubs: + hardsub_langs = [lang for lang in available_formats if lang] + if hardsub_langs and 'all' not in requested_hardsubs: full_format_langs = set(requested_hardsubs) + self.to_screen(f'Available hardsub languages: {", ".join(hardsub_langs)}') self.to_screen( - 'To get all formats of a hardsub language, use ' + 'To extract formats of a hardsub language, use ' '"--extractor-args crunchyrollbeta:hardsub=". ' 'See https://github.com/yt-dlp/yt-dlp#crunchyrollbeta-crunchyroll for more info', only_once=True) else: full_format_langs = set(map(str.lower, available_formats)) - audio_locale = traverse_obj(stream_response, ((None, 'meta'), 'audio_locale'), get_all=False) + audio_locale = traverse_obj(stream_response, ('audioLocale', {str})) hardsub_preference = qualities(requested_hardsubs[::-1]) - formats = [] - for stream_type, format_id, hardsub_lang, stream_url in available_formats.values(): - if stream_type.endswith('hls'): - if hardsub_lang.lower() in full_format_langs: - adaptive_formats = self._extract_m3u8_formats( - stream_url, display_id, 'mp4', m3u8_id=format_id, - fatal=False, note=f'Downloading {format_id} HLS manifest') - else: - adaptive_formats = (self._m3u8_meta_format(stream_url, ext='mp4', m3u8_id=format_id),) - elif stream_type.endswith('dash'): - adaptive_formats = self._extract_mpd_formats( - stream_url, display_id, mpd_id=format_id, - fatal=False, note=f'Downloading {format_id} MPD manifest') + formats, subtitles = [], {} + for format_id, hardsub_lang, stream_url in available_formats.values(): + if hardsub_lang.lower() in full_format_langs: + adaptive_formats, dash_subs = self._extract_mpd_formats_and_subtitles( + stream_url, display_id, mpd_id=format_id, headers=CrunchyrollBaseIE._AUTH_HEADERS, + fatal=False, note=f'Downloading {f"{format_id} " if hardsub_lang else ""}MPD manifest') + self._merge_subtitles(dash_subs, target=subtitles) else: - self.report_warning(f'Encountered unknown stream_type: {stream_type!r}', display_id, only_once=True) - continue + continue # XXX: Update this if/when meta mpd formats are working for f in adaptive_formats: if f.get('acodec') != 'none': f['language'] = audio_locale f['quality'] = hardsub_preference(hardsub_lang.lower()) formats.extend(adaptive_formats) - return formats + for locale, subtitle in traverse_obj(stream_response, (('subtitles', 'captions'), {dict.items}, ...)): + subtitles.setdefault(locale, []).append(traverse_obj(subtitle, {'url': 'url', 'ext': 'format'})) - def _extract_subtitles(self, data): - subtitles = {} - - for locale, subtitle in traverse_obj(data, ((None, 'meta'), 'subtitles', {dict.items}, ...)): - subtitles[locale] = [traverse_obj(subtitle, {'url': 'url', 'ext': 'format'})] - - return subtitles + return formats, subtitles class CrunchyrollCmsBaseIE(CrunchyrollBaseIE): @@ -245,7 +262,11 @@ class CrunchyrollBetaIE(CrunchyrollCmsBaseIE): 'like_count': int, 'dislike_count': int, }, - 'params': {'skip_download': 'm3u8', 'format': 'all[format_id~=hardsub]'}, + 'params': { + 'skip_download': 'm3u8', + 'extractor_args': {'crunchyrollbeta': {'hardsub': ['de-DE']}}, + 'format': 'bv[format_id~=hardsub]', + }, }, { # Premium only 'url': 'https://www.crunchyroll.com/watch/GYE5WKQGR', @@ -306,6 +327,7 @@ class CrunchyrollBetaIE(CrunchyrollCmsBaseIE): 'thumbnail': r're:^https://www.crunchyroll.com/imgsrv/.*\.jpeg?$', }, 'params': {'skip_download': 'm3u8'}, + 'skip': 'no longer exists', }, { 'url': 'https://www.crunchyroll.com/watch/G62PEZ2E6', 'info_dict': { @@ -359,31 +381,15 @@ class CrunchyrollBetaIE(CrunchyrollCmsBaseIE): else: raise ExtractorError(f'Unknown object type {object_type}') - # There might be multiple audio languages for one object (`_metadata.versions`), - # so we need to get the id from `streams_link` instead or we dont know which language to choose - streams_link = response.get('streams_link') - if not streams_link and traverse_obj(response, (f'{object_type}_metadata', 'is_premium_only')): + if not self._IS_PREMIUM and traverse_obj(response, (f'{object_type}_metadata', 'is_premium_only')): message = f'This {object_type} is for premium members only' if self.is_logged_in: raise ExtractorError(message, expected=True) self.raise_login_required(message) - # We need go from unsigned to signed api to avoid getting soft banned - stream_response = self._call_cms_api_signed(remove_start( - streams_link, '/content/v2/cms/'), internal_id, lang, 'stream info') - result['formats'] = self._extract_formats(stream_response, internal_id) - result['subtitles'] = self._extract_subtitles(stream_response) + result['formats'], result['subtitles'] = self._extract_stream(internal_id) - # if no intro chapter is available, a 403 without usable data is returned - intro_chapter = self._download_json( - f'https://static.crunchyroll.com/datalab-intro-v2/{internal_id}.json', - internal_id, note='Downloading chapter info', fatal=False, errnote=False) - if isinstance(intro_chapter, dict): - result['chapters'] = [{ - 'title': 'Intro', - 'start_time': float_or_none(intro_chapter.get('startTime')), - 'end_time': float_or_none(intro_chapter.get('endTime')), - }] + result['chapters'] = self._extract_chapters(internal_id) def calculate_count(item): return parse_count(''.join((item['displayed'], item.get('unit') or ''))) @@ -512,7 +518,7 @@ class CrunchyrollMusicIE(CrunchyrollBaseIE): 'display_id': 'egaono-hana', 'title': 'Egaono Hana', 'track': 'Egaono Hana', - 'artist': 'Goose house', + 'artists': ['Goose house'], 'thumbnail': r're:(?i)^https://www.crunchyroll.com/imgsrv/.*\.jpeg?$', 'genres': ['J-Pop'], }, @@ -525,11 +531,12 @@ class CrunchyrollMusicIE(CrunchyrollBaseIE): 'display_id': 'crossing-field', 'title': 'Crossing Field', 'track': 'Crossing Field', - 'artist': 'LiSA', + 'artists': ['LiSA'], 'thumbnail': r're:(?i)^https://www.crunchyroll.com/imgsrv/.*\.jpeg?$', 'genres': ['Anime'], }, 'params': {'skip_download': 'm3u8'}, + 'skip': 'no longer exists', }, { 'url': 'https://www.crunchyroll.com/watch/concert/MC2E2AC135', 'info_dict': { @@ -538,7 +545,7 @@ class CrunchyrollMusicIE(CrunchyrollBaseIE): 'display_id': 'live-is-smile-always-364joker-at-yokohama-arena', 'title': 'LiVE is Smile Always-364+JOKER- at YOKOHAMA ARENA', 'track': 'LiVE is Smile Always-364+JOKER- at YOKOHAMA ARENA', - 'artist': 'LiSA', + 'artists': ['LiSA'], 'thumbnail': r're:(?i)^https://www.crunchyroll.com/imgsrv/.*\.jpeg?$', 'description': 'md5:747444e7e6300907b7a43f0a0503072e', 'genres': ['J-Pop'], @@ -566,16 +573,14 @@ class CrunchyrollMusicIE(CrunchyrollBaseIE): if not response: raise ExtractorError(f'No video with id {internal_id} could be found (possibly region locked?)', expected=True) - streams_link = response.get('streams_link') - if not streams_link and response.get('isPremiumOnly'): + if not self._IS_PREMIUM and response.get('isPremiumOnly'): message = f'This {response.get("type") or "media"} is for premium members only' if self.is_logged_in: raise ExtractorError(message, expected=True) self.raise_login_required(message) result = self._transform_music_response(response) - stream_response = self._call_api(streams_link, internal_id, lang, 'stream info') - result['formats'] = self._extract_formats(stream_response, internal_id) + result['formats'], _ = self._extract_stream(f'music/{internal_id}', internal_id) return result @@ -587,7 +592,7 @@ class CrunchyrollMusicIE(CrunchyrollBaseIE): 'display_id': 'slug', 'title': 'title', 'track': 'title', - 'artist': ('artist', 'name'), + 'artists': ('artist', 'name', all), 'description': ('description', {str}, {lambda x: x.replace(r'\r\n', '\n') or None}), 'thumbnails': ('images', ..., ..., { 'url': ('source', {url_or_none}), @@ -611,7 +616,7 @@ class CrunchyrollArtistIE(CrunchyrollBaseIE): 'info_dict': { 'id': 'MA179CB50D', 'title': 'LiSA', - 'genres': ['J-Pop', 'Anime', 'Rock'], + 'genres': ['Anime', 'J-Pop', 'Rock'], 'description': 'md5:16d87de61a55c3f7d6c454b73285938e', }, 'playlist_mincount': 83, diff --git a/yt-dlp/yt_dlp/extractor/dropbox.py b/yt-dlp/yt_dlp/extractor/dropbox.py index bc2efce123..0246975c1f 100644 --- a/yt-dlp/yt_dlp/extractor/dropbox.py +++ b/yt-dlp/yt_dlp/extractor/dropbox.py @@ -65,12 +65,14 @@ class DropboxIE(InfoExtractor): formats, subtitles, has_anonymous_download = [], {}, False for encoded in reversed(re.findall(r'registerStreamedPrefetch\s*\(\s*"[\w/+=]+"\s*,\s*"([\w/+=]+)"', webpage)): decoded = base64.b64decode(encoded).decode('utf-8', 'ignore') + if not has_anonymous_download: + has_anonymous_download = self._search_regex( + r'(anonymous:\tanonymous)', decoded, 'anonymous', default=False) transcode_url = self._search_regex( r'\n.(https://[^\x03\x08\x12\n]+\.m3u8)', decoded, 'transcode url', default=None) if not transcode_url: continue formats, subtitles = self._extract_m3u8_formats_and_subtitles(transcode_url, video_id, 'mp4') - has_anonymous_download = self._search_regex(r'(anonymous:\tanonymous)', decoded, 'anonymous', default=False) break # downloads enabled we can get the original file diff --git a/yt-dlp/yt_dlp/extractor/joqrag.py b/yt-dlp/yt_dlp/extractor/joqrag.py index c68ad8cb5f..7a91d4a235 100644 --- a/yt-dlp/yt_dlp/extractor/joqrag.py +++ b/yt-dlp/yt_dlp/extractor/joqrag.py @@ -80,7 +80,7 @@ class JoqrAgIE(InfoExtractor): note='Downloading metadata', errnote='Failed to download metadata') title = self._extract_metadata('Program_name', metadata) - if title == '放送休止': + if not title or title == '放送休止': formats = [] live_status = 'is_upcoming' release_timestamp = self._extract_start_timestamp(video_id, False) diff --git a/yt-dlp/yt_dlp/extractor/kick.py b/yt-dlp/yt_dlp/extractor/kick.py index d124372424..889548f526 100644 --- a/yt-dlp/yt_dlp/extractor/kick.py +++ b/yt-dlp/yt_dlp/extractor/kick.py @@ -13,7 +13,8 @@ from ..utils import ( class KickBaseIE(InfoExtractor): def _real_initialize(self): - self._request_webpage(HEADRequest('https://kick.com/'), None, 'Setting up session', fatal=False) + self._request_webpage( + HEADRequest('https://kick.com/'), None, 'Setting up session', fatal=False, impersonate=True) xsrf_token = self._get_cookies('https://kick.com/').get('XSRF-TOKEN') if not xsrf_token: self.write_debug('kick.com did not set XSRF-TOKEN cookie') @@ -25,7 +26,7 @@ class KickBaseIE(InfoExtractor): def _call_api(self, path, display_id, note='Downloading API JSON', headers={}, **kwargs): return self._download_json( f'https://kick.com/api/v1/{path}', display_id, note=note, - headers=merge_dicts(headers, self._API_HEADERS), **kwargs) + headers=merge_dicts(headers, self._API_HEADERS), impersonate=True, **kwargs) class KickIE(KickBaseIE): @@ -82,26 +83,27 @@ class KickIE(KickBaseIE): class KickVODIE(KickBaseIE): _VALID_URL = r'https?://(?:www\.)?kick\.com/video/(?P[\da-f]{8}-(?:[\da-f]{4}-){3}[\da-f]{12})' _TESTS = [{ - 'url': 'https://kick.com/video/54244b5e-050a-4df4-a013-b2433dafbe35', - 'md5': '73691206a6a49db25c5aa1588e6538fc', + 'url': 'https://kick.com/video/58bac65b-e641-4476-a7ba-3707a35e60e3', + 'md5': '3870f94153e40e7121a6e46c068b70cb', 'info_dict': { - 'id': '54244b5e-050a-4df4-a013-b2433dafbe35', + 'id': '58bac65b-e641-4476-a7ba-3707a35e60e3', 'ext': 'mp4', - 'title': 'Making 710-carBoosting. Kinda No Pixel inspired. !guilded - !links', - 'description': 'md5:a0d3546bf7955d0a8252ffe0fd6f518f', - 'channel': 'kmack710', - 'channel_id': '16278', - 'uploader': 'Kmack710', - 'uploader_id': '16412', - 'upload_date': '20221206', - 'timestamp': 1670318289, - 'duration': 40104.0, + 'title': '🤠REBIRTH IS BACK!!!!🤠!stake CODE JAREDFPS 🤠', + 'description': 'md5:02b0c46f9b4197fb545ab09dddb85b1d', + 'channel': 'jaredfps', + 'channel_id': '26608', + 'uploader': 'JaredFPS', + 'uploader_id': '26799', + 'upload_date': '20240402', + 'timestamp': 1712097108, + 'duration': 33859.0, 'thumbnail': r're:^https?://.*\.jpg', - 'categories': ['Grand Theft Auto V'], + 'categories': ['Call of Duty: Warzone'], }, 'params': { 'skip_download': 'm3u8', }, + 'expected_warnings': [r'impersonation'], }] def _real_extract(self, url):