From 34b22a3489afff2f0a5f36a53ef61293f4290a6e Mon Sep 17 00:00:00 2001 From: Jay Cho Date: Sun, 7 Jun 2026 20:12:45 +0900 Subject: [PATCH 1/2] [Tizen.Network.WiFi] Consolidate GetFound*/GetWiFiConfigurations into EnumerateForeach helper GetFoundAPs, GetFoundSpecificAPs, GetFoundBssids and GetWiFiConfigurations each repeated the same 'native foreach callback -> List collection' pattern, differing only by the native foreach function, the handle clone call, and the wrapper type. Introduces a generic EnumerateForeach helper that takes the operation name, privilege, native foreach function, and an item-wrap delegate. The wrap delegate absorbs the differing Clone signatures (AP.Clone has the out handle first; Config.Clone has it second). Iteration semantics, ret-check timing, exception mapping (CheckReturnValue) and per-method privilege are preserved, so behavior is unchanged. Fixes #7622 --- .../Tizen.Network.WiFi/WiFiManagerImpl.cs | 126 +++++++----------- 1 file changed, 48 insertions(+), 78 deletions(-) diff --git a/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs b/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs index 21762e8f180..3cd363abc5a 100644 --- a/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs +++ b/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs @@ -181,97 +181,67 @@ internal SafeWiFiManagerHandle GetSafeHandle() } - internal IEnumerable GetFoundAPs() + // Shared "native foreach -> List" collector for the GetFound*/ + // GetWiFiConfigurations methods. Each call site supplies only what + // differs: the operation name and privilege (for CheckReturnValue), + // the native foreach function, and how to wrap a native item handle + // into its managed type. + private List EnumerateForeach(string opName, string privilege, + Func nativeForeach, + Func wrap) { - Log.Info(Globals.LogTag, "GetFoundAPs"); - List apList = new List(); - Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) => + Log.Info(Globals.LogTag, opName); + List list = new List(); + Interop.WiFi.HandleCallback callback = (IntPtr handle, IntPtr userData) => { - if (apHandle != IntPtr.Zero) + if (handle != IntPtr.Zero) { - IntPtr clonedHandle; - Interop.WiFi.AP.Clone(out clonedHandle, apHandle); - WiFiAP apItem = new WiFiAP(clonedHandle); - apList.Add(apItem); + list.Add(wrap(handle)); return true; } return false; }; - int ret = Interop.WiFi.GetForeachFoundAPs(GetSafeHandle(), callback, IntPtr.Zero); - CheckReturnValue(ret, "GetForeachFoundAPs", PrivilegeNetworkGet); - - return apList; + int ret = nativeForeach(GetSafeHandle(), callback, IntPtr.Zero); + CheckReturnValue(ret, opName, privilege); + return list; } - internal IEnumerable GetFoundSpecificAPs() - { - Log.Info(Globals.LogTag, "GetFoundSpecificAPs"); - List apList = new List(); - Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) => - { - if (apHandle != IntPtr.Zero) + internal IEnumerable GetFoundAPs() => + EnumerateForeach("GetForeachFoundAPs", PrivilegeNetworkGet, + (wifi, cb, ud) => Interop.WiFi.GetForeachFoundAPs(wifi, cb, ud), + apHandle => { - IntPtr clonedHandle; - Interop.WiFi.AP.Clone(out clonedHandle, apHandle); - WiFiAP apItem = new WiFiAP(clonedHandle); - apList.Add(apItem); - return true; - } - return false; - - }; - - int ret = Interop.WiFi.GetForeachFoundSpecificAPs(GetSafeHandle(), callback, IntPtr.Zero); - CheckReturnValue(ret, "GetForeachFoundSpecificAPs", PrivilegeNetworkGet); - - return apList; - } - - internal IEnumerable GetFoundBssids() - { - Log.Info(Globals.LogTag, "GetFoundBssids"); - List apList = new List(); - Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) => - { - if (apHandle != IntPtr.Zero) + Interop.WiFi.AP.Clone(out IntPtr clonedHandle, apHandle); + return new WiFiAP(clonedHandle); + }); + + internal IEnumerable GetFoundSpecificAPs() => + EnumerateForeach("GetForeachFoundSpecificAPs", PrivilegeNetworkGet, + (wifi, cb, ud) => Interop.WiFi.GetForeachFoundSpecificAPs(wifi, cb, ud), + apHandle => { - IntPtr clonedHandle; - Interop.WiFi.AP.Clone(out clonedHandle, apHandle); - WiFiAP apItem = new WiFiAP(clonedHandle); - apList.Add(apItem); - return true; - } - return false; - }; - - int ret = Interop.WiFi.GetForeachFoundBssids(GetSafeHandle(), callback, IntPtr.Zero); - CheckReturnValue(ret, "GetForeachFoundBssids", PrivilegeNetworkGet); - - return apList; - } - - internal IEnumerable GetWiFiConfigurations() - { - Log.Debug(Globals.LogTag, "GetWiFiConfigurations"); - List configList = new List(); - Interop.WiFi.HandleCallback callback = (IntPtr configHandle, IntPtr userData) => - { - if (configHandle != IntPtr.Zero) + Interop.WiFi.AP.Clone(out IntPtr clonedHandle, apHandle); + return new WiFiAP(clonedHandle); + }); + + internal IEnumerable GetFoundBssids() => + EnumerateForeach("GetForeachFoundBssids", PrivilegeNetworkGet, + (wifi, cb, ud) => Interop.WiFi.GetForeachFoundBssids(wifi, cb, ud), + apHandle => { - IntPtr clonedConfig; - Interop.WiFi.Config.Clone(configHandle, out clonedConfig); - WiFiConfiguration configItem = new WiFiConfiguration(clonedConfig); - configList.Add(configItem); - return true; - } - return false; - }; - - int ret = Interop.WiFi.Config.GetForeachConfiguration(GetSafeHandle(), callback, IntPtr.Zero); - CheckReturnValue(ret, "GetForeachConfiguration", PrivilegeNetworkProfile); - return configList; - } + Interop.WiFi.AP.Clone(out IntPtr clonedHandle, apHandle); + return new WiFiAP(clonedHandle); + }); + + internal IEnumerable GetWiFiConfigurations() => + EnumerateForeach("GetForeachConfiguration", PrivilegeNetworkProfile, + (wifi, cb, ud) => Interop.WiFi.Config.GetForeachConfiguration(wifi, cb, ud), + configHandle => + { + Interop.WiFi.Config.Clone(configHandle, out IntPtr clonedConfig); + return new WiFiConfiguration(clonedConfig); + }); internal void SaveWiFiNetworkConfiguration(WiFiConfiguration config) { From 37941b24b31ff82470bdf3b95477c2e5ee5f205a Mon Sep 17 00:00:00 2001 From: Jay Cho Date: Mon, 8 Jun 2026 21:04:56 +0900 Subject: [PATCH 2/2] Address review feedback Harden EnumerateForeach: catch exceptions raised inside the native foreach callback so they never unwind across the P/Invoke boundary, and rethrow after the native call returns. Check the return value of every AP.Clone / Config.Clone call and throw a WiFiException when cloning fails. Applied-Human-Comments: 3369222130,3369222132,3369222133,3369222134,3369222136 --- .../Tizen.Network.WiFi/WiFiManagerImpl.cs | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs b/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs index 3cd363abc5a..8b9712627b5 100644 --- a/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs +++ b/src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs @@ -192,17 +192,33 @@ private List EnumerateForeach(string opName, string privilege, { Log.Info(Globals.LogTag, opName); List list = new List(); + Exception capturedException = null; Interop.WiFi.HandleCallback callback = (IntPtr handle, IntPtr userData) => { if (handle != IntPtr.Zero) { - list.Add(wrap(handle)); + try + { + list.Add(wrap(handle)); + } + catch (Exception ex) + { + // Never let a managed exception unwind through the native + // P/Invoke boundary. Capture it, stop the iteration, and + // rethrow once the native foreach has returned. + capturedException = ex; + return false; + } return true; } return false; }; int ret = nativeForeach(GetSafeHandle(), callback, IntPtr.Zero); + if (capturedException != null) + { + throw capturedException; + } CheckReturnValue(ret, opName, privilege); return list; } @@ -212,7 +228,11 @@ internal IEnumerable GetFoundAPs() => (wifi, cb, ud) => Interop.WiFi.GetForeachFoundAPs(wifi, cb, ud), apHandle => { - Interop.WiFi.AP.Clone(out IntPtr clonedHandle, apHandle); + int ret = Interop.WiFi.AP.Clone(out IntPtr clonedHandle, apHandle); + if (ret != (int)WiFiError.None) + { + WiFiErrorFactory.ThrowWiFiException(ret, "Failed to clone AP handle"); + } return new WiFiAP(clonedHandle); }); @@ -221,7 +241,11 @@ internal IEnumerable GetFoundSpecificAPs() => (wifi, cb, ud) => Interop.WiFi.GetForeachFoundSpecificAPs(wifi, cb, ud), apHandle => { - Interop.WiFi.AP.Clone(out IntPtr clonedHandle, apHandle); + int ret = Interop.WiFi.AP.Clone(out IntPtr clonedHandle, apHandle); + if (ret != (int)WiFiError.None) + { + WiFiErrorFactory.ThrowWiFiException(ret, "Failed to clone AP handle"); + } return new WiFiAP(clonedHandle); }); @@ -230,7 +254,11 @@ internal IEnumerable GetFoundBssids() => (wifi, cb, ud) => Interop.WiFi.GetForeachFoundBssids(wifi, cb, ud), apHandle => { - Interop.WiFi.AP.Clone(out IntPtr clonedHandle, apHandle); + int ret = Interop.WiFi.AP.Clone(out IntPtr clonedHandle, apHandle); + if (ret != (int)WiFiError.None) + { + WiFiErrorFactory.ThrowWiFiException(ret, "Failed to clone AP handle"); + } return new WiFiAP(clonedHandle); }); @@ -239,7 +267,11 @@ internal IEnumerable GetWiFiConfigurations() => (wifi, cb, ud) => Interop.WiFi.Config.GetForeachConfiguration(wifi, cb, ud), configHandle => { - Interop.WiFi.Config.Clone(configHandle, out IntPtr clonedConfig); + int ret = Interop.WiFi.Config.Clone(configHandle, out IntPtr clonedConfig); + if (ret != (int)WiFiError.None) + { + WiFiErrorFactory.ThrowWiFiException(ret, "Failed to clone WiFi configuration"); + } return new WiFiConfiguration(clonedConfig); });