[Connection][WiFi] Fix exception handling in async methods (#154)
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.WiFi / Tizen.Network.WiFi / WiFiManagerImpl.cs
1 /*
2  * Copyright (c) 2016 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         internal string MacAddress
62         {
63             get
64             {
65                 if (String.IsNullOrEmpty(_macAddress))
66                 {
67                     string address;
68                     int ret = Interop.WiFi.GetMacAddress(GetSafeHandle(), out address);
69                     if (ret != (int)WiFiError.None)
70                     {
71                         Log.Error(Globals.LogTag, "Failed to get mac address, Error - " + (WiFiError)ret);
72                         _macAddress = "";
73                     }
74                     else
75                     {
76                         _macAddress = address;
77                     }
78                 }
79                 return _macAddress;
80             }
81         }
82
83         internal string InterfaceName
84         {
85             get
86             {
87                 string name;
88                 int ret = Interop.WiFi.GetNetworkInterfaceName(GetSafeHandle(), out name);
89                 if (ret != (int)WiFiError.None)
90                 {
91                     Log.Error(Globals.LogTag, "Failed to get interface name, Error - " + (WiFiError)ret);
92                     return "";
93                 }
94                 return name;
95             }
96         }
97
98         internal WiFiConnectionState ConnectionState
99         {
100             get
101             {
102                 int state;
103                 int ret = Interop.WiFi.GetConnectionState(GetSafeHandle(), out state);
104                 if (ret != (int)WiFiError.None)
105                 {
106                     Log.Error(Globals.LogTag, "Failed to get connection state, Error - " + (WiFiError)ret);
107                     return WiFiConnectionState.Failure;
108                 }
109                 return (WiFiConnectionState)state;
110             }
111         }
112
113         internal bool IsActive
114         {
115             get
116             {
117                 bool active;
118                 int ret = Interop.WiFi.IsActive(GetSafeHandle(), out active);
119                 if (ret != (int)WiFiError.None)
120                 {
121                     Log.Error(Globals.LogTag, "Failed to get isActive, Error - " + (WiFiError)ret);
122                 }
123                 return active;
124             }
125         }
126
127         internal static WiFiManagerImpl Instance
128         {
129             get
130             {
131                return _instance.Value;
132             }
133         }
134
135         private static ThreadLocal<HandleHolder> s_threadName = new ThreadLocal<HandleHolder>(() =>
136         {
137             Log.Info(Globals.LogTag, "In threadlocal delegate");
138             return new HandleHolder();
139         });
140
141         private WiFiManagerImpl()
142         {
143             Log.Info(Globals.LogTag, "WiFiManagerImpl constructor");
144         }
145
146         internal SafeWiFiManagerHandle GetSafeHandle()
147         {
148             return s_threadName.Value.GetSafeHandle();
149         }
150
151         internal SafeWiFiManagerHandle Initialize()
152         {
153             SafeWiFiManagerHandle handle;
154             int tid = Thread.CurrentThread.ManagedThreadId;
155             Log.Info(Globals.LogTag, "PInvoke wifi_manager_initialize");
156             int ret = Interop.WiFi.Initialize(tid, out handle);
157             if (ret != (int)WiFiError.None)
158             {
159                 Log.Error(Globals.LogTag, "Failed to initialize wifi, Error - " + (WiFiError)ret);
160                 WiFiErrorFactory.ThrowWiFiException(ret, "http://tizen.org/privilege/network.get");
161             }
162             handle.SetTID(tid);
163             return handle;
164         }
165
166         internal IEnumerable<WiFiAP> GetFoundAPs()
167         {
168             Log.Info(Globals.LogTag, "GetFoundAPs");
169             List<WiFiAP> apList = new List<WiFiAP>();
170             Interop.WiFi.HandleCallback callback = (IntPtr apHandle, IntPtr userData) =>
171             {
172                 if (apHandle != IntPtr.Zero)
173                 {
174                     IntPtr clonedHandle;
175                     Interop.WiFi.AP.Clone(out clonedHandle, apHandle);
176                     WiFiAP apItem = new WiFiAP(clonedHandle);
177                     apList.Add(apItem);
178                     return true;
179                 }
180                 return false;
181             };
182
183             int ret = Interop.WiFi.GetForeachFoundAPs(GetSafeHandle(), callback, IntPtr.Zero);
184             if (ret != (int)WiFiError.None)
185             {
186                 Log.Error(Globals.LogTag, "Failed to get all APs, Error - " + (WiFiError)ret);
187                 WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle(), "http://tizen.org/privilege/network.get");
188             }
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             if (ret != (int)WiFiError.None)
213             {
214                 Log.Error(Globals.LogTag, "Failed to get specific APs, Error - " + (WiFiError)ret);
215                 WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle(), "http://tizen.org/privilege/network.get");
216             }
217
218             return apList;
219         }
220
221         internal IEnumerable<WiFiConfiguration> GetWiFiConfigurations()
222         {
223             Log.Debug(Globals.LogTag, "GetWiFiConfigurations");
224             List<WiFiConfiguration> configList = new List<WiFiConfiguration>();
225             Interop.WiFi.HandleCallback callback = (IntPtr configHandle, IntPtr userData) =>
226             {
227                 if (configHandle != IntPtr.Zero)
228                 {
229                     IntPtr clonedConfig;
230                     Interop.WiFi.Config.Clone(configHandle, out clonedConfig);
231                     WiFiConfiguration configItem = new WiFiConfiguration(clonedConfig);
232                     configList.Add(configItem);
233                     return true;
234                 }
235                 return false;
236             };
237
238             int ret = Interop.WiFi.Config.GetForeachConfiguration(GetSafeHandle(), callback, IntPtr.Zero);
239             if (ret != (int)WiFiError.None)
240             {
241                 Log.Error(Globals.LogTag, "Failed to get configurations, Error - " + (WiFiError)ret);
242                 WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle(), "http://tizen.org/privilege/network.profile");
243             }
244
245             return configList;
246         }
247
248         internal void SaveWiFiNetworkConfiguration(WiFiConfiguration config)
249         {
250             Log.Debug(Globals.LogTag, "SaveWiFiNetworkConfiguration");
251             if (config == null)
252             {
253                 throw new ArgumentNullException("WiFi configuration is null");
254             }
255
256             IntPtr configHandle = config.GetHandle();
257             int ret = Interop.WiFi.Config.SaveConfiguration(GetSafeHandle(), configHandle);
258             if (ret != (int)WiFiError.None)
259             {
260                 Log.Error(Globals.LogTag, "Failed to save configuration, Error - " + (WiFiError)ret);
261                 WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle(), "http://tizen.org/privilege/network.profile");
262             }
263         }
264
265         internal WiFiAP GetConnectedAP()
266         {
267             Log.Info(Globals.LogTag, "GetConnectedAP");
268             IntPtr apHandle;
269             int ret = Interop.WiFi.GetConnectedAP(GetSafeHandle(), out apHandle);
270             if (ret != (int)WiFiError.None)
271             {
272                 if (ret == (int)WiFiError.NoConnectionError)
273                 {
274                     Log.Error(Globals.LogTag, "No connection " + (WiFiError)ret);
275                     return null;
276                 }
277                 else
278                 {
279                     Log.Error(Globals.LogTag, "Failed to get connected AP, Error - " + (WiFiError)ret);
280                     WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle(), "http://tizen.org/privilege/network.get");
281                 }
282             }
283             WiFiAP ap = new WiFiAP(apHandle);
284             return ap;
285         }
286
287         internal Task ActivateAsync()
288         {
289             Log.Info(Globals.LogTag, "ActivateAsync");
290             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
291             IntPtr id;
292             lock (_callback_map)
293             {
294                 id = (IntPtr)_requestId++;
295                 _callback_map[id] = (error, key) =>
296                 {
297                     Log.Info(Globals.LogTag, "ActivateAsync done");
298                     if (error != (int)WiFiError.None)
299                     {
300                         Log.Error(Globals.LogTag, "Error occurs during WiFi activating, " + (WiFiError)error);
301                         task.SetException(new InvalidOperationException("Error occurs during WiFi activating, " + (WiFiError)error));
302                     }
303                     else
304                     {
305                         task.SetResult(true);
306                     }
307                     lock (_callback_map)
308                     {
309                         _callback_map.Remove(key);
310                     }
311                 };
312             }
313
314             context.Post((x) =>
315             {
316                 Log.Info(Globals.LogTag, "Interop.WiFi.ActivateAsync");
317                 try
318                 {
319                     int ret = Interop.WiFi.Activate(GetSafeHandle(), _callback_map[id], id);
320                     if (ret != (int)WiFiError.None)
321                     {
322                         Log.Error(Globals.LogTag, "Failed to activate wifi, Error - " + (WiFiError)ret);
323                         WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle());
324                     }
325                 }
326                 catch (Exception e)
327                 {
328                     Log.Error(Globals.LogTag, "Exception on ActivateAsync\n" + e.ToString());
329                     task.SetException(e);
330                 }
331             }, null);
332
333             return task.Task;
334         }
335
336         internal Task ActivateWithWiFiPickerTestedAsync()
337         {
338             Log.Info(Globals.LogTag, "ActivateWithWiFiPickerTestedAsync");
339             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
340             IntPtr id;
341             lock (_callback_map)
342             {
343                 id = (IntPtr)_requestId++;
344                 _callback_map[id] = (error, key) =>
345                 {
346                     Log.Info(Globals.LogTag, "ActivateWithWiFiPickerTestedAsync done");
347                     if (error != (int)WiFiError.None)
348                     {
349                         Log.Error(Globals.LogTag, "Error occurs during WiFi activating, " + (WiFiError)error);
350                         task.SetException(new InvalidOperationException("Error occurs during WiFi activating, " + (WiFiError)error));
351                     }
352                     else
353                     {
354                         task.SetResult(true);
355                     }
356                     lock (_callback_map)
357                     {
358                         _callback_map.Remove(key);
359                     }
360                 };
361             }
362
363             context.Post((x) =>
364             {
365                 Log.Info(Globals.LogTag, "Interop.WiFi.ActivateWithWiFiPickerTestedAsync");
366                 try
367                 {
368                     int ret = Interop.WiFi.ActivateWithWiFiPickerTested(GetSafeHandle(), _callback_map[id], id);
369                     if (ret != (int)WiFiError.None)
370                     {
371                         Log.Error(Globals.LogTag, "Failed to activate wifi, Error - " + (WiFiError)ret);
372                         WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle());
373                     }
374                 }
375                 catch (Exception e)
376                 {
377                     Log.Error(Globals.LogTag, "Exception on ActivateWithWiFiPickerTestedAsync\n" + e.ToString());
378                     task.SetException(e);
379                 }
380             }, null);
381             
382             return task.Task;
383         }
384
385         internal Task DeactivateAsync()
386         {
387             Log.Info(Globals.LogTag, "DeactivateAsync");
388             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
389             IntPtr id;
390             lock (_callback_map)
391             {
392                 id = (IntPtr)_requestId++;
393                 _callback_map[id] = (error, key) =>
394                 {
395                     Log.Info(Globals.LogTag, "DeactivateAsync done");
396                     if (error != (int)WiFiError.None)
397                     {
398                         Log.Error(Globals.LogTag, "Error occurs during WiFi deactivating, " + (WiFiError)error);
399                         task.SetException(new InvalidOperationException("Error occurs during WiFi deactivating, " + (WiFiError)error));
400                     }
401                     else
402                     {
403                         task.SetResult(true);
404                     }
405                     lock (_callback_map)
406                     {
407                         _callback_map.Remove(key);
408                     }
409                 };
410             }
411
412             context.Post((x) =>
413             {
414                 Log.Info(Globals.LogTag, "Interop.WiFi.Deactivate");
415                 try
416                 {
417                     int ret = Interop.WiFi.Deactivate(GetSafeHandle(), _callback_map[id], id);
418                     if (ret != (int)WiFiError.None)
419                     {
420                         Log.Error(Globals.LogTag, "Failed to deactivate wifi, Error - " + (WiFiError)ret);
421                         WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle());
422                     }
423                 }
424                 catch (Exception e)
425                 {
426                     Log.Error(Globals.LogTag, "Exception on Deactivate\n" + e.ToString());
427                     task.SetException(e);
428                 }
429             }, null);
430
431             return task.Task;           
432         }
433
434         internal Task ScanAsync()
435         {
436             Log.Info(Globals.LogTag, "ScanAsync");
437             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
438             IntPtr id;
439             lock (_callback_map)
440             {
441                 id = (IntPtr)_requestId++;
442                 _callback_map[id] = (error, key) =>
443                 {
444                     Log.Info(Globals.LogTag, "ScanAsync done");
445                     if (error != (int)WiFiError.None)
446                     {
447                         Log.Error(Globals.LogTag, "Error occurs during WiFi scanning, " + (WiFiError)error);
448                         task.SetException(new InvalidOperationException("Error occurs during WiFi scanning, " + (WiFiError)error));
449                     }
450                     else
451                     {
452                         task.SetResult(true);
453                     }
454                     lock (_callback_map)
455                     {
456                         _callback_map.Remove(key);
457                     }
458                 };
459             }
460
461             context.Post((x) =>
462             {
463                 Log.Info(Globals.LogTag, "Interop.WiFi.Scan");
464                 try
465                 {
466                     int ret = Interop.WiFi.Scan(GetSafeHandle(), _callback_map[id], id);
467                     if (ret != (int)WiFiError.None)
468                     {
469                         Log.Error(Globals.LogTag, "Failed to scan all AP, Error - " + (WiFiError)ret);
470                         WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle());
471                     }
472                 }
473                 catch (Exception e)
474                 {
475                     Log.Error(Globals.LogTag, "Exception on Scan\n" + e.ToString());
476                     task.SetException(e);
477                 }
478             }, null);
479
480             return task.Task;
481         }
482
483         internal Task ScanSpecificAPAsync(string essid)
484         {
485             Log.Info(Globals.LogTag, "ScanSpecificAPAsync " + essid);
486             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
487             IntPtr id;
488             lock (_callback_map)
489             {
490                 id = (IntPtr)_requestId++;
491                 _callback_map[id] = (error, key) =>
492                 {
493                     Log.Info(Globals.LogTag, "ScanSpecificAPAsync Done " + essid);
494                     if (error != (int)WiFiError.None)
495                     {
496                         Log.Error(Globals.LogTag, "Error occurs during WiFi scanning, " + (WiFiError)error);
497                         task.SetException(new InvalidOperationException("Error occurs during WiFi scanning, " + (WiFiError)error));
498                     }
499                     else
500                     {
501                         task.SetResult(true);
502                     }
503                     lock (_callback_map)
504                     {
505                         _callback_map.Remove(key);
506                     }
507                 };
508             }
509
510             context.Post((x) =>
511             {
512                 Log.Info(Globals.LogTag, "Interop.WiFi.ScanSpecificAPAsync");
513                 try
514                 {
515                     int ret = Interop.WiFi.ScanSpecificAP(GetSafeHandle(), essid, _callback_map[id], id);
516                     if (ret != (int)WiFiError.None)
517                     {
518                         Log.Error(Globals.LogTag, "Failed to scan with specific AP, Error - " + (WiFiError)ret);
519                         WiFiErrorFactory.ThrowWiFiException(ret, GetSafeHandle().DangerousGetHandle());
520                     }
521                 }
522                 catch (Exception e)
523                 {
524                     Log.Error(Globals.LogTag, "Exception on ScanSpecificAPAsync\n" + e.ToString());
525                     task.SetException(e);
526                 }
527             }, null);
528
529             return task.Task;
530         }
531     }
532 }