Remove device name in remote resource
[platform/core/csapi/iotcon.git] / Tizen.Network.IoTConnectivity / Tizen.Network.IoTConnectivity / RemoteResource.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
18 using System;
19 using System.Collections.Generic;
20 using System.Net;
21 using System.Runtime.InteropServices;
22 using System.Threading.Tasks;
23
24 namespace Tizen.Network.IoTConnectivity
25 {
26     /// <summary>
27     /// This class represents a remote resource.
28     /// It provides APIs to manage remote resource.
29     /// </summary>
30     public class RemoteResource : IDisposable
31     {
32         internal const int TimeOutMax = 3600;
33         internal IntPtr _remoteResourceHandle = IntPtr.Zero;
34
35         private bool _disposed = false;
36         private bool _cacheEnabled = false;
37         private ResourceOptions _options;
38
39         private int _responseCallbackId = 1;
40         private static Dictionary<IntPtr, Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback> _responseCallbacksMap = new Dictionary<IntPtr, Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback>();
41
42         private Interop.IoTConnectivity.Client.RemoteResource.CachedRepresentationChangedCallback _cacheUpdatedCallback;
43         private Interop.IoTConnectivity.Client.RemoteResource.StateChangedCallback _stateChangedCallback;
44         private Interop.IoTConnectivity.Client.RemoteResource.ObserveCallback _observeCallback;
45
46         private EventHandler<StateChangedEventArgs> _stateChangedEventHandler;
47
48         /// <summary>
49         /// Creates a remote resource instance
50         /// </summary>
51         /// <remarks>
52         /// To use this API, you should provide all of the details required to correctly contact and
53         /// observe the object.\n
54         /// If not, you should discover the resource object manually.\n
55         /// The @a policy can contain multiple policies like ResourcePolicy.Discoverable | ResourcePolicy.Observable.
56         /// </remarks>
57         /// <param name="hostAddress">The host address of the resource</param>
58         /// <param name="uriPath">The URI path of the resource</param>
59         /// <param name="policy">The policies of the resource</param>
60         /// <param name="resourceTypes">The resource types of the resource</param>
61         /// <param name="resourceInterfaces">The resource interfaces of the resource</param>
62         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
63         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
64         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
65         public RemoteResource(string hostAddress, string uriPath, ResourcePolicy policy, ResourceTypes resourceTypes, ResourceInterfaces resourceInterfaces)
66         {
67             if (hostAddress == null || uriPath == null || resourceTypes == null || resourceInterfaces == null)
68             {
69                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Invalid parameters");
70                 throw new ArgumentException("Invalid parameter");
71             }
72
73             HostAddress = hostAddress;
74             UriPath = uriPath;
75             Policy = policy;
76             Types = new List<string>(resourceTypes);
77             Interfaces = new List<string>(resourceInterfaces);
78             DeviceId = null;
79
80             CreateRemoteResource(resourceTypes._resourceTypeHandle, resourceInterfaces.ResourceInterfacesHandle);
81         }
82
83         internal RemoteResource(IntPtr handleToClone)
84         {
85             int ret = Interop.IoTConnectivity.Client.RemoteResource.Clone(handleToClone, out _remoteResourceHandle);
86             if (ret != (int)IoTConnectivityError.None)
87             {
88                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to clone");
89                 throw IoTConnectivityErrorFactory.GetException(ret);
90             }
91             SetRemoteResource();
92         }
93
94         /// <summary>
95         /// Destructor of the RemoteResource class.
96         /// </summary>
97         ~RemoteResource()
98         {
99             Dispose(false);
100         }
101
102         /// <summary>
103         /// Event that is invoked with cached resource attributes
104         /// </summary>
105         public event EventHandler<CacheUpdatedEventArgs> CacheUpdated;
106
107         /// <summary>
108         /// Observe event on the resource sent by the server
109         /// </summary>
110         public event EventHandler<ObserverNotifiedEventArgs> ObserverNotified;
111
112         /// <summary>
113         /// Event that is called when remote resource's state are changed
114         /// </summary>
115         public event EventHandler<StateChangedEventArgs> StateChanged
116         {
117             add
118             {
119                 if (_stateChangedEventHandler == null)
120                 {
121                     RegisterStateChangedEvent();
122                 }
123                 _stateChangedEventHandler += value;
124             }
125             remove
126             {
127                 _stateChangedEventHandler -= value;
128                 if (_stateChangedEventHandler == null)
129                 {
130                     UnregisterStateChangedEvent();
131                 }
132             }
133         }
134
135         /// <summary>
136         /// The host address of the resource
137         /// </summary>
138         public string HostAddress { get; private set; }
139
140         /// <summary>
141         /// The URI path of the resource
142         /// </summary>
143         public string UriPath { get; private set; }
144
145         /// <summary>
146         /// The resource types of the remote resource
147         /// </summary>
148         public IEnumerable<string> Types { get; private set; }
149
150         /// <summary>
151         /// The interfaces of the resource
152         /// </summary>
153         public IEnumerable<string> Interfaces { get; private set; }
154
155         /// <summary>
156         /// The policy of the resource
157         /// </summary>
158         public ResourcePolicy Policy { get; private set; }
159
160         /// <summary>
161         /// The header options of the resource
162         /// </summary>
163         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
164         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
165         public ResourceOptions Options
166         {
167             get
168             {
169                 return _options;
170             }
171             set
172             {
173                 _options = value;
174                 if (value != null)
175                 {
176                     int ret = Interop.IoTConnectivity.Client.RemoteResource.SetOptions(_remoteResourceHandle, value._resourceOptionsHandle);
177                     if (ret != (int)IoTConnectivityError.None)
178                     {
179                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set options");
180                         throw IoTConnectivityErrorFactory.GetException(ret);
181                     }
182                 }
183             }
184         }
185
186         /// <summary>
187         /// Indicates the CacheEnabled status of the remote resource.
188         /// </summary>
189         /// <remarks>
190         /// Client can start caching only when this is set true. Set it to false to stop caching the resource attributes.
191         /// </remarks>
192         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
193         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
194         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
195         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
196         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
197         public bool CacheEnabled
198         {
199             get
200             {
201                 return _cacheEnabled;
202             }
203             set
204             {
205                 if (_cacheEnabled != value)
206                 {
207                     _cacheEnabled = value;
208                     HandleCachePolicyChanged();
209                 }
210             }
211         }
212
213         /// <summary>
214         /// Time interval of monitoring and caching API
215         /// </summary>
216         /// <remarks>
217         /// Default time interval is 10 seconds.\n
218         /// Seconds for time interval (must be in range from 1 to 3600)
219         /// </remarks>
220         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
221         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
222         public int TimeInterval
223         {
224             get
225             {
226                 int interval;
227                 int ret = Interop.IoTConnectivity.Client.RemoteResource.GetTimeInterval(_remoteResourceHandle, out interval);
228                 if (ret != (int)IoTConnectivityError.None)
229                 {
230                     Log.Warn(IoTConnectivityErrorFactory.LogTag, "Failed to get time interval");
231                     return 0;
232                 }
233                 return interval;
234             }
235             set
236             {
237                 int ret = (int)IoTConnectivityError.InvalidParameter;
238                 if (value <= TimeOutMax && value > 0)
239                 {
240                     ret = Interop.IoTConnectivity.Client.RemoteResource.SetTimeInterval(_remoteResourceHandle, value);
241                 }
242                 if (ret != (int)IoTConnectivityError.None)
243                 {
244                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set time interval");
245                     throw IoTConnectivityErrorFactory.GetException(ret);
246                 }
247             }
248         }
249
250         /// <summary>
251         /// The device id of the resource
252         /// </summary>
253         public string DeviceId { get; private set; }
254
255         /// <summary>
256         /// Gets cached representation from the remote resource
257         /// </summary>
258         public Representation CachedRepresentation()
259         {
260             IntPtr handle;
261             int ret = Interop.IoTConnectivity.Client.RemoteResource.GetCachedRepresentation(_remoteResourceHandle, out handle);
262             if (ret != (int)IoTConnectivityError.None)
263             {
264                 Log.Warn(IoTConnectivityErrorFactory.LogTag, "Failed to get CachedRepresentation");
265                 return null;
266             }
267
268             Representation representation = new Representation(handle);
269             return representation;
270         }
271
272         /// <summary>
273         /// Starts observing on the resource
274         /// </summary>
275         /// <remarks>
276         /// When server sends notification message, <see cref="ObserverNotified"/> will be called.
277         /// </remarks>
278         /// <privilege>
279         /// http://tizen.org/privilege/internet
280         /// </privilege>
281         /// <param name="policy">The type to specify how client wants to observe</param>
282         /// <param name="query">The query to send to server</param>
283         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
284         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
285         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
286         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
287         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
288         public void StartObserving(ObservePolicy policy, ResourceQuery query = null)
289         {
290             _observeCallback = (IntPtr resource, int err, int sequenceNumber, IntPtr response, IntPtr userData) =>
291             {
292                 int result;
293                 IntPtr representationHandle;
294                 int ret = Interop.IoTConnectivity.Server.Response.GetResult(response, out result);
295                 if (ret != (int)IoTConnectivityError.None)
296                 {
297                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get result");
298                     return;
299                 }
300
301                 ret = Interop.IoTConnectivity.Server.Response.GetRepresentation(response, out representationHandle);
302                 if (ret != (int)IoTConnectivityError.None)
303                 {
304                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get representation");
305                     return;
306                 }
307
308                 Representation repr = null;
309                 try
310                 {
311                     repr = new Representation(representationHandle);
312                 }
313                 catch (Exception exp)
314                 {
315                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new representation: " + exp.Message);
316                     return;
317                 }
318
319                 ObserverNotifiedEventArgs e = new ObserverNotifiedEventArgs()
320                 {
321                     Representation = repr,
322                     Result = (ResponseCode)result
323                 };
324                 ObserverNotified?.Invoke(this, e);
325             };
326
327             IntPtr queryHandle = IntPtr.Zero;
328             if (query != null)
329             {
330                 queryHandle = query._resourceQueryHandle;
331             }
332
333             int errCode = Interop.IoTConnectivity.Client.RemoteResource.RegisterObserve(_remoteResourceHandle, (int)policy, queryHandle, _observeCallback, IntPtr.Zero);
334             if (errCode != (int)IoTConnectivityError.None)
335             {
336                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register observe callbacks");
337                 throw IoTConnectivityErrorFactory.GetException(errCode);
338             }
339         }
340
341         /// <summary>
342         /// Stops observing on the resource
343         /// </summary>
344         /// <privilege>
345         /// http://tizen.org/privilege/internet
346         /// </privilege>
347         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
348         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
349         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
350         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
351         public void StopObserving()
352         {
353             int ret = Interop.IoTConnectivity.Client.RemoteResource.DeregisterObserve(_remoteResourceHandle);
354             if (ret != (int)IoTConnectivityError.None)
355             {
356                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to deregister observe callbacks");
357                 throw IoTConnectivityErrorFactory.GetException(ret);
358             }
359         }
360
361         /// <summary>
362         /// Gets the attributes of a resource, asynchronously
363         /// </summary>
364         /// <privilege>
365         /// http://tizen.org/privilege/internet
366         /// </privilege>
367         /// <param name="query">The ResourceQuery to send to server</param>
368         /// <returns>Remote response with result and representation</returns>
369         public async Task<RemoteResponse> GetAsync(ResourceQuery query = null)
370         {
371             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
372
373             IntPtr id = IntPtr.Zero;
374             lock (_responseCallbacksMap)
375             {
376                 id = (IntPtr)_responseCallbackId++;
377             }
378             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
379             {
380                 IntPtr responseCallbackId = userData;
381                 lock(_responseCallbacksMap)
382                 {
383                     _responseCallbacksMap.Remove(responseCallbackId);
384                 }
385
386                 if (responseHandle != IntPtr.Zero)
387                 {
388                     try
389                     {
390                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
391                     }
392                     catch(Exception exp)
393                     {
394                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
395                         tcsRemoteResponse.TrySetException(exp);
396                     }
397                 }
398                 else
399                 {
400                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
401                 }
402             };
403
404             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
405             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Get(_remoteResourceHandle, queryHandle, _responseCallbacksMap[id], id);
406             if (errCode != (int)IoTConnectivityError.None)
407             {
408                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource attributes");
409                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
410             }
411             return await tcsRemoteResponse.Task;
412         }
413
414         /// <summary>
415         /// Puts the representation of a resource, asynchronously.
416         /// </summary>
417         /// <privilege>
418         /// http://tizen.org/privilege/internet
419         /// </privilege>
420         /// <param name="representation">Resource representation to put</param>
421         /// <param name="query">The ResourceQuery to send to server</param>
422         /// <returns>Remote response with result and representation</returns>
423         public async Task<RemoteResponse> PutAsync(Representation representation, ResourceQuery query = null)
424         {
425             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
426
427             IntPtr id = IntPtr.Zero;
428             lock (_responseCallbacksMap)
429             {
430                 id = (IntPtr)_responseCallbackId++;
431             }
432             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
433             {
434                 IntPtr responseCallbackId = userData;
435                 lock (_responseCallbacksMap)
436                 {
437                     _responseCallbacksMap.Remove(responseCallbackId);
438                 }
439                 if (err == (int)(IoTConnectivityError.Iotivity))
440                 {
441                     RemoteResponse response = new RemoteResponse();
442                     response.Result = ResponseCode.Forbidden;
443                     response.Representation = null;
444                     tcsRemoteResponse.TrySetResult(response);
445                 }
446                 else if (responseHandle != IntPtr.Zero)
447                 {
448                     try
449                     {
450                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
451                     }
452                     catch (Exception exp)
453                     {
454                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
455                         tcsRemoteResponse.TrySetException(exp);
456                     }
457                 }
458                 else
459                 {
460                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
461                 }
462             };
463             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
464             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Put(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
465             if (errCode != (int)IoTConnectivityError.None)
466             {
467                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to put resource representation");
468                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
469             }
470             return await tcsRemoteResponse.Task;
471         }
472
473         /// <summary>
474         /// Post request on a resource, asynchronously
475         /// </summary>
476         /// <privilege>
477         /// http://tizen.org/privilege/internet
478         /// </privilege>
479         /// <param name="representation">Resource representation of request</param>
480         /// <param name="query">The ResourceQuery to send to server</param>
481         /// <returns>Remote response with result and representation</returns>
482         public async Task<RemoteResponse> PostAsync(Representation representation, ResourceQuery query = null)
483         {
484             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
485
486             IntPtr id = IntPtr.Zero;
487             lock (_responseCallbacksMap)
488             {
489                 id = (IntPtr)_responseCallbackId++;
490             }
491             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
492             {
493                 IntPtr responseCallbackId = userData;
494                 lock (_responseCallbacksMap)
495                 {
496                     _responseCallbacksMap.Remove(responseCallbackId);
497                 }
498                 if (responseHandle != IntPtr.Zero)
499                 {
500                     try
501                     {
502                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
503                     }
504                     catch (Exception exp)
505                     {
506                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
507                         tcsRemoteResponse.TrySetException(exp);
508                     }
509                 }
510                 else
511                 {
512                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
513                 }
514             };
515             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
516             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Post(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
517             if (errCode != (int)IoTConnectivityError.None)
518             {
519                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to post request");
520                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
521             }
522             return await tcsRemoteResponse.Task;
523         }
524
525         /// <summary>
526         /// Deletes the resource, asynchronously
527         /// </summary>
528         /// <privilege>
529         /// http://tizen.org/privilege/internet
530         /// </privilege>
531         /// <returns>Remote response with result and representation</returns>
532         public async Task<RemoteResponse> DeleteAsync()
533         {
534             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
535
536             IntPtr id = IntPtr.Zero;
537             lock (_responseCallbacksMap)
538             {
539                 id = (IntPtr)_responseCallbackId++;
540             }
541             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
542             {
543                 IntPtr responseCallbackId = userData;
544                 lock (_responseCallbacksMap)
545                 {
546                     _responseCallbacksMap.Remove(responseCallbackId);
547                 }
548                 if (err == (int)(IoTConnectivityError.Iotivity))
549                 {
550                     RemoteResponse response = new RemoteResponse();
551                     response.Result = ResponseCode.Forbidden;
552                     response.Representation = null;
553                     tcsRemoteResponse.TrySetResult(response);
554                 }
555                 else if (responseHandle != IntPtr.Zero)
556                 {
557                     try
558                     {
559                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
560                     }
561                     catch (Exception exp)
562                     {
563                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
564                         tcsRemoteResponse.TrySetException(exp);
565                     }
566                 }
567                 else
568                 {
569                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
570                 }
571             };
572
573             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Delete(_remoteResourceHandle, _responseCallbacksMap[id], id);
574             if (errCode != (int)IoTConnectivityError.None)
575             {
576                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to delete");
577                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
578             }
579             return await tcsRemoteResponse.Task;
580         }
581
582         /// <summary>
583         /// Releases any unmanaged resources used by this object.
584         /// </summary>
585         public void Dispose()
586         {
587             Dispose(true);
588             GC.SuppressFinalize(this);
589         }
590
591         internal static Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType GetConnectivityType(string hostAddress)
592         {
593             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None;
594
595             Log.Info(IoTConnectivityErrorFactory.LogTag, hostAddress);
596
597             if (hostAddress == IoTConnectivityClientManager.MulticastAddress)
598             {
599                 type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
600             }
601             else
602             {
603                 IPAddress address;
604                 string hostName = hostAddress;
605                 if (hostAddress.Contains(":"))
606                 {
607                     string[] hostParts = hostAddress.Split(':');
608                     if (hostParts.Length == 2)
609                     {
610                         hostName = hostParts[0];
611                     }
612                 }
613                 if (hostAddress.Contains("%"))
614                 {
615                     string[] hostParts = hostAddress.Split('%');
616                     if (hostParts.Length == 2)
617                     {
618                         hostName = hostParts[0];
619                     }
620                 }
621                 if (hostName.Contains("["))
622                 {
623                     string[] hostParts = hostName.Split('[');
624                     if (hostParts.Length == 2)
625                     {
626                         hostName = hostParts[1];
627                     }
628                 }
629                 Log.Info(IoTConnectivityErrorFactory.LogTag, hostName);
630                 if (IPAddress.TryParse(hostName, out address))
631                 {
632                     switch (address.AddressFamily)
633                     {
634                         case System.Net.Sockets.AddressFamily.InterNetwork:
635                             type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
636                             break;
637                         case System.Net.Sockets.AddressFamily.InterNetworkV6:
638                             type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv6;
639                             break;
640                         default:
641                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to parse for Ipv4 or Ipv6");
642                             break;
643                     }
644                 }
645                 else
646                 {
647                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to parse hostname " + hostName);
648                 }
649             }
650             return type;
651         }
652
653         /// <summary>
654         /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
655         /// </summary>
656         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
657         protected virtual void Dispose(bool disposing)
658         {
659             if (_disposed)
660                 return;
661
662             if (disposing)
663             {
664                 // Free managed objects
665             }
666
667             Interop.IoTConnectivity.Client.RemoteResource.Destroy(_remoteResourceHandle);
668             _disposed = true;
669         }
670
671         private void HandleCachePolicyChanged()
672         {
673             if (_cacheEnabled)
674             {
675                 _cacheUpdatedCallback = (IntPtr resource, IntPtr representation, IntPtr userData) =>
676                 {
677                     if (CacheEnabled)
678                     {
679                         Representation repr = null;
680                         try
681                         {
682                             repr = new Representation(representation);
683                         }
684                         catch (Exception exp)
685                         {
686                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new Representation: " + exp.Message);
687                             return;
688                         }
689
690                         CacheUpdatedEventArgs e = new CacheUpdatedEventArgs()
691                         {
692                             Representation = repr
693                         };
694                         CacheUpdated?.Invoke(this, e);
695                     }
696                 };
697
698                 int ret = Interop.IoTConnectivity.Client.RemoteResource.StartCaching(_remoteResourceHandle, _cacheUpdatedCallback, IntPtr.Zero);
699                 if (ret != (int)IoTConnectivityError.None)
700                 {
701                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add cache updated event handler");
702                     throw IoTConnectivityErrorFactory.GetException(ret);
703                 }
704             }
705             else
706             {
707                 int ret = Interop.IoTConnectivity.Client.RemoteResource.StopCaching(_remoteResourceHandle);
708                 if (ret != (int)IoTConnectivityError.None)
709                 {
710                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove cache updated event handler");
711                     throw IoTConnectivityErrorFactory.GetException(ret);
712                 }
713             }
714         }
715
716         private void RegisterStateChangedEvent()
717         {
718             _stateChangedCallback = (IntPtr resource, int state, IntPtr userData) =>
719             {
720                 StateChangedEventArgs e = new StateChangedEventArgs()
721                 {
722                     State = (ResourceState)state
723                 };
724                 _stateChangedEventHandler?.Invoke(null, e);
725             };
726
727             int ret = Interop.IoTConnectivity.Client.RemoteResource.StartMonitoring(_remoteResourceHandle, _stateChangedCallback, IntPtr.Zero);
728             if (ret != (int)IoTConnectivityError.None)
729             {
730                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add state changed event handler");
731                 throw IoTConnectivityErrorFactory.GetException(ret);
732             }
733         }
734
735         private void UnregisterStateChangedEvent()
736         {
737             int ret = Interop.IoTConnectivity.Client.RemoteResource.StopMonitoring(_remoteResourceHandle);
738             if (ret != (int)IoTConnectivityError.None)
739             {
740                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove state changed event handler");
741                 throw IoTConnectivityErrorFactory.GetException(ret);
742             }
743         }
744
745         private void CreateRemoteResource(IntPtr resourceTypeHandle, IntPtr resourceInterfaceHandle)
746         {
747             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = GetConnectivityType(HostAddress);
748             if (connectivityType == Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None)
749             {
750                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Unable to parse host address");
751                 throw new ArgumentException("Unable to parse host address");
752             }
753             int ret = Interop.IoTConnectivity.Client.RemoteResource.Create(HostAddress, (int)connectivityType, UriPath, (int)Policy, resourceTypeHandle, resourceInterfaceHandle, out _remoteResourceHandle);
754             if (ret != (int)IoTConnectivityError.None)
755             {
756                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get remote resource");
757                 throw IoTConnectivityErrorFactory.GetException(ret);
758             }
759         }
760
761         private void SetRemoteResource()
762         {
763             IntPtr hostAddressPtr, uriPathPtr;
764             int ret = Interop.IoTConnectivity.Client.RemoteResource.GetHostAddress(_remoteResourceHandle, out hostAddressPtr);
765             if (ret != (int)IoTConnectivityError.None)
766             {
767                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get host address");
768                 throw IoTConnectivityErrorFactory.GetException(ret);
769             }
770
771             ret = Interop.IoTConnectivity.Client.RemoteResource.GetUriPath(_remoteResourceHandle, out uriPathPtr);
772             if (ret != (int)IoTConnectivityError.None)
773             {
774                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
775                 throw IoTConnectivityErrorFactory.GetException(ret);
776             }
777
778             int policy = (int)ResourcePolicy.NoProperty;
779             ret = Interop.IoTConnectivity.Client.RemoteResource.GetPolicies(_remoteResourceHandle, out policy);
780             if (ret != (int)IoTConnectivityError.None)
781             {
782                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
783                 throw IoTConnectivityErrorFactory.GetException(ret);
784             }
785
786             IntPtr typesHandle, interfacesHandle;
787             ret = Interop.IoTConnectivity.Client.RemoteResource.GetTypes(_remoteResourceHandle, out typesHandle);
788             if (ret != (int)IoTConnectivityError.None)
789             {
790                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource types");
791                 throw IoTConnectivityErrorFactory.GetException(ret);
792             }
793
794             ret = Interop.IoTConnectivity.Client.RemoteResource.GetInterfaces(_remoteResourceHandle, out interfacesHandle);
795             if (ret != (int)IoTConnectivityError.None)
796             {
797                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource interfaces");
798                 throw IoTConnectivityErrorFactory.GetException(ret);
799             }
800
801             IntPtr deviceIdPtr;
802             ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceId(_remoteResourceHandle, out deviceIdPtr);
803             if (ret != (int)IoTConnectivityError.None)
804             {
805                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device id");
806                 throw IoTConnectivityErrorFactory.GetException(ret);
807             }
808             DeviceId = Marshal.PtrToStringAnsi(deviceIdPtr);
809             HostAddress = Marshal.PtrToStringAnsi(hostAddressPtr);
810             UriPath = Marshal.PtrToStringAnsi(uriPathPtr);
811             Types = new ResourceTypes(typesHandle);
812             Interfaces = new ResourceInterfaces(interfacesHandle);
813             Policy = (ResourcePolicy)policy;
814         }
815
816         private RemoteResponse GetRemoteResponse(IntPtr response)
817         {
818             int result;
819             IntPtr representationHandle, optionsHandle;
820             int ret = Interop.IoTConnectivity.Server.Response.GetResult(response, out result);
821             if (ret != (int)IoTConnectivityError.None)
822             {
823                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get result");
824                 throw IoTConnectivityErrorFactory.GetException(ret);
825             }
826
827             ret = Interop.IoTConnectivity.Server.Response.GetRepresentation(response, out representationHandle);
828             if (ret != (int)IoTConnectivityError.None)
829             {
830                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get representation");
831                 throw IoTConnectivityErrorFactory.GetException(ret);
832             }
833
834             ret = Interop.IoTConnectivity.Server.Response.GetOptions(response, out optionsHandle);
835             if (ret != (int)IoTConnectivityError.None)
836             {
837                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get options");
838                 throw IoTConnectivityErrorFactory.GetException(ret);
839             }
840             return new RemoteResponse()
841             {
842                 Result = (ResponseCode)result,
843                 Representation = new Representation(representationHandle),
844                 Options = (optionsHandle == IntPtr.Zero)? null : new ResourceOptions(optionsHandle)
845             };
846         }
847     }
848 }