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