[Connection][WiFi] Assign zero to Handle only when Interop.Destroy() (#235)
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Connection / Tizen.Network.Connection / ConnectionProfile.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.Runtime.InteropServices;
22 using Tizen.Applications;
23
24 namespace Tizen.Network.Connection
25 {
26     /// <summary>
27     /// This is the ConnectionProfile class. It provides event and properties of the connection profile.
28     /// </summary>
29     /// <since_tizen> 3 </since_tizen>
30     public class ConnectionProfile : IDisposable
31     {
32         internal IntPtr ProfileHandle = IntPtr.Zero;
33         private IAddressInformation IPv4;
34         private IAddressInformation IPv6;
35         private bool disposed = false;
36         private EventHandler<ProfileStateEventArgs> _ProfileStateChanged = null;
37
38         private Interop.ConnectionProfile.ProfileStateChangedCallback _profileChangedCallback;
39
40         private TizenSynchronizationContext context = new TizenSynchronizationContext();
41
42         internal IntPtr GetHandle()
43         {
44             return ProfileHandle;
45         }
46
47         /// <summary>
48         /// The event is called when the state of profile is changed.
49         /// </summary>
50         /// <since_tizen> 3 </since_tizen>
51         /// <feature>http://tizen.org/feature/network.ethernet</feature>
52         /// <feature>http://tizen.org/feature/network.telephony</feature>
53         /// <feature>http://tizen.org/feature/network.tethering.bluetooth</feature>
54         /// <feature>http://tizen.org/feature/network.wifi</feature>
55         /// <exception cref="System.NotSupportedException">Thrown when a feature is not supported.</exception>
56         public event EventHandler<ProfileStateEventArgs> ProfileStateChanged
57         {
58             add
59             {
60                 Log.Info(Globals.LogTag, "ProfileStateChanged add");
61                 context.Post((x) =>
62                 {
63                     if (_ProfileStateChanged == null)
64                     {
65                         try
66                         {
67                             ProfileStateChangedStart();
68                         } catch (Exception e)
69                         {
70                             Log.Error(Globals.LogTag, "Exception on adding ProfileStateChanged\n" + e.ToString());
71                             return;
72                         }
73                     }
74                     _ProfileStateChanged += value;
75                 }, null);
76             }
77             remove
78             {
79                 Log.Info(Globals.LogTag, "ProfileStateChanged remove");
80                 context.Post((x) =>
81                 {
82                     _ProfileStateChanged -= value;
83                     if (_ProfileStateChanged == null)
84                     {
85                         try
86                         {
87                             ProfileStateChangedStop();
88                         }
89                         catch (Exception e)
90                         {
91                             Log.Error(Globals.LogTag, "Exception on removing ProfileStateChanged\n" + e.ToString());
92                         }
93                     }
94                 }, null);
95             }
96         }
97
98         private void ProfileStateChangedStart()
99         {
100             _profileChangedCallback = (ProfileState state, IntPtr userData) =>
101             {
102                 if (_ProfileStateChanged != null)
103                 {
104                     _ProfileStateChanged(null, new ProfileStateEventArgs(state));
105                 }
106             };
107
108             Log.Info(Globals.LogTag, "ProfileStateChangedStart");
109             int ret = Interop.ConnectionProfile.SetStateChangeCallback(ProfileHandle, _profileChangedCallback, IntPtr.Zero);
110             if ((ConnectionError)ret != ConnectionError.None)
111             {
112                 Log.Error(Globals.LogTag, "It failed to register callback for changing profile state, " + (ConnectionError)ret);
113                 ConnectionErrorFactory.ThrowConnectionException(ret);
114             }
115         }
116
117         private void ProfileStateChangedStop()
118         {
119             Log.Info(Globals.LogTag, "ProfileStateChangedStop");
120             int ret = Interop.ConnectionProfile.UnsetStateChangeCallback(ProfileHandle);
121             if ((ConnectionError)ret != ConnectionError.None)
122             {
123                 Log.Error(Globals.LogTag, "It failed to unregister callback for changing profile state, " + (ConnectionError)ret);
124                 ConnectionErrorFactory.ThrowConnectionException(ret);
125             }
126         }
127
128         internal ConnectionProfile(IntPtr handle)
129         {
130             ProfileHandle = handle;
131             IPv4 = new ConnectionAddressInformation(ProfileHandle, AddressFamily.IPv4);
132             IPv6 = new ConnectionAddressInformation(ProfileHandle, AddressFamily.IPv6);
133         }
134
135         /// <summary>
136         /// Destroy the ConnectionProfile object
137         /// </summary>
138         ~ConnectionProfile()
139         {
140             Dispose(false);
141         }
142
143         /// <summary>
144         /// Disposes the memory allocated to unmanaged resources.
145         /// </summary>
146         /// <since_tizen> 3 </since_tizen>
147         public void Dispose()
148         {
149             Dispose(true);
150             GC.SuppressFinalize(this);
151         }
152
153         private void Dispose(bool disposing)
154         {
155             if (disposed)
156                 return;
157
158             // Free unmanaged objects
159             UnregisterEvents();
160             Destroy();
161             disposed = true;
162         }
163
164         private void UnregisterEvents()
165         {
166             if (_ProfileStateChanged != null)
167             {
168                 ProfileStateChangedStop();
169             }
170         }
171
172         private void Destroy()
173         {
174             int ret = Interop.ConnectionProfile.Destroy(ProfileHandle);
175             if ((ConnectionError)ret == ConnectionError.None)
176             {
177                 ProfileHandle = IntPtr.Zero;
178             }
179             
180         }
181
182         internal void CheckDisposed()
183         {
184             if (disposed)
185             {
186                 throw new ObjectDisposedException(GetType().FullName);
187             }
188         }
189
190         /// <summary>
191         /// The profile ID.
192         /// </summary>
193         /// <since_tizen> 3 </since_tizen>
194         /// <value>Unique ID of the profile.</value>
195         public string Id
196         {
197             get
198             {
199                 IntPtr Value;
200                 int ret = Interop.ConnectionProfile.GetId(ProfileHandle, out Value);
201                 if ((ConnectionError)ret != ConnectionError.None)
202                 {
203                     Log.Error(Globals.LogTag, "It failed to get id of connection profile, " + (ConnectionError)ret);
204                 }
205                 string result = Marshal.PtrToStringAnsi(Value);
206                 Interop.Libc.Free(Value);
207                 return result;
208             }
209         }
210
211         /// <summary>
212         /// The profile name.
213         /// </summary>
214         /// <since_tizen> 3 </since_tizen>
215         /// <value>User friendly name of the profile.</value>
216         public string Name
217         {
218             get
219             {
220                 IntPtr Value;
221                 int ret = Interop.ConnectionProfile.GetName(ProfileHandle, out Value);
222                 if ((ConnectionError)ret != ConnectionError.None)
223                 {
224                     Log.Error(Globals.LogTag, "It failed to get name of connection profile, " + (ConnectionError)ret);
225                 }
226                 string result = Marshal.PtrToStringAnsi(Value);
227                 Interop.Libc.Free(Value);
228                 return result;
229             }
230         }
231
232         /// <summary>
233         /// The network type.
234         /// </summary>
235         /// <since_tizen> 3 </since_tizen>
236         /// <value>Profile type of the network connection.</value>
237         public ConnectionProfileType Type
238         {
239             get
240             {
241                 int Value;
242                 int ret = Interop.ConnectionProfile.GetType(ProfileHandle, out Value);
243                 if ((ConnectionError)ret != ConnectionError.None)
244                 {
245                     Log.Error(Globals.LogTag, "It failed to get type of connection profile, " + (ConnectionError)ret);
246                 }
247                 return (ConnectionProfileType)Value;
248             }
249         }
250
251         /// <summary>
252         /// The name of the network interface.
253         /// </summary>
254         /// <since_tizen> 3 </since_tizen>
255         /// <value>Network interface name, for example, eth0 and pdp0.</value>
256         public string InterfaceName
257         {
258             get
259             {
260                 IntPtr Value;
261                 int ret = Interop.ConnectionProfile.GetNetworkInterfaceName(ProfileHandle, out Value);
262                 if ((ConnectionError)ret != ConnectionError.None)
263                 {
264                     Log.Error(Globals.LogTag, "It failed to get network interface name, " + (ConnectionError)ret);
265                 }
266                 string result = Marshal.PtrToStringAnsi(Value);
267                 Interop.Libc.Free(Value);
268                 return result;
269             }
270         }
271
272         /// <summary>
273         /// Refreshes the profile information.
274         /// </summary>
275         /// <since_tizen> 3 </since_tizen>
276         /// <privilege>http://tizen.org/privilege/network.get</privilege>
277         /// <feature>http://tizen.org/feature/network.ethernet</feature>
278         /// <feature>http://tizen.org/feature/network.telephony</feature>
279         /// <feature>http://tizen.org/feature/network.tethering.bluetooth</feature>
280         /// <feature>http://tizen.org/feature/network.wifi</feature>
281         /// <exception cref="System.NotSupportedException">Thrown when a feature is not supported.</exception>
282         /// <exception cref="System.UnauthorizedAccessException">Thrown when a permission is denied.</exception>
283         /// <exception cref="System.ArgumentException">Thrown when a value is an invalid parameter.</exception>
284         /// <exception cref="System.InvalidOperationException">Thrown when a profile instance is invalid or when a method fails due to an invalid operation.</exception>
285         /// <exception cref="System.ObjectDisposedException">Thrown when an operation is performed on a disposed object.</exception>
286         public void Refresh()
287         {
288             CheckDisposed();
289             int ret = Interop.ConnectionProfile.Refresh(ProfileHandle);
290             if ((ConnectionError)ret != ConnectionError.None)
291             {
292                 Log.Error(Globals.LogTag, "It failed to get network interface name, " + (ConnectionError)ret);
293                 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");
294                 ConnectionErrorFactory.CheckPermissionDeniedException(ret, "(http://tizen.org/privilege/network.get)");
295                 ConnectionErrorFactory.CheckHandleNullException(ret, (ProfileHandle == IntPtr.Zero), "ProfileHandle may have been disposed or released");
296                 ConnectionErrorFactory.ThrowConnectionException(ret);
297             }
298         }
299
300         /// <summary>
301         /// Gets the network state.
302         /// </summary>
303         /// <since_tizen> 3 </since_tizen>
304         /// <param name="family">The address family.</param>
305         /// <returns>The network state.</returns>
306         /// <feature>http://tizen.org/feature/network.ethernet</feature>
307         /// <feature>http://tizen.org/feature/network.telephony</feature>
308         /// <feature>http://tizen.org/feature/network.tethering.bluetooth</feature>
309         /// <feature>http://tizen.org/feature/network.wifi</feature>
310         /// <exception cref="System.NotSupportedException">Thrown when a feature is not supported.</exception>
311         /// <exception cref="System.ArgumentException">Thrown when a value is an invalid parameter.</exception>
312         /// <exception cref="System.InvalidOperationException">Thrown when a profile instance is invalid or when a method fails due to an invalid operation.</exception>
313         /// <exception cref="System.ObjectDisposedException">Thrown when an operation is performed on a disposed object.</exception>
314         public ProfileState GetState(AddressFamily family)
315         {
316             CheckDisposed();
317             int Value;
318             int ret = (int)ConnectionError.None;
319             if (family == AddressFamily.IPv4)
320             {
321                 ret = Interop.ConnectionProfile.GetState(ProfileHandle, out Value);
322             }
323
324             else
325             {
326                 ret = Interop.ConnectionProfile.GetIPv6State(ProfileHandle, out Value);
327             }
328
329             if ((ConnectionError)ret != ConnectionError.None)
330             {
331                 Log.Error(Globals.LogTag, "It failed to get profile state, " + (ConnectionError)ret);
332                 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");
333                 ConnectionErrorFactory.CheckHandleNullException(ret, (ProfileHandle == IntPtr.Zero), "ProfileHandle may have been disposed or released");
334                 ConnectionErrorFactory.ThrowConnectionException(ret);
335             }
336
337             return (ProfileState)Value;
338         }
339
340         /// <summary>
341         /// The Proxy type.
342         /// </summary>
343         /// <since_tizen> 3 </since_tizen>
344         /// <value>Proxy type of the connection.</value>
345         /// <exception cref="System.NotSupportedException">Thrown during set when a feature is not supported.</exception>
346         /// <exception cref="System.ArgumentException">Thrown during set when a value is an invalid parameter.</exception>
347         /// <exception cref="System.InvalidOperationException">Thrown during set when a profile instance is invalid or when a method fails due to an invalid operation.</exception>
348         /// <exception cref="System.ObjectDisposedException">Thrown during set when a operation is performed on a disposed object.</exception>
349         public ProxyType ProxyType
350         {
351             get
352             {
353                 int Value;
354                 int ret = Interop.ConnectionProfile.GetProxyType(ProfileHandle, out Value);
355                 if ((ConnectionError)ret != ConnectionError.None)
356                 {
357                     Log.Error(Globals.LogTag, "It failed to get proxy type, " + (ConnectionError)ret);
358                 }
359                 return (ProxyType)Value;
360
361             }
362
363             set
364             {
365                 CheckDisposed();
366                 int ret = Interop.ConnectionProfile.SetProxyType(ProfileHandle, (int)value);
367                 if ((ConnectionError)ret != ConnectionError.None)
368                 {
369                     Log.Error(Globals.LogTag, "It failed to set proxy type, " + (ConnectionError)ret);
370                     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");
371                     ConnectionErrorFactory.CheckHandleNullException(ret, (ProfileHandle == IntPtr.Zero), "ProfileHandle may have been disposed or released");
372                     ConnectionErrorFactory.ThrowConnectionException(ret);
373                 }
374             }
375         }
376
377         /// <summary>
378         /// The proxy address.
379         /// </summary>
380         /// <since_tizen> 3 </since_tizen>
381         /// <value>Proxy address of the connection.</value>
382         /// <exception cref="System.NotSupportedException">Thrown during set when a feature is not supported.</exception>
383         /// <exception cref="System.ArgumentException">Thrown during set when a value is an invalid parameter.</exception>
384         /// <exception cref="System.ArgumentNullException">Thrown during set when a value is null.</exception>
385         /// <exception cref="System.InvalidOperationException">Thrown during set when a profile instance is invalid or when a method fails due to an invalid operation.</exception>
386         /// <exception cref="System.ObjectDisposedException">Thrown when an operation is performed on a disposed object.</exception>
387         public string ProxyAddress
388         {
389             get
390             {
391                 IntPtr Value;
392                 int ret = Interop.ConnectionProfile.GetProxyAddress(ProfileHandle, (int)AddressFamily.IPv4, out Value);
393                 if ((ConnectionError)ret != ConnectionError.None)
394                 {
395                     Log.Error(Globals.LogTag, "It failed to get proxy address, " + (ConnectionError)ret);
396                 }
397                 string result = Marshal.PtrToStringAnsi(Value);
398                 Interop.Libc.Free(Value);
399                 return result;
400
401             }
402
403             set
404             {
405                 CheckDisposed();
406                 if (value != null)
407                 {
408                     int ret = Interop.ConnectionProfile.SetProxyAddress(ProfileHandle, (int)AddressFamily.IPv4, value);
409                     if ((ConnectionError)ret != ConnectionError.None)
410                     {
411                         Log.Error(Globals.LogTag, "It failed to set proxy address, " + (ConnectionError)ret);
412                         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");
413                         ConnectionErrorFactory.CheckHandleNullException(ret, (ProfileHandle == IntPtr.Zero), "ProfileHandle may have been disposed or released");
414                         ConnectionErrorFactory.ThrowConnectionException(ret);
415                     }
416                 }
417
418                 else
419                 {
420                     throw new ArgumentNullException("ProxyAddress is null");
421                 }
422             }
423         }
424
425         /// <summary>
426         /// The address information (IPv4).
427         /// </summary>
428         /// <since_tizen> 3 </since_tizen>
429         /// <value>Instance of IAddressInformation with IPV4 address.</value>
430         public IAddressInformation IPv4Settings
431         {
432             get
433             {
434                 return IPv4;
435
436             }
437         }
438
439         /// <summary>
440         /// The address information (IPv6).
441         /// </summary>
442         /// <since_tizen> 3 </since_tizen>
443         /// <value>Instance of IAddressInformation with IPV6 address.</value>
444         public IAddressInformation IPv6Settings
445         {
446             get
447             {
448                 return IPv6;
449             }
450         }
451     }
452
453     /// <summary>
454     /// An extended EventArgs class, which contains changed profile state.
455     /// </summary>
456     /// <since_tizen> 3 </since_tizen>
457     public class ProfileStateEventArgs : EventArgs
458     {
459         private ProfileState _State = ProfileState.Disconnected;
460
461         internal ProfileStateEventArgs(ProfileState state)
462         {
463             _State = state;
464         }
465
466         /// <summary>
467         /// The profile state.
468         /// </summary>
469         /// <since_tizen> 3 </since_tizen>
470         /// <value>State type of the connection profile.</value>
471         public ProfileState State
472         {
473             get
474             {
475                 return _State;
476             }
477         }
478     }
479 }