Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 77 additions & 75 deletions src/Tizen.Network.WiFi/Tizen.Network.WiFi/WiFiManagerImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,97 +181,99 @@ internal SafeWiFiManagerHandle GetSafeHandle()
}


internal IEnumerable<WiFiAP> GetFoundAPs()
// Shared "native foreach -> List<T>" 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<T> EnumerateForeach<T>(string opName, string privilege,
Func<SafeWiFiManagerHandle, Interop.WiFi.HandleCallback, IntPtr, int> nativeForeach,
Func<IntPtr, T> wrap)
{
Log.Info(Globals.LogTag, "GetFoundAPs");
List<WiFiAP> apList = new List<WiFiAP>();
Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
Log.Info(Globals.LogTag, opName);
List<T> list = new List<T>();
Exception capturedException = null;
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);
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 = Interop.WiFi.GetForeachFoundAPs(GetSafeHandle(), callback, IntPtr.Zero);
CheckReturnValue(ret, "GetForeachFoundAPs", PrivilegeNetworkGet);

return apList;
}

internal IEnumerable<WiFiAP> GetFoundSpecificAPs()
{
Log.Info(Globals.LogTag, "GetFoundSpecificAPs");
List<WiFiAP> apList = new List<WiFiAP>();
Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
int ret = nativeForeach(GetSafeHandle(), callback, IntPtr.Zero);
if (capturedException != null)
{
if (apHandle != IntPtr.Zero)
{
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;
throw capturedException;
}
CheckReturnValue(ret, opName, privilege);
return list;
}
Comment on lines +189 to 224

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Propagating managed exceptions through native code boundaries (P/Invoke) can lead to undefined behavior, native crashes, or silent failures. Since the wrap delegate can throw exceptions (e.g., if cloning fails or during object construction), it is highly recommended to catch any exceptions inside the callback, stop the iteration, and safely rethrow the captured exception after the native foreach method returns.

        private List<T> EnumerateForeach<T>(string opName, string privilege,
            Func<SafeWiFiManagerHandle, Interop.WiFi.HandleCallback, IntPtr, int> nativeForeach,
            Func<IntPtr, T> wrap)
        {
            Log.Info(Globals.LogTag, opName);
            List<T> list = new List<T>();
            Exception capturedException = null;
            Interop.WiFi.HandleCallback callback = (IntPtr handle, IntPtr userData) =>
            {
                if (handle != IntPtr.Zero)
                {
                    try
                    {
                        list.Add(wrap(handle));
                    }
                    catch (Exception ex)
                    {
                        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;
        }


internal IEnumerable<WiFiAP> GetFoundBssids()
{
Log.Info(Globals.LogTag, "GetFoundBssids");
List<WiFiAP> apList = new List<WiFiAP>();
Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
{
if (apHandle != IntPtr.Zero)
internal IEnumerable<WiFiAP> 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.GetForeachFoundBssids(GetSafeHandle(), callback, IntPtr.Zero);
CheckReturnValue(ret, "GetForeachFoundBssids", PrivilegeNetworkGet);
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);
});
Comment on lines +229 to +237

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The return value of Interop.WiFi.AP.Clone is ignored. If cloning fails, it may return a non-zero error code and leave clonedHandle as IntPtr.Zero or invalid, which will cause downstream failures when the WiFiAP instance is used. It is safer to check the return value and throw an exception if cloning fails.

                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);
                });


return apList;
}
internal IEnumerable<WiFiAP> GetFoundSpecificAPs() =>
EnumerateForeach("GetForeachFoundSpecificAPs", PrivilegeNetworkGet,
(wifi, cb, ud) => Interop.WiFi.GetForeachFoundSpecificAPs(wifi, cb, ud),
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);
});
Comment on lines +242 to +250

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The return value of Interop.WiFi.AP.Clone is ignored. If cloning fails, it may return a non-zero error code and leave clonedHandle as IntPtr.Zero or invalid, which will cause downstream failures when the WiFiAP instance is used. It is safer to check the return value and throw an exception if cloning fails.

                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);
                });


internal IEnumerable<WiFiConfiguration> GetWiFiConfigurations()
{
Log.Debug(Globals.LogTag, "GetWiFiConfigurations");
List<WiFiConfiguration> configList = new List<WiFiConfiguration>();
Interop.WiFi.HandleCallback callback = (IntPtr configHandle, IntPtr userData) =>
{
if (configHandle != IntPtr.Zero)
internal IEnumerable<WiFiAP> 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.AP.Clone(out IntPtr clonedHandle, apHandle);
if (ret != (int)WiFiError.None)
{
WiFiErrorFactory.ThrowWiFiException(ret, "Failed to clone AP handle");
}
return new WiFiAP(clonedHandle);
});
Comment on lines +255 to +263

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The return value of Interop.WiFi.AP.Clone is ignored. If cloning fails, it may return a non-zero error code and leave clonedHandle as IntPtr.Zero or invalid, which will cause downstream failures when the WiFiAP instance is used. It is safer to check the return value and throw an exception if cloning fails.

                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);
                });


int ret = Interop.WiFi.Config.GetForeachConfiguration(GetSafeHandle(), callback, IntPtr.Zero);
CheckReturnValue(ret, "GetForeachConfiguration", PrivilegeNetworkProfile);
return configList;
}
internal IEnumerable<WiFiConfiguration> GetWiFiConfigurations() =>
EnumerateForeach("GetForeachConfiguration", PrivilegeNetworkProfile,
(wifi, cb, ud) => Interop.WiFi.Config.GetForeachConfiguration(wifi, cb, ud),
configHandle =>
{
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);
});
Comment on lines +268 to +276

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The return value of Interop.WiFi.Config.Clone is ignored. If cloning fails, it may return a non-zero error code and leave clonedConfig as IntPtr.Zero or invalid, which will cause downstream failures when the WiFiConfiguration instance is used. It is safer to check the return value and throw an exception if cloning fails.

                configHandle =>
                {
                    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);
                });


internal void SaveWiFiNetworkConfiguration(WiFiConfiguration config)
{
Expand Down
Loading