[WiFi] Add missing lock (#4616)
[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 WiFiScanState ScanState
132         {
133             get
134             {
135                 int state;
136                 int ret = Interop.WiFi.GetScanState(GetSafeHandle(), out state);
137                 if (ret != (int)WiFiError.None)
138                 {
139                     Log.Error(Globals.LogTag, "Failed to get scan state, Error - " + (WiFiError)ret);
140                     return WiFiScanState.NotScanning;
141                 }
142                 return (WiFiScanState)state;
143             }
144         }
145
146         internal static WiFiManagerImpl Instance
147         {
148             get
149             {
150                return _instance.Value;
151             }
152         }
153
154         private static ThreadLocal<HandleHolder> s_threadName = new ThreadLocal<HandleHolder>(() =>
155         {
156             Log.Info(Globals.LogTag, "In threadlocal delegate");
157             return new HandleHolder();
158         });
159
160         private WiFiManagerImpl()
161         {
162             Log.Info(Globals.LogTag, "WiFiManagerImpl constructor");
163         }
164
165         internal SafeWiFiManagerHandle GetSafeHandle()
166         {
167             return s_threadName.Value.GetSafeHandle();
168         }
169
170         internal SafeWiFiManagerHandle Initialize()
171         {
172             SafeWiFiManagerHandle handle;
173             int tid = Thread.CurrentThread.ManagedThreadId;
174             Log.Info(Globals.LogTag, "PInvoke wifi_manager_initialize");
175             int ret = Interop.WiFi.Initialize(tid, out handle);
176             if (ret != (int)WiFiError.None)
177             {
178                 Log.Error(Globals.LogTag, "Initialize Fail, Error - " + (WiFiError)ret);
179                 WiFiErrorFactory.ThrowWiFiException(ret, PrivilegeNetworkGet);
180             }
181             handle.SetTID(tid);
182             return handle;
183         }
184
185         internal IEnumerable<WiFiAP> GetFoundAPs()
186         {
187             Log.Info(Globals.LogTag, "GetFoundAPs");
188             List<WiFiAP> apList = new List<WiFiAP>();
189             Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
190             {
191                 if (apHandle != IntPtr.Zero)
192                 {
193                     IntPtr clonedHandle;
194                     Interop.WiFi.AP.Clone(out clonedHandle, apHandle);
195                     WiFiAP apItem = new WiFiAP(clonedHandle);
196                     apList.Add(apItem);
197                     return true;
198                 }
199                 return false;
200             };
201
202             int ret = Interop.WiFi.GetForeachFoundAPs(GetSafeHandle(), callback, IntPtr.Zero);
203             CheckReturnValue(ret, "GetForeachFoundAPs", PrivilegeNetworkGet);
204
205             return apList;
206         }
207
208         internal IEnumerable<WiFiAP> GetFoundSpecificAPs()
209         {
210             Log.Info(Globals.LogTag, "GetFoundSpecificAPs");
211             List<WiFiAP> apList = new List<WiFiAP>();
212             Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
213             {
214                 if (apHandle != IntPtr.Zero)
215                 {
216                     IntPtr clonedHandle;
217                     Interop.WiFi.AP.Clone(out clonedHandle, apHandle);
218                     WiFiAP apItem = new WiFiAP(clonedHandle);
219                     apList.Add(apItem);
220                     return true;
221                 }
222                 return false;
223
224             };
225
226             int ret = Interop.WiFi.GetForeachFoundSpecificAPs(GetSafeHandle(), callback, IntPtr.Zero);
227             CheckReturnValue(ret, "GetForeachFoundSpecificAPs", PrivilegeNetworkGet);
228             
229             return apList;
230         }
231
232         internal IEnumerable<WiFiAP> GetFoundBssids()
233         {
234             Log.Info(Globals.LogTag, "GetFoundBssids");
235             List<WiFiAP> apList = new List<WiFiAP>();
236             Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
237             {
238                 if (apHandle != IntPtr.Zero)
239                 {
240                     IntPtr clonedHandle;
241                     Interop.WiFi.AP.Clone(out clonedHandle, apHandle);
242                     WiFiAP apItem = new WiFiAP(clonedHandle);
243                     apList.Add(apItem);
244                     return true;
245                 }
246                 return false;
247             };
248
249             int ret = Interop.WiFi.GetForeachFoundBssids(GetSafeHandle(), callback, IntPtr.Zero);
250             CheckReturnValue(ret, "GetForeachFoundBssids", PrivilegeNetworkGet);
251
252             return apList;
253         }
254
255         internal IEnumerable<WiFiConfiguration> GetWiFiConfigurations()
256         {
257             Log.Debug(Globals.LogTag, "GetWiFiConfigurations");
258             List<WiFiConfiguration> configList = new List<WiFiConfiguration>();
259             Interop.WiFi.HandleCallback callback = (IntPtr configHandle, IntPtr userData) =>
260             {
261                 if (configHandle != IntPtr.Zero)
262                 {
263                     IntPtr clonedConfig;
264                     Interop.WiFi.Config.Clone(configHandle, out clonedConfig);
265                     WiFiConfiguration configItem = new WiFiConfiguration(clonedConfig);
266                     configList.Add(configItem);
267                     return true;
268                 }
269                 return false;
270             };
271
272             int ret = Interop.WiFi.Config.GetForeachConfiguration(GetSafeHandle(), callback, IntPtr.Zero);
273             CheckReturnValue(ret, "GetForeachConfiguration", PrivilegeNetworkProfile);
274             return configList;
275         }
276
277         internal void SaveWiFiNetworkConfiguration(WiFiConfiguration config)
278         {
279             Log.Debug(Globals.LogTag, "SaveWiFiNetworkConfiguration");
280             if (config == null)
281             {
282                 throw new ArgumentNullException("WiFi configuration is null");
283             }
284
285             IntPtr configHandle = config.GetHandle();
286             int ret = Interop.WiFi.Config.SaveConfiguration(GetSafeHandle(), configHandle);
287             CheckReturnValue(ret, "SaveConfiguration", PrivilegeNetworkProfile);
288        }
289
290         internal WiFiAP GetConnectedAP()
291         {
292             Log.Info(Globals.LogTag, "GetConnectedAP");
293             IntPtr apHandle;
294             int ret = Interop.WiFi.GetConnectedAP(GetSafeHandle(), out apHandle);
295             if (ret == (int)WiFiError.NoConnectionError)
296             {
297                 Log.Error(Globals.LogTag, "No connection " + (WiFiError)ret);
298                 return null;
299             }
300             CheckReturnValue(ret, "GetConnectedAP", PrivilegeNetworkGet);
301             WiFiAP ap = new WiFiAP(apHandle);
302             return ap;
303         }
304
305         internal Task ActivateAsync()
306         {
307             Log.Info(Globals.LogTag, "ActivateAsync");
308             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
309             IntPtr id;
310             lock (_callback_map)
311             {
312                 id = (IntPtr)_requestId++;
313                 _callback_map[id] = (error, key) =>
314                 {
315                     Log.Info(Globals.LogTag, "ActivateAsync done");
316                     if (error != (int)WiFiError.None)
317                     {
318                         Log.Error(Globals.LogTag, "Error occurs during WiFi activating, " + (WiFiError)error);
319                         task.SetException(WiFiErrorFactory.GetException(error, "Error occurs during WiFi activating"));
320                     }
321                     else
322                     {
323                         task.SetResult(true);
324                     }
325                     lock (_callback_map)
326                     {
327                         _callback_map.Remove(key);
328                     }
329                 };
330             }
331
332             context.Post((x) =>
333             {
334                 Log.Info(Globals.LogTag, "Interop.WiFi.ActivateAsync");
335                 try
336                 {
337                     int ret = (int)WiFiError.None;
338                     lock (_callback_map)
339                     {
340                         ret = Interop.WiFi.Activate(GetSafeHandle(), _callback_map[id], id);
341                     }
342                     CheckReturnValue(ret, "Activate", "");
343                 }
344                 catch (Exception e)
345                 {
346                     Log.Error(Globals.LogTag, "Exception on ActivateAsync\n" + e);
347                     task.SetException(e);
348                 }
349             }, null);
350
351             return task.Task;
352         }
353
354         internal Task ActivateWithWiFiPickerTestedAsync()
355         {
356             Log.Info(Globals.LogTag, "ActivateWithWiFiPickerTestedAsync");
357             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
358             IntPtr id;
359             lock (_callback_map)
360             {
361                 id = (IntPtr)_requestId++;
362                 _callback_map[id] = (error, key) =>
363                 {
364                     Log.Info(Globals.LogTag, "ActivateWithWiFiPickerTestedAsync done");
365                     if (error != (int)WiFiError.None)
366                     {
367                         Log.Error(Globals.LogTag, "Error occurs during WiFi activating, " + (WiFiError)error);
368                         task.SetException(WiFiErrorFactory.GetException(error, "Error occurs during WiFi activating"));
369                     }
370                     else
371                     {
372                         task.SetResult(true);
373                     }
374                     lock (_callback_map)
375                     {
376                         _callback_map.Remove(key);
377                     }
378                 };
379             }
380
381             context.Post((x) =>
382             {
383                 Log.Info(Globals.LogTag, "Interop.WiFi.ActivateWithWiFiPickerTestedAsync");
384                 try
385                 {
386                     int ret = (int)WiFiError.None;
387                     lock (_callback_map)
388                     {
389                         ret = Interop.WiFi.ActivateWithWiFiPickerTested(GetSafeHandle(), _callback_map[id], id);
390                     }
391                     CheckReturnValue(ret, "ActivateWithWiFiPickerTested", "");
392                 }
393                 catch (Exception e)
394                 {
395                     Log.Error(Globals.LogTag, "Exception on ActivateWithWiFiPickerTestedAsync\n" + e);
396                     task.SetException(e);
397                 }
398             }, null);
399             
400             return task.Task;
401         }
402
403         internal Task DeactivateAsync()
404         {
405             Log.Info(Globals.LogTag, "DeactivateAsync");
406             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
407             IntPtr id;
408             lock (_callback_map)
409             {
410                 id = (IntPtr)_requestId++;
411                 _callback_map[id] = (error, key) =>
412                 {
413                     Log.Info(Globals.LogTag, "DeactivateAsync done");
414                     if (error != (int)WiFiError.None)
415                     {
416                         Log.Error(Globals.LogTag, "Error occurs during WiFi deactivating, " + (WiFiError)error);
417                         task.SetException(WiFiErrorFactory.GetException(error, "Error occurs during WiFi deactivating"));
418                     }
419                     else
420                     {
421                         task.SetResult(true);
422                     }
423                     lock (_callback_map)
424                     {
425                         _callback_map.Remove(key);
426                     }
427                 };
428             }
429
430             context.Post((x) =>
431             {
432                 Log.Info(Globals.LogTag, "Interop.WiFi.Deactivate");
433                 try
434                 {
435                     int ret = Interop.WiFi.Deactivate(GetSafeHandle(), _callback_map[id], id);
436                     CheckReturnValue(ret, "Deactivate", "");
437                 }
438                 catch (Exception e)
439                 {
440                     Log.Error(Globals.LogTag, "Exception on Deactivate\n" + e);
441                     task.SetException(e);
442                 }
443             }, null);
444
445             return task.Task;           
446         }
447
448         internal Task ScanAsync()
449         {
450             Log.Info(Globals.LogTag, "ScanAsync");
451             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
452             IntPtr id;
453             lock (_callback_map)
454             {
455                 id = (IntPtr)_requestId++;
456                 _callback_map[id] = (error, key) =>
457                 {
458                     Log.Info(Globals.LogTag, "ScanAsync done");
459                     if (error != (int)WiFiError.None)
460                     {
461                         Log.Error(Globals.LogTag, "Error occurs during WiFi scanning, " + (WiFiError)error);
462                         task.SetException(new InvalidOperationException("Error occurs during WiFi scanning, " + (WiFiError)error));
463                     }
464                     else
465                     {
466                         task.SetResult(true);
467                     }
468                     lock (_callback_map)
469                     {
470                         _callback_map.Remove(key);
471                     }
472                 };
473             }
474
475             context.Post((x) =>
476             {
477                 Log.Info(Globals.LogTag, "Interop.WiFi.Scan");
478                 try
479                 {
480                     int ret = Interop.WiFi.Scan(GetSafeHandle(), _callback_map[id], id);
481                     CheckReturnValue(ret, "Scan", "");
482                 }
483                 catch (Exception e)
484                 {
485                     Log.Error(Globals.LogTag, "Exception on Scan\n" + e);
486                     task.SetException(e);
487                 }
488             }, null);
489
490             return task.Task;
491         }
492
493         internal Task ScanSpecificAPAsync(string essid)
494         {
495             Log.Info(Globals.LogTag, "ScanSpecificAPAsync " + essid);
496             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
497             IntPtr id;
498             lock (_callback_map)
499             {
500                 id = (IntPtr)_requestId++;
501                 _callback_map[id] = (error, key) =>
502                 {
503                     Log.Info(Globals.LogTag, "ScanSpecificAPAsync Done " + essid);
504                     if (error != (int)WiFiError.None)
505                     {
506                         Log.Error(Globals.LogTag, "Error occurs during WiFi scanning, " + (WiFiError)error);
507                         task.SetException(new InvalidOperationException("Error occurs during WiFi scanning, " + (WiFiError)error));
508                     }
509                     else
510                     {
511                         task.SetResult(true);
512                     }
513                     lock (_callback_map)
514                     {
515                         _callback_map.Remove(key);
516                     }
517                 };
518             }
519
520             context.Post((x) =>
521             {
522                 Log.Info(Globals.LogTag, "Interop.WiFi.ScanSpecificAPAsync");
523                 try
524                 {
525                     int ret = Interop.WiFi.ScanSpecificAP(GetSafeHandle(), essid, _callback_map[id], id);
526                     CheckReturnValue(ret, "ScanSpecificAP", "");
527                 }
528                 catch (Exception e)
529                 {
530                     Log.Error(Globals.LogTag, "Exception on ScanSpecificAPAsync\n" + e);
531                     task.SetException(e);
532                 }
533             }, null);
534
535             return task.Task;
536         }
537
538         internal Task BssidScanAsync()
539         {
540             Log.Info(Globals.LogTag, "BssidScanAsync");
541             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
542             IntPtr id;
543             lock (_callback_map)
544             {
545                 id = (IntPtr)_requestId++;
546                 _callback_map[id] = (error, key) =>
547                 {
548                     Log.Info(Globals.LogTag, "BssidScanAsync done");
549                     if (error != (int)WiFiError.None)
550                     {
551                         Log.Error(Globals.LogTag, "Error occurs during bssid scanning, " + (WiFiError)error);
552                         task.SetException(new InvalidOperationException("Error occurs during bssid scanning, " + (WiFiError)error));
553                     }
554                     else
555                     {
556                         task.SetResult(true);
557                     }
558                     lock (_callback_map)
559                     {
560                         _callback_map.Remove(key);
561                     }
562                 };
563             }
564
565             context.Post((x) =>
566             {
567                 Log.Info(Globals.LogTag, "Interop.WiFi.BssidScan");
568                 try
569                 {
570                     int ret = Interop.WiFi.BssidScan(GetSafeHandle(), _callback_map[id], id);
571                     CheckReturnValue(ret, "BssidScan", "");
572                 }
573                 catch (Exception e)
574                 {
575                     Log.Error(Globals.LogTag, "Exception on BssidScan\n" + e);
576                     task.SetException(e);
577                 }
578             }, null);
579
580             return task.Task;
581         }
582
583         private void CheckReturnValue(int ret, string method, string privilege)
584         {
585             if (ret != (int)WiFiError.None)
586             {
587                 Log.Error(Globals.LogTag, method + " Fail, Error - " + (WiFiError)ret);
588                 if (ret == (int)WiFiError.InvalidParameterError)
589                 {
590                     throw new InvalidOperationException("Invalid handle");
591                 }
592                 WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle(), privilege);
593             }
594         }
595     }
596 }