[WiFi] Fix infinite recursion (#392)
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.WiFi / Tizen.Network.WiFi / WiFiManagerImpl.cs
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Collections.Generic;
19 using System.Threading;
20 using System.Threading.Tasks;
21 using System.Runtime.InteropServices;
22 using Tizen.Applications;
23
24 namespace Tizen.Network.WiFi
25 {
26     static internal class Globals
27     {
28         internal const string LogTag = "Tizen.Network.WiFi";
29     }
30
31     internal class HandleHolder
32     {
33         private SafeWiFiManagerHandle _handle;
34
35         internal HandleHolder()
36         {
37             _handle = WiFiManagerImpl.Instance.Initialize();
38             Log.Info(Globals.LogTag, "Handle: " + _handle);
39         }
40
41         internal SafeWiFiManagerHandle GetSafeHandle()
42         {
43             Log.Debug(Globals.LogTag, "Handleholder safehandle = " + _handle);
44             return _handle;
45         }
46     }
47
48     internal partial class WiFiManagerImpl
49     {
50         private static readonly Lazy<WiFiManagerImpl> _instance =
51             new Lazy<WiFiManagerImpl>(() => new WiFiManagerImpl());
52
53         private TizenSynchronizationContext context = new TizenSynchronizationContext();
54         
55         private Dictionary<IntPtr, Interop.WiFi.VoidCallback> _callback_map =
56             new Dictionary<IntPtr, Interop.WiFi.VoidCallback>();
57         
58         private int _requestId = 0;
59         private string _macAddress;
60
61         //private string PrivilegeNetworkSet = "http://tizen.org/privilege/network.set";
62         private string PrivilegeNetworkGet = "http://tizen.org/privilege/network.get";
63         private string PrivilegeNetworkProfile = "http://tizen.org/privilege/network.get";
64
65         internal string MacAddress
66         {
67             get
68             {
69                 if (String.IsNullOrEmpty(_macAddress))
70                 {
71                     string address;
72                     int ret = Interop.WiFi.GetMacAddress(GetSafeHandle(), out address);
73                     if (ret != (int)WiFiError.None)
74                     {
75                         Log.Error(Globals.LogTag, "Failed to get mac address, Error - " + (WiFiError)ret);
76                         _macAddress = "";
77                     }
78                     else
79                     {
80                         _macAddress = address;
81                     }
82                 }
83                 return _macAddress;
84             }
85         }
86
87         internal string InterfaceName
88         {
89             get
90             {
91                 string name;
92                 int ret = Interop.WiFi.GetNetworkInterfaceName(GetSafeHandle(), out name);
93                 if (ret != (int)WiFiError.None)
94                 {
95                     Log.Error(Globals.LogTag, "Failed to get interface name, Error - " + (WiFiError)ret);
96                     return "";
97                 }
98                 return name;
99             }
100         }
101
102         internal WiFiConnectionState ConnectionState
103         {
104             get
105             {
106                 int state;
107                 int ret = Interop.WiFi.GetConnectionState(GetSafeHandle(), out state);
108                 if (ret != (int)WiFiError.None)
109                 {
110                     Log.Error(Globals.LogTag, "Failed to get connection state, Error - " + (WiFiError)ret);
111                     return WiFiConnectionState.Failure;
112                 }
113                 return (WiFiConnectionState)state;
114             }
115         }
116
117         internal bool IsActive
118         {
119             get
120             {
121                 bool active;
122                 int ret = Interop.WiFi.IsActive(GetSafeHandle(), out active);
123                 if (ret != (int)WiFiError.None)
124                 {
125                     Log.Error(Globals.LogTag, "Failed to get isActive, Error - " + (WiFiError)ret);
126                 }
127                 return active;
128             }
129         }
130
131         internal static WiFiManagerImpl Instance
132         {
133             get
134             {
135                return _instance.Value;
136             }
137         }
138
139         private static ThreadLocal<HandleHolder> s_threadName = new ThreadLocal<HandleHolder>(() =>
140         {
141             Log.Info(Globals.LogTag, "In threadlocal delegate");
142             return new HandleHolder();
143         });
144
145         private WiFiManagerImpl()
146         {
147             Log.Info(Globals.LogTag, "WiFiManagerImpl constructor");
148         }
149
150         internal SafeWiFiManagerHandle GetSafeHandle()
151         {
152             return s_threadName.Value.GetSafeHandle();
153         }
154
155         internal SafeWiFiManagerHandle Initialize()
156         {
157             SafeWiFiManagerHandle handle;
158             int tid = Thread.CurrentThread.ManagedThreadId;
159             Log.Info(Globals.LogTag, "PInvoke wifi_manager_initialize");
160             int ret = Interop.WiFi.Initialize(tid, out handle);
161             if (ret != (int)WiFiError.None)
162             {
163                 Log.Error(Globals.LogTag, "Initialize Fail, Error - " + (WiFiError)ret);
164                 WiFiErrorFactory.ThrowWiFiException(ret, PrivilegeNetworkGet);
165             }
166             handle.SetTID(tid);
167             return handle;
168         }
169
170         internal IEnumerable<WiFiAP> GetFoundAPs()
171         {
172             Log.Info(Globals.LogTag, "GetFoundAPs");
173             List<WiFiAP> apList = new List<WiFiAP>();
174             Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
175             {
176                 if (apHandle != IntPtr.Zero)
177                 {
178                     IntPtr clonedHandle;
179                     Interop.WiFi.AP.Clone(out clonedHandle, apHandle);
180                     WiFiAP apItem = new WiFiAP(clonedHandle);
181                     apList.Add(apItem);
182                     return true;
183                 }
184                 return false;
185             };
186
187             int ret = Interop.WiFi.GetForeachFoundAPs(GetSafeHandle(), callback, IntPtr.Zero);
188             CheckReturnValue(ret, "GetForeachFoundAPs", PrivilegeNetworkGet);
189
190             return apList;
191         }
192
193         internal IEnumerable<WiFiAP> GetFoundSpecificAPs()
194         {
195             Log.Info(Globals.LogTag, "GetFoundSpecificAPs");
196             List<WiFiAP> apList = new List<WiFiAP>();
197             Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
198             {
199                 if (apHandle != IntPtr.Zero)
200                 {
201                     IntPtr clonedHandle;
202                     Interop.WiFi.AP.Clone(out clonedHandle, apHandle);
203                     WiFiAP apItem = new WiFiAP(clonedHandle);
204                     apList.Add(apItem);
205                     return true;
206                 }
207                 return false;
208
209             };
210
211             int ret = Interop.WiFi.GetForeachFoundSpecificAPs(GetSafeHandle(), callback, IntPtr.Zero);
212             CheckReturnValue(ret, "GetForeachFoundSpecificAPs", PrivilegeNetworkGet);
213             
214             return apList;
215         }
216
217         internal IEnumerable<WiFiAP> GetFoundBssids()
218         {
219             Log.Info(Globals.LogTag, "GetFoundBssids");
220             List<WiFiAP> apList = new List<WiFiAP>();
221             Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
222             {
223                 if (apHandle != IntPtr.Zero)
224                 {
225                     IntPtr clonedHandle;
226                     Interop.WiFi.AP.Clone(out clonedHandle, apHandle);
227                     WiFiAP apItem = new WiFiAP(clonedHandle);
228                     apList.Add(apItem);
229                     return true;
230                 }
231                 return false;
232             };
233
234             int ret = Interop.WiFi.GetForeachFoundBssids(GetSafeHandle(), callback, IntPtr.Zero);
235             CheckReturnValue(ret, "GetForeachFoundBssids", PrivilegeNetworkGet);
236
237             return apList;
238         }
239
240         internal IEnumerable<WiFiConfiguration> GetWiFiConfigurations()
241         {
242             Log.Debug(Globals.LogTag, "GetWiFiConfigurations");
243             List<WiFiConfiguration> configList = new List<WiFiConfiguration>();
244             Interop.WiFi.HandleCallback callback = (IntPtr configHandle, IntPtr userData) =>
245             {
246                 if (configHandle != IntPtr.Zero)
247                 {
248                     IntPtr clonedConfig;
249                     Interop.WiFi.Config.Clone(configHandle, out clonedConfig);
250                     WiFiConfiguration configItem = new WiFiConfiguration(clonedConfig);
251                     configList.Add(configItem);
252                     return true;
253                 }
254                 return false;
255             };
256
257             int ret = Interop.WiFi.Config.GetForeachConfiguration(GetSafeHandle(), callback, IntPtr.Zero);
258             CheckReturnValue(ret, "GetForeachConfiguration", PrivilegeNetworkProfile);
259             return configList;
260         }
261
262         internal void SaveWiFiNetworkConfiguration(WiFiConfiguration config)
263         {
264             Log.Debug(Globals.LogTag, "SaveWiFiNetworkConfiguration");
265             if (config == null)
266             {
267                 throw new ArgumentNullException("WiFi configuration is null");
268             }
269
270             IntPtr configHandle = config.GetHandle();
271             int ret = Interop.WiFi.Config.SaveConfiguration(GetSafeHandle(), configHandle);
272             CheckReturnValue(ret, "SaveConfiguration", PrivilegeNetworkProfile);
273        }
274
275         internal WiFiAP GetConnectedAP()
276         {
277             Log.Info(Globals.LogTag, "GetConnectedAP");
278             IntPtr apHandle;
279             int ret = Interop.WiFi.GetConnectedAP(GetSafeHandle(), out apHandle);
280             if (ret == (int)WiFiError.NoConnectionError)
281             {
282                 Log.Error(Globals.LogTag, "No connection " + (WiFiError)ret);
283                 return null;
284             }
285             CheckReturnValue(ret, "GetConnectedAP", PrivilegeNetworkGet);
286             WiFiAP ap = new WiFiAP(apHandle);
287             return ap;
288         }
289
290         internal Task ActivateAsync()
291         {
292             Log.Info(Globals.LogTag, "ActivateAsync");
293             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
294             IntPtr id;
295             lock (_callback_map)
296             {
297                 id = (IntPtr)_requestId++;
298                 _callback_map[id] = (error, key) =>
299                 {
300                     Log.Info(Globals.LogTag, "ActivateAsync done");
301                     if (error != (int)WiFiError.None)
302                     {
303                         Log.Error(Globals.LogTag, "Error occurs during WiFi activating, " + (WiFiError)error);
304                         task.SetException(new InvalidOperationException("Error occurs during WiFi activating, " + (WiFiError)error));
305                     }
306                     else
307                     {
308                         task.SetResult(true);
309                     }
310                     lock (_callback_map)
311                     {
312                         _callback_map.Remove(key);
313                     }
314                 };
315             }
316
317             context.Post((x) =>
318             {
319                 Log.Info(Globals.LogTag, "Interop.WiFi.ActivateAsync");
320                 try
321                 {
322                     int ret = Interop.WiFi.Activate(GetSafeHandle(), _callback_map[id], id);
323                     CheckReturnValue(ret, "Activate", "");
324                 }
325                 catch (Exception e)
326                 {
327                     Log.Error(Globals.LogTag, "Exception on ActivateAsync\n" + e);
328                     task.SetException(e);
329                 }
330             }, null);
331
332             return task.Task;
333         }
334
335         internal Task ActivateWithWiFiPickerTestedAsync()
336         {
337             Log.Info(Globals.LogTag, "ActivateWithWiFiPickerTestedAsync");
338             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
339             IntPtr id;
340             lock (_callback_map)
341             {
342                 id = (IntPtr)_requestId++;
343                 _callback_map[id] = (error, key) =>
344                 {
345                     Log.Info(Globals.LogTag, "ActivateWithWiFiPickerTestedAsync done");
346                     if (error != (int)WiFiError.None)
347                     {
348                         Log.Error(Globals.LogTag, "Error occurs during WiFi activating, " + (WiFiError)error);
349                         task.SetException(new InvalidOperationException("Error occurs during WiFi activating, " + (WiFiError)error));
350                     }
351                     else
352                     {
353                         task.SetResult(true);
354                     }
355                     lock (_callback_map)
356                     {
357                         _callback_map.Remove(key);
358                     }
359                 };
360             }
361
362             context.Post((x) =>
363             {
364                 Log.Info(Globals.LogTag, "Interop.WiFi.ActivateWithWiFiPickerTestedAsync");
365                 try
366                 {
367                     int ret = Interop.WiFi.ActivateWithWiFiPickerTested(GetSafeHandle(), _callback_map[id], id);
368                     CheckReturnValue(ret, "ActivateWithWiFiPickerTested", "");
369                 }
370                 catch (Exception e)
371                 {
372                     Log.Error(Globals.LogTag, "Exception on ActivateWithWiFiPickerTestedAsync\n" + e);
373                     task.SetException(e);
374                 }
375             }, null);
376             
377             return task.Task;
378         }
379
380         internal Task DeactivateAsync()
381         {
382             Log.Info(Globals.LogTag, "DeactivateAsync");
383             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
384             IntPtr id;
385             lock (_callback_map)
386             {
387                 id = (IntPtr)_requestId++;
388                 _callback_map[id] = (error, key) =>
389                 {
390                     Log.Info(Globals.LogTag, "DeactivateAsync done");
391                     if (error != (int)WiFiError.None)
392                     {
393                         Log.Error(Globals.LogTag, "Error occurs during WiFi deactivating, " + (WiFiError)error);
394                         task.SetException(new InvalidOperationException("Error occurs during WiFi deactivating, " + (WiFiError)error));
395                     }
396                     else
397                     {
398                         task.SetResult(true);
399                     }
400                     lock (_callback_map)
401                     {
402                         _callback_map.Remove(key);
403                     }
404                 };
405             }
406
407             context.Post((x) =>
408             {
409                 Log.Info(Globals.LogTag, "Interop.WiFi.Deactivate");
410                 try
411                 {
412                     int ret = Interop.WiFi.Deactivate(GetSafeHandle(), _callback_map[id], id);
413                     CheckReturnValue(ret, "Deactivate", "");
414                 }
415                 catch (Exception e)
416                 {
417                     Log.Error(Globals.LogTag, "Exception on Deactivate\n" + e);
418                     task.SetException(e);
419                 }
420             }, null);
421
422             return task.Task;           
423         }
424
425         internal Task ScanAsync()
426         {
427             Log.Info(Globals.LogTag, "ScanAsync");
428             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
429             IntPtr id;
430             lock (_callback_map)
431             {
432                 id = (IntPtr)_requestId++;
433                 _callback_map[id] = (error, key) =>
434                 {
435                     Log.Info(Globals.LogTag, "ScanAsync done");
436                     if (error != (int)WiFiError.None)
437                     {
438                         Log.Error(Globals.LogTag, "Error occurs during WiFi scanning, " + (WiFiError)error);
439                         task.SetException(new InvalidOperationException("Error occurs during WiFi scanning, " + (WiFiError)error));
440                     }
441                     else
442                     {
443                         task.SetResult(true);
444                     }
445                     lock (_callback_map)
446                     {
447                         _callback_map.Remove(key);
448                     }
449                 };
450             }
451
452             context.Post((x) =>
453             {
454                 Log.Info(Globals.LogTag, "Interop.WiFi.Scan");
455                 try
456                 {
457                     int ret = Interop.WiFi.Scan(GetSafeHandle(), _callback_map[id], id);
458                     CheckReturnValue(ret, "Scan", "");
459                 }
460                 catch (Exception e)
461                 {
462                     Log.Error(Globals.LogTag, "Exception on Scan\n" + e);
463                     task.SetException(e);
464                 }
465             }, null);
466
467             return task.Task;
468         }
469
470         internal Task ScanSpecificAPAsync(string essid)
471         {
472             Log.Info(Globals.LogTag, "ScanSpecificAPAsync " + essid);
473             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
474             IntPtr id;
475             lock (_callback_map)
476             {
477                 id = (IntPtr)_requestId++;
478                 _callback_map[id] = (error, key) =>
479                 {
480                     Log.Info(Globals.LogTag, "ScanSpecificAPAsync Done " + essid);
481                     if (error != (int)WiFiError.None)
482                     {
483                         Log.Error(Globals.LogTag, "Error occurs during WiFi scanning, " + (WiFiError)error);
484                         task.SetException(new InvalidOperationException("Error occurs during WiFi scanning, " + (WiFiError)error));
485                     }
486                     else
487                     {
488                         task.SetResult(true);
489                     }
490                     lock (_callback_map)
491                     {
492                         _callback_map.Remove(key);
493                     }
494                 };
495             }
496
497             context.Post((x) =>
498             {
499                 Log.Info(Globals.LogTag, "Interop.WiFi.ScanSpecificAPAsync");
500                 try
501                 {
502                     int ret = Interop.WiFi.ScanSpecificAP(GetSafeHandle(), essid, _callback_map[id], id);
503                     CheckReturnValue(ret, "ScanSpecificAP", "");
504                 }
505                 catch (Exception e)
506                 {
507                     Log.Error(Globals.LogTag, "Exception on ScanSpecificAPAsync\n" + e);
508                     task.SetException(e);
509                 }
510             }, null);
511
512             return task.Task;
513         }
514
515         internal Task BssidScanAsync()
516         {
517             Log.Info(Globals.LogTag, "BssidScanAsync");
518             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
519             IntPtr id;
520             lock (_callback_map)
521             {
522                 id = (IntPtr)_requestId++;
523                 _callback_map[id] = (error, key) =>
524                 {
525                     Log.Info(Globals.LogTag, "BssidScanAsync done");
526                     if (error != (int)WiFiError.None)
527                     {
528                         Log.Error(Globals.LogTag, "Error occurs during bssid scanning, " + (WiFiError)error);
529                         task.SetException(new InvalidOperationException("Error occurs during bssid scanning, " + (WiFiError)error));
530                     }
531                     else
532                     {
533                         task.SetResult(true);
534                     }
535                     lock (_callback_map)
536                     {
537                         _callback_map.Remove(key);
538                     }
539                 };
540             }
541
542             context.Post((x) =>
543             {
544                 Log.Info(Globals.LogTag, "Interop.WiFi.BssidScan");
545                 try
546                 {
547                     int ret = Interop.WiFi.BssidScan(GetSafeHandle(), _callback_map[id], id);
548                     CheckReturnValue(ret, "BssidScan", "");
549                 }
550                 catch (Exception e)
551                 {
552                     Log.Error(Globals.LogTag, "Exception on BssidScan\n" + e);
553                     task.SetException(e);
554                 }
555             }, null);
556
557             return task.Task;
558         }
559
560         private void CheckReturnValue(int ret, string method, string privilege)
561         {
562             if (ret != (int)WiFiError.None)
563             {
564                 Log.Error(Globals.LogTag, method + " Fail, Error - " + (WiFiError)ret);
565                 if (ret == (int)WiFiError.InvalidParameterError)
566                 {
567                     throw new InvalidOperationException("Invalid handle");
568                 }
569                 WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle(), privilege);
570             }
571         }
572     }
573 }