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