[Connection][WiFi]Apply TizenSynchronizationContext for event handling (#138)
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Connection / Tizen.Network.Connection / ConnectionInternalManager.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.Linq;
20 using System.Text;
21 using System.Threading.Tasks;
22 using System.Runtime.InteropServices;
23 using System.Collections;
24 using System.Threading;
25 using Tizen.Applications;
26
27 namespace Tizen.Network.Connection
28 {
29     class HandleHolder
30     {
31         private IntPtr Handle;
32         private int _tid;
33
34         public HandleHolder()
35         {
36             _tid = Thread.CurrentThread.ManagedThreadId;
37             Log.Info(Globals.LogTag, "PInvoke connection_destroy for Thread " + _tid);
38             int ret = Interop.Connection.Create(_tid, out Handle);
39             Log.Info(Globals.LogTag, "Handle: " + Handle);
40             if(ret != (int)ConnectionError.None)
41             {
42                 ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.tethering.bluetooth " + "http://tizen.org/feature/network.ethernet");
43                 ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.get)");
44                 ConnectionErrorFactory.ThrowConnectionException(ret);
45             }
46         }
47
48         ~HandleHolder()
49         {
50             Destroy();
51         }
52
53         internal IntPtr GetHandle()
54         {
55             Log.Debug(Globals.LogTag, "handleholder handle = " + Handle);
56             return Handle;
57         }
58
59         private void Destroy()
60         {
61
62             Log.Info(Globals.LogTag, "PInvoke connection_destroy for Thread " + _tid);
63             Interop.Connection.Destroy(_tid, Handle);
64             if (Handle != IntPtr.Zero)
65             {
66                 Handle = IntPtr.Zero;
67             }
68         }
69     }
70
71     internal class ConnectionInternalManager
72     {
73         private static readonly Lazy<ConnectionInternalManager> s_instance =
74             new Lazy<ConnectionInternalManager>(() => new ConnectionInternalManager());
75
76         private EventHandler<ConnectionTypeEventArgs> _ConnectionTypeChanged = null;
77         private EventHandler<AddressEventArgs> _IPAddressChanged = null;
78         private EventHandler<EthernetCableStateEventArgs> _EthernetCableStateChanged = null;
79         private EventHandler<AddressEventArgs> _ProxyAddressChanged = null;
80
81         private Interop.Connection.ConnectionAddressChangedCallback _connectionAddressChangedCallback;
82         private Interop.Connection.ConnectionTypeChangedCallback _connectionTypeChangedCallback;
83         private Interop.Connection.ConnectionAddressChangedCallback _proxyAddressChangedCallback;
84         private Interop.Connection.EthernetCableStateChangedCallback _ethernetCableStateChangedCallback;
85
86         private TizenSynchronizationContext context = new TizenSynchronizationContext();
87
88         internal static ConnectionInternalManager Instance
89         {
90             get
91             {
92                 return s_instance.Value;
93             }
94         }
95
96         private static ThreadLocal<HandleHolder> s_threadName = new ThreadLocal<HandleHolder>(() =>
97         {
98             Log.Info(Globals.LogTag, "In threadlocal delegate");
99             return new HandleHolder();
100         });
101
102         private ConnectionInternalManager()
103         {
104             Log.Info(Globals.LogTag, "ConnectionInternalManager constructor");
105         }
106
107         ~ConnectionInternalManager()
108         {
109             UnregisterEvents();
110         }
111
112         internal IntPtr GetHandle()
113         {
114             return s_threadName.Value.GetHandle();
115         }
116
117         internal event EventHandler<ConnectionTypeEventArgs> ConnectionTypeChanged
118         {
119             add
120             {
121                 context.Post((x) =>
122                         {
123                             if (_ConnectionTypeChanged == null)
124                             {
125                                 ConnectionTypeChangedStart();
126                             }
127                             _ConnectionTypeChanged += value;
128                         }, null);
129             }
130             remove
131             {
132                 context.Post((x) =>
133                         {
134                             _ConnectionTypeChanged -= value;
135                             if (_ConnectionTypeChanged == null)
136                             {
137                                 ConnectionTypeChangedStop();
138                             }
139                         }, null);
140             }
141         }
142
143         private void ConnectionTypeChangedStart()
144         {
145             _connectionTypeChangedCallback = (ConnectionType type, IntPtr user_data) =>
146             {
147                 if (_ConnectionTypeChanged != null)
148                 {
149                     _ConnectionTypeChanged(null, new ConnectionTypeEventArgs(type));
150                 }
151             };
152
153             int ret = Interop.Connection.SetTypeChangedCallback(GetHandle(), _connectionTypeChangedCallback, IntPtr.Zero);
154             if ((ConnectionError)ret != ConnectionError.None)
155             {
156                 Log.Error(Globals.LogTag, "It failed to register connection type changed callback, " + (ConnectionError)ret);
157                 ConnectionErrorFactory.ThrowConnectionException(ret);
158             }
159         }
160
161         private void ConnectionTypeChangedStop()
162         {
163             int ret = Interop.Connection.UnsetTypeChangedCallback(GetHandle());
164             if ((ConnectionError)ret != ConnectionError.None)
165             {
166                 Log.Error(Globals.LogTag, "It failed to unregister connection type changed callback, " + (ConnectionError)ret);
167                 ConnectionErrorFactory.ThrowConnectionException(ret);
168             }
169         }
170
171         internal event EventHandler<EthernetCableStateEventArgs> EthernetCableStateChanged
172         {
173             add
174             {
175                 context.Post((x) =>
176                         {
177                             if (_EthernetCableStateChanged == null)
178                             {
179                                 EthernetCableStateChangedStart();
180                             }
181                             _EthernetCableStateChanged += value;
182                         }, null);
183             }
184             remove
185             {
186                 context.Post((x) =>
187                         {
188                             _EthernetCableStateChanged -= value;
189                             if (_EthernetCableStateChanged == null)
190                             {
191                                 EthernetCableStateChangedStop();
192                             }
193                         }, null);
194             }
195         }
196
197         private void EthernetCableStateChangedStart()
198         {
199             _ethernetCableStateChangedCallback = (EthernetCableState state, IntPtr user_data) =>
200             {
201                 if (_EthernetCableStateChanged != null)
202                 {
203                     _EthernetCableStateChanged(null, new EthernetCableStateEventArgs(state));
204                 }
205             };
206             int ret = Interop.Connection.SetEthernetCableStateChagedCallback(GetHandle(),
207                     _ethernetCableStateChangedCallback, IntPtr.Zero);
208             if ((ConnectionError)ret != ConnectionError.None)
209             {
210                 Log.Error(Globals.LogTag,
211                         "It failed to register ethernet cable state changed callback, " +
212                         (ConnectionError)ret);
213                 ConnectionErrorFactory.ThrowConnectionException(ret);
214             }
215         }
216
217         private void EthernetCableStateChangedStop()
218         {
219             int ret = Interop.Connection.UnsetEthernetCableStateChagedCallback(GetHandle());
220             if ((ConnectionError)ret != ConnectionError.None)
221             {
222                 Log.Error(Globals.LogTag,
223                         "It failed to unregister ethernet cable state changed callback, " + 
224                         (ConnectionError)ret);
225                 ConnectionErrorFactory.ThrowConnectionException(ret);
226             }
227         }
228
229         internal event EventHandler<AddressEventArgs> IPAddressChanged
230         {
231             add
232             {
233                 context.Post((x) =>
234                         {
235                             if (_IPAddressChanged == null)
236                             {
237                                 IPAddressChangedStart();
238                             }
239                             _IPAddressChanged += value;
240                         }, null);
241             }
242
243             remove
244             {
245                 context.Post((x) =>
246                         {
247                             _IPAddressChanged -= value;
248                             if (_IPAddressChanged == null)
249                             {
250                                 IPAddressChangedStop();
251                             }
252                         }, null);
253             }
254         }
255
256         private void IPAddressChangedStart()
257         {
258             _connectionAddressChangedCallback = (IntPtr IPv4, IntPtr IPv6, IntPtr UserData) =>
259             {
260                 if (_IPAddressChanged != null)
261                 {
262                     string ipv4 = Marshal.PtrToStringAnsi(IPv4);
263                     string ipv6 = Marshal.PtrToStringAnsi(IPv6);
264
265                     if ((string.IsNullOrEmpty(ipv4) == false) || (string.IsNullOrEmpty(ipv6) == false))
266                     {
267                         _IPAddressChanged(null, new AddressEventArgs(ipv4, ipv6));
268                     }
269                 }
270             };
271
272             int ret = Interop.Connection.SetIPAddressChangedCallback(GetHandle(), _connectionAddressChangedCallback, IntPtr.Zero);
273             if ((ConnectionError)ret != ConnectionError.None)
274             {
275                 Log.Error(Globals.LogTag, "It failed to register callback for changing IP address, " + (ConnectionError)ret);
276             }
277         }
278
279         private void IPAddressChangedStop()
280         {
281             int ret = Interop.Connection.UnsetIPAddressChangedCallback(GetHandle());
282             if ((ConnectionError)ret != ConnectionError.None)
283             {
284                 Log.Error(Globals.LogTag, "It failed to unregister callback for changing IP address, " + (ConnectionError)ret);
285             }
286         }
287
288         internal event EventHandler<AddressEventArgs> ProxyAddressChanged
289         {
290             add
291             {
292                 context.Post((x) =>
293                         {
294                             if (_ProxyAddressChanged == null)
295                             {
296                                ProxyAddressChangedStart();
297                             }
298                             _ProxyAddressChanged += value;
299                         }, null);
300             }
301             remove
302             {
303                 context.Post((x) =>
304                         {
305                             _ProxyAddressChanged -= value;
306                             if (_ProxyAddressChanged == null)
307                             {
308                                 ProxyAddressChangedStop();
309                             }
310                         }, null);
311             }
312         }
313
314         private void ProxyAddressChangedStart()
315         {
316             _proxyAddressChangedCallback = (IntPtr IPv4, IntPtr IPv6, IntPtr UserData) =>
317             {
318                 if (_ProxyAddressChanged != null)
319                 {
320                     string ipv4 = Marshal.PtrToStringAnsi(IPv4);
321                     string ipv6 = Marshal.PtrToStringAnsi(IPv6);
322
323                     if ((string.IsNullOrEmpty(ipv4) == false) || (string.IsNullOrEmpty(ipv6) == false))
324                     {
325                         _ProxyAddressChanged(null, new AddressEventArgs(ipv4, ipv6));
326                     }
327                 }
328             };
329
330             int ret = Interop.Connection.SetProxyAddressChangedCallback(GetHandle(), _proxyAddressChangedCallback, IntPtr.Zero);
331             if ((ConnectionError)ret != ConnectionError.None)
332             {
333                 Log.Error(Globals.LogTag, "It failed to register callback for changing proxy address, " + (ConnectionError)ret);
334             }
335         }
336
337         private void ProxyAddressChangedStop()
338         {
339             int ret = Interop.Connection.UnsetProxyAddressChangedCallback(GetHandle());
340             if ((ConnectionError)ret != ConnectionError.None)
341             {
342                 Log.Error(Globals.LogTag, "It failed to unregister callback for changing proxy address, " + (ConnectionError)ret);
343             }
344         }
345
346         private void UnregisterEvents()
347         {
348             if (_ConnectionTypeChanged != null)
349             {
350                 ConnectionTypeChangedStop();
351             }
352             if (_IPAddressChanged != null)
353             {
354                 IPAddressChangedStop();
355             }
356             if (_EthernetCableStateChanged != null)
357             {
358                 EthernetCableStateChangedStop();
359             }
360             if (_ProxyAddressChanged != null)
361             {
362                 ProxyAddressChangedStop();
363             }
364         }
365
366         internal int GetProfileIterator(ProfileListType type, out IntPtr iterator)
367         {
368             return Interop.Connection.GetProfileIterator(GetHandle(), (int)type, out iterator);
369         }
370
371         internal bool HasNext(IntPtr iterator)
372         {
373             return Interop.Connection.HasNextProfileIterator(iterator);
374         }
375
376         internal int NextProfileIterator(IntPtr iterator, out IntPtr profileHandle)
377         {
378             return Interop.Connection.GetNextProfileIterator(iterator, out profileHandle);
379         }
380
381         internal int DestoryProfileIterator(IntPtr iterator)
382         {
383             return Interop.Connection.DestroyProfileIterator(iterator);
384         }
385
386         internal System.Net.IPAddress GetIPAddress(AddressFamily family)
387         {
388             Log.Info(Globals.LogTag, "GetIPAddress " + family);
389             IntPtr ip;
390             int ret = Interop.Connection.GetIPAddress(GetHandle(), (int)family, out ip);
391             if ((ConnectionError)ret != ConnectionError.None)
392             {
393                 Log.Error(Globals.LogTag, "It failed to get IP address, " + (ConnectionError)ret);
394                 ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.tethering.bluetooth " + "http://tizen.org/feature/network.ethernet");
395                 ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
396                 ConnectionErrorFactory.ThrowConnectionException(ret);
397             }
398
399             string result = Marshal.PtrToStringAnsi(ip);
400             Interop.Libc.Free(ip);
401             Log.Info(Globals.LogTag, "IPAddress " + result + " (" + result.Length + ")");
402             if (result.Length == 0)
403             {
404                 if (family == AddressFamily.IPv4)
405                     return System.Net.IPAddress.Parse("0.0.0.0");
406                 else
407                     return System.Net.IPAddress.Parse("::");
408             }
409             return System.Net.IPAddress.Parse(result);
410         }
411
412         internal IEnumerable<System.Net.IPAddress> GetAllIPv6Addresses(ConnectionType type)
413         {
414             Log.Debug(Globals.LogTag, "GetAllIPv6Addresses");
415             List<System.Net.IPAddress> ipList = new List<System.Net.IPAddress>();
416             Interop.Connection.IPv6AddressCallback callback = (IntPtr ipv6Address, IntPtr userData) =>
417             {
418                 if (ipv6Address != IntPtr.Zero)
419                 {
420                     string ipv6 = Marshal.PtrToStringAnsi(ipv6Address);
421                     if (ipv6.Length == 0)
422                         ipList.Add(System.Net.IPAddress.Parse("::"));
423                     else
424                         ipList.Add(System.Net.IPAddress.Parse(ipv6));
425                     return true;
426                 }
427                 return false;
428             };
429
430             int ret = Interop.Connection.GetAllIPv6Addresses(GetHandle(), (int)type, callback, IntPtr.Zero);
431             if (ret != (int)ConnectionError.None)
432             {
433                 Log.Error(Globals.LogTag, "Failed to get all IPv6 addresses, Error - " + (ConnectionError)ret);
434                 ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.tethering.bluetooth " + "http://tizen.org/feature/network.ethernet");
435                 ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
436                 ConnectionErrorFactory.ThrowConnectionException(ret);
437             }
438
439             return ipList;
440         }
441
442         internal string GetProxy(AddressFamily family)
443         {
444             Log.Debug(Globals.LogTag, "GetProxy " + family);
445             IntPtr ip;
446             int ret = Interop.Connection.GetProxy(GetHandle(), (int)family, out ip);
447             if ((ConnectionError)ret != ConnectionError.None)
448             {
449                 Log.Error(Globals.LogTag, "It failed to get proxy, " + (ConnectionError)ret);
450                 ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.tethering.bluetooth " + "http://tizen.org/feature/network.ethernet");
451                 ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
452                 ConnectionErrorFactory.ThrowConnectionException(ret);
453             }
454
455             string result = Marshal.PtrToStringAnsi(ip);
456             Interop.Libc.Free(ip);
457             return result;
458         }
459
460         internal string GetMacAddress(ConnectionType type)
461         {
462             Log.Info(Globals.LogTag, "GetMacAddress " + type);
463             IntPtr mac;
464             int ret = Interop.Connection.GetMacAddress(GetHandle(), (int)type, out mac);
465             if ((ConnectionError)ret != ConnectionError.None)
466             {
467                 Log.Error(Globals.LogTag, "It failed to get mac address, " + (ConnectionError)ret);
468                 ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.ethernet");
469                 ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
470                 ConnectionErrorFactory.ThrowConnectionException(ret);
471             }
472
473             string result = Marshal.PtrToStringAnsi(mac);
474             Interop.Libc.Free(mac);
475             return result;
476         }
477
478         internal long GetStatistics(ConnectionType connectionType, StatisticsType statisticsType)
479         {
480             Log.Debug(Globals.LogTag, "GetStatistics " + connectionType + ", " + statisticsType);
481             long size;
482             int ret = Interop.Connection.GetStatistics(GetHandle(), (int)connectionType,
483                     (int)statisticsType, out size);
484             if ((ConnectionError)ret != ConnectionError.None)
485             {
486                 Log.Error(Globals.LogTag, "It failed to get statistics, " + (ConnectionError)ret);
487                 ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.telephony");
488                 ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.get)");
489                 ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
490                 ConnectionErrorFactory.ThrowConnectionException(ret);
491             }
492             return size;
493         }
494
495         internal void ResetStatistics(ConnectionType connectionType, StatisticsType statisticsType)
496         {
497             Log.Debug(Globals.LogTag, "ResetStatistics " + connectionType + ", " + statisticsType);
498             int ret = Interop.Connection.ResetStatistics(GetHandle(), (int)connectionType,
499                     (int)statisticsType);
500             if ((ConnectionError)ret != ConnectionError.None)
501             {
502                 Log.Error(Globals.LogTag, "It failed to reset statistics, " + (ConnectionError)ret);
503                 ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.telephony");
504                 ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.set)");
505                 ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
506                 ConnectionErrorFactory.ThrowConnectionException(ret);
507             }
508         }
509
510         internal void AddRoute(AddressFamily family, string interfaceName, System.Net.IPAddress address, System.Net.IPAddress gateway)
511         {
512             if (interfaceName != null && address != null && gateway != null)
513             {
514                 Log.Debug(Globals.LogTag, "AddRoute " + family + ", " + interfaceName + ", " + address + ", " + gateway);
515                 int ret = Interop.Connection.AddRoute(GetHandle(), family, interfaceName, address.ToString(), gateway.ToString());
516                 if ((ConnectionError)ret != ConnectionError.None)
517                 {
518                     Log.Error(Globals.LogTag, "It failed to add route to the routing table, " + (ConnectionError)ret);
519                     ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.tethering.bluetooth " + "http://tizen.org/feature/network.ethernet");
520                     ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.set)");
521                     ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
522                     ConnectionErrorFactory.ThrowConnectionException(ret);
523                 }
524             }
525
526             else
527             {
528                 throw new ArgumentNullException("Arguments are null");
529             }
530         }
531
532         internal void RemoveRoute(AddressFamily family, string interfaceName, System.Net.IPAddress address, System.Net.IPAddress gateway)
533         {
534             if (interfaceName != null && address != null && gateway != null)
535             {
536                 Log.Debug(Globals.LogTag, "RemoveRoute " + family + ", " + interfaceName + ", " + address + ", " + gateway);
537                 int ret = Interop.Connection.RemoveRoute(GetHandle(), family, interfaceName, address.ToString(), gateway.ToString());
538                 if ((ConnectionError)ret != ConnectionError.None)
539                 {
540                     Log.Error(Globals.LogTag, "It failed to remove route from the routing table, " + (ConnectionError)ret);
541                     ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.tethering.bluetooth " + "http://tizen.org/feature/network.ethernet");
542                     ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.set)");
543                     ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
544                     ConnectionErrorFactory.ThrowConnectionException(ret);
545                 }
546             }
547
548             else
549             {
550                 throw new ArgumentNullException("Arguments are null");
551             }
552         }
553
554         internal ConnectionType ConnectionType
555         {
556             get
557             {
558                 Log.Info(Globals.LogTag, "get ConnectionType");
559                 int type = 0;
560                 int ret = Interop.Connection.GetType(GetHandle(), out type);
561                 if ((ConnectionError)ret != ConnectionError.None)
562                 {
563                     Log.Error(Globals.LogTag, "It failed to get connection type, " + (ConnectionError)ret);
564                     ConnectionErrorFactory.ThrowConnectionException(ret);
565                 }
566                 return (ConnectionType)type;
567             }
568         }
569
570         internal CellularState CellularState
571         {
572             get
573             {
574                 Log.Info(Globals.LogTag, "get CellularState");
575                 int type = 0;
576                 int ret = Interop.Connection.GetCellularState(GetHandle(), out type);
577                 if ((ConnectionError)ret != ConnectionError.None)
578                 {
579                     Log.Error(Globals.LogTag, "It failed to get cellular state, " + (ConnectionError)ret);
580                     ConnectionErrorFactory.ThrowConnectionException(ret);
581                 }
582                 return (CellularState)type;
583             }
584         }
585
586         internal ConnectionState WiFiState
587         {
588             get
589             {
590                 Log.Info(Globals.LogTag, "get WiFiState");
591                 int type = 0;
592                 int ret = Interop.Connection.GetWiFiState(GetHandle(), out type);
593                 if ((ConnectionError)ret != ConnectionError.None)
594                 {
595                     Log.Error(Globals.LogTag, "It failed to get wifi state, " + (ConnectionError)ret);
596                     ConnectionErrorFactory.ThrowConnectionException(ret);
597                 }
598                 return (ConnectionState)type;
599             }
600         }
601
602         internal ConnectionState BluetoothState
603         {
604             get
605             {
606                 Log.Info(Globals.LogTag, "get BluetoothState");
607                 int type = 0;
608                 int ret = Interop.Connection.GetBtState(GetHandle(), out type);
609                 if ((ConnectionError)ret != ConnectionError.None)
610                 {
611                     Log.Error(Globals.LogTag, "It failed to get bluetooth state, " + (ConnectionError)ret);
612                     ConnectionErrorFactory.ThrowConnectionException(ret);
613                 }
614                 return (ConnectionState)type;
615             }
616         }
617
618         internal ConnectionState EthernetState
619         {
620             get
621             {
622                 Log.Info(Globals.LogTag, "get ConnectionType");
623                 int type = 0;
624                 int ret = Interop.Connection.GetEthernetState(GetHandle(), out type);
625                 if ((ConnectionError)ret != ConnectionError.None)
626                 {
627                     Log.Error(Globals.LogTag, "It failed to get ethernet state, " + (ConnectionError)ret);
628                     ConnectionErrorFactory.ThrowConnectionException(ret);
629                 }
630                 return (ConnectionState)type;
631             }
632         }
633
634         internal EthernetCableState EthernetCableState
635         {
636             get
637             {
638                 Log.Info(Globals.LogTag, "get EthernetCableState");
639                 int type = 0;
640                 int ret = Interop.Connection.GetEthernetCableState(GetHandle(), out type);
641                 if ((ConnectionError)ret != ConnectionError.None)
642                 {
643                     Log.Error(Globals.LogTag, "It failed to get ethernet cable state, " + (ConnectionError)ret);
644                     ConnectionErrorFactory.ThrowConnectionException(ret);
645                 }
646                 return (EthernetCableState)type;
647             }
648         }
649
650         internal IntPtr CreateCellularProfile(ConnectionProfileType type, string keyword)
651         {
652             Log.Debug(Globals.LogTag, "CreateCellularProfile, " + type + ", " + keyword);
653             if (keyword != null)
654             {
655                 IntPtr handle = IntPtr.Zero;
656                 int ret = Interop.ConnectionProfile.Create((int)type, keyword, out handle);
657                 if ((ConnectionError)ret != ConnectionError.None)
658                 {
659                     Log.Error(Globals.LogTag, "It failed to Create profile, " + (ConnectionError)ret);
660                     ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.telephony");
661                     ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.get)");
662                     ConnectionErrorFactory.ThrowConnectionException(ret);
663                 }
664
665                 return handle;
666             }
667
668             else
669             {
670                 throw new ArgumentNullException("Keyword is null");
671             }
672         }
673
674         internal void AddCellularProfile(CellularProfile profile)
675         {
676
677             Log.Debug(Globals.LogTag, "AddCellularProfile");
678             if (profile != null)
679             {
680                 if (profile.Type == ConnectionProfileType.Cellular)
681                 {
682                     int ret = Interop.Connection.AddProfile(GetHandle(), profile.ProfileHandle);
683                     if ((ConnectionError)ret != ConnectionError.None)
684                     {
685                         Log.Error(Globals.LogTag, "Failed to add cellular profile, " + (ConnectionError)ret);
686                         ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony");
687                         ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.profile)");
688                         ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero || profile.ProfileHandle == IntPtr.Zero), "Connection or Profile Handle may have been disposed or released");
689                         ConnectionErrorFactory.ThrowConnectionException(ret);
690                     }
691                 }
692
693                 else
694                 {
695                     throw new ArgumentException("Profile type is not cellular");
696                 }
697             }
698
699             else
700             {
701                 throw new ArgumentNullException("Profile is null");
702             }
703         }
704
705         internal void RemoveProfile(ConnectionProfile profile)
706         {
707             Log.Debug(Globals.LogTag, "RemoveProfile");
708             if (profile != null)
709             {
710                 int ret = Interop.Connection.RemoveProfile(GetHandle(), profile.ProfileHandle);
711                 if ((ConnectionError)ret != ConnectionError.None)
712                 {
713                     Log.Error(Globals.LogTag, "It failed to remove profile, " + (ConnectionError)ret);
714                     ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.telephony");
715                     ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero || profile.ProfileHandle == IntPtr.Zero), "Connection or Profile Handle may have been disposed or released");
716                     ConnectionErrorFactory.ThrowConnectionException(ret);
717                 }
718             }
719
720             else
721             {
722                 throw new ArgumentNullException("Profile is null");
723             }
724         }
725
726         internal void UpdateProfile(ConnectionProfile profile)
727         {
728             Log.Info(Globals.LogTag, "UpdateProfile");
729             if (profile != null)
730             {
731                 int ret = Interop.Connection.UpdateProfile(GetHandle(), profile.ProfileHandle);
732                 if ((ConnectionError)ret != ConnectionError.None)
733                 {
734                     Log.Error(Globals.LogTag, "It failed to update profile, " + (ConnectionError)ret);
735                     ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.ethernet");
736                     ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero || profile.ProfileHandle == IntPtr.Zero), "Connection or Profile Handle may have been disposed or released");
737                     ConnectionErrorFactory.ThrowConnectionException(ret);
738                 }
739             }
740
741             else
742             {
743                 throw new ArgumentNullException("Profile is null");
744             }
745         }
746
747         internal ConnectionProfile GetCurrentProfile()
748         {
749             Log.Info(Globals.LogTag, "GetCurrentProfile");
750             IntPtr ProfileHandle;
751             int ret = Interop.Connection.GetCurrentProfile(GetHandle(), out ProfileHandle);
752             if ((ConnectionError)ret != ConnectionError.None)
753             {
754                 if ((ConnectionError)ret == ConnectionError.NoConnection)
755                 {
756                     Log.Error(Globals.LogTag, "No connection " + (ConnectionError)ret);
757                     return null;
758                 }
759                 else
760                 {
761                     Log.Error(Globals.LogTag, "It failed to get current profile, " + (ConnectionError)ret);
762                     ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.tethering.bluetooth " + "http://tizen.org/feature/network.ethernet");
763                     ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.get)");
764                     ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
765                     ConnectionErrorFactory.ThrowConnectionException(ret);
766                 }
767             }
768
769             ConnectionProfile Profile = new ConnectionProfile(ProfileHandle);
770             return Profile;
771         }
772
773         internal ConnectionProfile GetDefaultCellularProfile(CellularServiceType type)
774         {
775             Log.Debug(Globals.LogTag, "GetDefaultCellularProfile");
776             IntPtr ProfileHandle;
777             int ret = Interop.Connection.GetDefaultCellularServiceProfile(GetHandle(), (int)type, out ProfileHandle);
778             if ((ConnectionError)ret != ConnectionError.None)
779             {
780                 Log.Error(Globals.LogTag, "Error: " + ret);
781                 Log.Error(Globals.LogTag, "It failed to get default cellular profile, " + (ConnectionError)ret);
782                 ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony");
783                 ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.get)");
784                 ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
785                 ConnectionErrorFactory.ThrowConnectionException(ret);
786             }
787
788             CellularProfile Profile = new CellularProfile(ProfileHandle);
789             return Profile;
790         }
791
792         internal Task SetDefaultCellularProfile(CellularServiceType type, ConnectionProfile profile)
793         {
794             Log.Debug(Globals.LogTag, "SetDefaultCellularProfile");
795             if (profile != null)
796             {
797                 TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
798                 Interop.Connection.ConnectionCallback Callback = (ConnectionError Result, IntPtr Data) =>
799                 {
800                     if (Result != ConnectionError.None)
801                     {
802                         Log.Error(Globals.LogTag, "Error occurs during set default cellular profile, " + Result);
803                         task.SetException(new InvalidOperationException("Error occurs during set default cellular profile, " + Result));
804                     }
805                     else
806                     {
807                         task.SetResult(true);
808                     }
809                 };
810
811                 int ret = Interop.Connection.SetDefaultCellularServiceProfileAsync(GetHandle(), (int)type, profile.ProfileHandle, Callback, (IntPtr)0);
812                 if ((ConnectionError)ret != ConnectionError.None)
813                 {
814                     Log.Error(Globals.LogTag, "It failed to set default cellular profile, " + (ConnectionError)ret);
815                     ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony");
816                     ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero || profile.ProfileHandle == IntPtr.Zero), "Connection or Profile Handle may have been disposed or released");
817                     ConnectionErrorFactory.ThrowConnectionException(ret);
818                 }
819
820                 return task.Task;
821             }
822
823             else
824             {
825                 throw new ArgumentNullException("Profile is null");
826             }
827         }
828
829
830         internal Task<IEnumerable<ConnectionProfile>> GetProfileListAsync(ProfileListType type)
831         {
832             Log.Debug(Globals.LogTag, "GetProfileListAsync");
833             var task = new TaskCompletionSource<IEnumerable<ConnectionProfile>>();
834
835             List<ConnectionProfile> Result = new List<ConnectionProfile>();
836             IntPtr iterator;
837             int ret = Interop.Connection.GetProfileIterator(GetHandle(), (int)type, out iterator);
838             if ((ConnectionError)ret != ConnectionError.None)
839             {
840                 Log.Error(Globals.LogTag, "It failed to get profile iterator, " + (ConnectionError)ret);
841                 ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.tethering.bluetooth " + "http://tizen.org/feature/network.ethernet");
842                 ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.get)");
843                 ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero), "Connection Handle may have been disposed or released");
844                 ConnectionErrorFactory.ThrowConnectionException(ret);
845             }
846
847             while (Interop.Connection.HasNextProfileIterator(iterator))
848             {
849                 IntPtr nextH;
850                 IntPtr profileH;
851                 Interop.Connection.GetNextProfileIterator(iterator, out nextH);
852                 Interop.ConnectionProfile.Clone(out profileH, nextH);
853
854                 int profileType;
855                 Interop.ConnectionProfile.GetType(profileH, out profileType);
856
857                 if ((ConnectionProfileType)profileType == ConnectionProfileType.WiFi)
858                 {
859                     WiFiProfile cur = new WiFiProfile(profileH);
860                     Result.Add(cur);
861                 }
862                 else if ((ConnectionProfileType)profileType == ConnectionProfileType.Cellular)
863                 {
864                     CellularProfile cur = new CellularProfile(profileH);
865                     Result.Add(cur);
866                 }
867                 else {
868                     ConnectionProfile cur = new ConnectionProfile(profileH);
869                     Result.Add(cur);
870                 }
871             }
872             Interop.Connection.DestroyProfileIterator(iterator);
873             task.SetResult(Result);
874             return task.Task;
875         }
876
877         internal Task OpenProfileAsync(ConnectionProfile profile)
878         {
879             Log.Debug(Globals.LogTag, "OpenProfileAsync");
880             if (profile != null)
881             {
882                 Log.Debug(Globals.LogTag, "OpenProfileAsync " + profile.Name);
883                 TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
884                 Interop.Connection.ConnectionCallback Callback = (ConnectionError Result, IntPtr Data) =>
885                 {
886                     Log.Debug(Globals.LogTag, "Connected " + profile.Name);
887                     if (Result != ConnectionError.None)
888                     {
889                         Log.Error(Globals.LogTag, "Error occurs during connecting profile, " + Result);
890                         task.SetException(new InvalidOperationException("Error occurs during connecting profile, " + Result));
891                     }
892                     else
893                     {
894                         task.SetResult(true);
895                     }
896                 };
897
898                 int ret = Interop.Connection.OpenProfile(GetHandle(), profile.ProfileHandle, Callback, IntPtr.Zero);
899                 if ((ConnectionError)ret != ConnectionError.None)
900                 {
901                     Log.Error(Globals.LogTag, "It failed to connect profile, " + (ConnectionError)ret);
902                     ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.tethering.bluetooth");
903                     ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero || profile.ProfileHandle == IntPtr.Zero), "Connection or Profile Handle may have been disposed or released");
904                     ConnectionErrorFactory.ThrowConnectionException(ret);
905                 }
906
907                 return task.Task;
908             }
909
910             else
911             {
912                 throw new ArgumentNullException("Profile is null");
913             }
914         }
915
916         internal Task CloseProfileAsync(ConnectionProfile profile)
917         {
918             Log.Debug(Globals.LogTag, "CloseProfileAsync");
919             if (profile != null)
920             {
921                 Log.Debug(Globals.LogTag, "CloseProfileAsync " + profile.Name);
922                 TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
923                 Interop.Connection.ConnectionCallback Callback = (ConnectionError Result, IntPtr Data) =>
924                 {
925                     if (Result != ConnectionError.None)
926                     {
927                         Log.Error(Globals.LogTag, "Error occurs during disconnecting profile, " + Result);
928                         task.SetException(new InvalidOperationException("Error occurs during disconnecting profile, " + Result));
929                     }
930                     else
931                     {
932                         task.SetResult(true);
933                     }
934                 };
935
936                 int ret = Interop.Connection.CloseProfile(GetHandle(), profile.ProfileHandle, Callback, IntPtr.Zero);
937                 if ((ConnectionError)ret != ConnectionError.None)
938                 {
939                     Log.Error(Globals.LogTag, "It failed to disconnect profile, " + (ConnectionError)ret);
940                     ConnectionErrorFactory.CheckFeatureUnsupportedException(ret, "http://tizen.org/feature/network.telephony " + "http://tizen.org/feature/network.wifi " + "http://tizen.org/feature/network.tethering.bluetooth");
941                     ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.set)");
942                     ConnectionErrorFactory.CheckHandleNullException(ret, (GetHandle() == IntPtr.Zero || profile.ProfileHandle == IntPtr.Zero), "Connection or Profile Handle may have been disposed or released");
943                     ConnectionErrorFactory.ThrowConnectionException(ret);
944                 }
945
946                 return task.Task;
947             }
948
949             else
950             {
951                 throw new ArgumentNullException("Profile is null");
952             }
953         }
954     }
955 }