463b8fa672f0deb4ae8ae8f86d5727de4f47b12f
[platform/core/csapi/tizenfx.git] / src / 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="InvalidOperationException">Thrown when the operation is invalid</exception>
285         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
286         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
287         public void StartObserving(ObservePolicy policy, ResourceQuery query = null)
288         {
289             _observeCallback = (IntPtr resource, int err, int sequenceNumber, IntPtr response, IntPtr userData) =>
290             {
291                 int result;
292                 IntPtr representationHandle;
293                 int ret = Interop.IoTConnectivity.Server.Response.GetResult(response, out result);
294                 if (ret != (int)IoTConnectivityError.None)
295                 {
296                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get result");
297                     return;
298                 }
299
300                 ret = Interop.IoTConnectivity.Server.Response.GetRepresentation(response, out representationHandle);
301                 if (ret != (int)IoTConnectivityError.None)
302                 {
303                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get representation");
304                     return;
305                 }
306
307                 Representation repr = null;
308                 try
309                 {
310                     repr = new Representation(representationHandle);
311                 }
312                 catch (Exception exp)
313                 {
314                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new representation: " + exp.Message);
315                     return;
316                 }
317
318                 ObserverNotifiedEventArgs e = new ObserverNotifiedEventArgs()
319                 {
320                     Representation = repr,
321                     Result = (ResponseCode)result
322                 };
323                 ObserverNotified?.Invoke(this, e);
324             };
325
326             IntPtr queryHandle = IntPtr.Zero;
327             if (query != null)
328             {
329                 queryHandle = query._resourceQueryHandle;
330             }
331
332             int errCode = Interop.IoTConnectivity.Client.RemoteResource.RegisterObserve(_remoteResourceHandle, (int)policy, queryHandle, _observeCallback, IntPtr.Zero);
333             if (errCode != (int)IoTConnectivityError.None)
334             {
335                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register observe callbacks");
336                 throw IoTConnectivityErrorFactory.GetException(errCode);
337             }
338         }
339
340         /// <summary>
341         /// Stops observing on the resource
342         /// </summary>
343         /// <privilege>
344         /// http://tizen.org/privilege/internet
345         /// </privilege>
346         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
347         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
348         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
349         public void StopObserving()
350         {
351             int ret = Interop.IoTConnectivity.Client.RemoteResource.DeregisterObserve(_remoteResourceHandle);
352             if (ret != (int)IoTConnectivityError.None)
353             {
354                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to deregister observe callbacks");
355                 throw IoTConnectivityErrorFactory.GetException(ret);
356             }
357         }
358
359         /// <summary>
360         /// Gets the attributes of a resource, asynchronously
361         /// </summary>
362         /// <privilege>
363         /// http://tizen.org/privilege/internet
364         /// </privilege>
365         /// <param name="query">The ResourceQuery to send to server</param>
366         /// <returns>Remote response with result and representation</returns>
367         public async Task<RemoteResponse> GetAsync(ResourceQuery query = null)
368         {
369             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
370
371             IntPtr id = IntPtr.Zero;
372             lock (_responseCallbacksMap)
373             {
374                 id = (IntPtr)_responseCallbackId++;
375             }
376             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
377             {
378                 IntPtr responseCallbackId = userData;
379                 lock(_responseCallbacksMap)
380                 {
381                     _responseCallbacksMap.Remove(responseCallbackId);
382                 }
383
384                 if (responseHandle != IntPtr.Zero)
385                 {
386                     try
387                     {
388                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
389                     }
390                     catch(Exception exp)
391                     {
392                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
393                         tcsRemoteResponse.TrySetException(exp);
394                     }
395                 }
396                 else
397                 {
398                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
399                 }
400             };
401
402             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
403             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Get(_remoteResourceHandle, queryHandle, _responseCallbacksMap[id], id);
404             if (errCode != (int)IoTConnectivityError.None)
405             {
406                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource attributes");
407                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
408             }
409             return await tcsRemoteResponse.Task;
410         }
411
412         /// <summary>
413         /// Puts the representation of a resource, asynchronously.
414         /// </summary>
415         /// <privilege>
416         /// http://tizen.org/privilege/internet
417         /// </privilege>
418         /// <param name="representation">Resource representation to put</param>
419         /// <param name="query">The ResourceQuery to send to server</param>
420         /// <returns>Remote response with result and representation</returns>
421         public async Task<RemoteResponse> PutAsync(Representation representation, ResourceQuery query = null)
422         {
423             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
424
425             IntPtr id = IntPtr.Zero;
426             lock (_responseCallbacksMap)
427             {
428                 id = (IntPtr)_responseCallbackId++;
429             }
430             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
431             {
432                 IntPtr responseCallbackId = userData;
433                 lock (_responseCallbacksMap)
434                 {
435                     _responseCallbacksMap.Remove(responseCallbackId);
436                 }
437                 if (err == (int)(IoTConnectivityError.Iotivity))
438                 {
439                     RemoteResponse response = new RemoteResponse();
440                     response.Result = ResponseCode.Forbidden;
441                     response.Representation = null;
442                     tcsRemoteResponse.TrySetResult(response);
443                 }
444                 else if (responseHandle != IntPtr.Zero)
445                 {
446                     try
447                     {
448                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
449                     }
450                     catch (Exception exp)
451                     {
452                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
453                         tcsRemoteResponse.TrySetException(exp);
454                     }
455                 }
456                 else
457                 {
458                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
459                 }
460             };
461             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
462             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Put(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
463             if (errCode != (int)IoTConnectivityError.None)
464             {
465                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to put resource representation");
466                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
467             }
468             return await tcsRemoteResponse.Task;
469         }
470
471         /// <summary>
472         /// Post request on a resource, asynchronously
473         /// </summary>
474         /// <privilege>
475         /// http://tizen.org/privilege/internet
476         /// </privilege>
477         /// <param name="representation">Resource representation of request</param>
478         /// <param name="query">The ResourceQuery to send to server</param>
479         /// <returns>Remote response with result and representation</returns>
480         public async Task<RemoteResponse> PostAsync(Representation representation, ResourceQuery query = null)
481         {
482             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
483
484             IntPtr id = IntPtr.Zero;
485             lock (_responseCallbacksMap)
486             {
487                 id = (IntPtr)_responseCallbackId++;
488             }
489             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
490             {
491                 IntPtr responseCallbackId = userData;
492                 lock (_responseCallbacksMap)
493                 {
494                     _responseCallbacksMap.Remove(responseCallbackId);
495                 }
496                 if (responseHandle != IntPtr.Zero)
497                 {
498                     try
499                     {
500                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
501                     }
502                     catch (Exception exp)
503                     {
504                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
505                         tcsRemoteResponse.TrySetException(exp);
506                     }
507                 }
508                 else
509                 {
510                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
511                 }
512             };
513             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
514             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Post(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
515             if (errCode != (int)IoTConnectivityError.None)
516             {
517                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to post request");
518                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
519             }
520             return await tcsRemoteResponse.Task;
521         }
522
523         /// <summary>
524         /// Deletes the resource, asynchronously
525         /// </summary>
526         /// <privilege>
527         /// http://tizen.org/privilege/internet
528         /// </privilege>
529         /// <returns>Remote response with result and representation</returns>
530         public async Task<RemoteResponse> DeleteAsync()
531         {
532             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
533
534             IntPtr id = IntPtr.Zero;
535             lock (_responseCallbacksMap)
536             {
537                 id = (IntPtr)_responseCallbackId++;
538             }
539             _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
540             {
541                 IntPtr responseCallbackId = userData;
542                 lock (_responseCallbacksMap)
543                 {
544                     _responseCallbacksMap.Remove(responseCallbackId);
545                 }
546                 if (err == (int)(IoTConnectivityError.Iotivity))
547                 {
548                     RemoteResponse response = new RemoteResponse();
549                     response.Result = ResponseCode.Forbidden;
550                     response.Representation = null;
551                     tcsRemoteResponse.TrySetResult(response);
552                 }
553                 else if (responseHandle != IntPtr.Zero)
554                 {
555                     try
556                     {
557                         tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
558                     }
559                     catch (Exception exp)
560                     {
561                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
562                         tcsRemoteResponse.TrySetException(exp);
563                     }
564                 }
565                 else
566                 {
567                     tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
568                 }
569             };
570
571             int errCode = Interop.IoTConnectivity.Client.RemoteResource.Delete(_remoteResourceHandle, _responseCallbacksMap[id], id);
572             if (errCode != (int)IoTConnectivityError.None)
573             {
574                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to delete");
575                 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
576             }
577             return await tcsRemoteResponse.Task;
578         }
579
580         /// <summary>
581         /// Releases any unmanaged resources used by this object.
582         /// </summary>
583         public void Dispose()
584         {
585             Dispose(true);
586             GC.SuppressFinalize(this);
587         }
588
589         internal static Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType GetConnectivityType(string hostAddress)
590         {
591             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None;
592
593             Log.Info(IoTConnectivityErrorFactory.LogTag, hostAddress);
594
595             if (hostAddress == IoTConnectivityClientManager.MulticastAddress)
596             {
597                 type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
598             }
599             else
600             {
601                 IPAddress address;
602                 string hostName = hostAddress;
603                 if (hostAddress.Contains(":"))
604                 {
605                     string[] hostParts = hostAddress.Split(':');
606                     if (hostParts.Length == 2)
607                     {
608                         hostName = hostParts[0];
609                     }
610                 }
611                 if (hostAddress.Contains("%"))
612                 {
613                     string[] hostParts = hostAddress.Split('%');
614                     if (hostParts.Length == 2)
615                     {
616                         hostName = hostParts[0];
617                     }
618                 }
619                 if (hostName.Contains("["))
620                 {
621                     string[] hostParts = hostName.Split('[');
622                     if (hostParts.Length == 2)
623                     {
624                         hostName = hostParts[1];
625                     }
626                 }
627                 Log.Info(IoTConnectivityErrorFactory.LogTag, hostName);
628                 if (IPAddress.TryParse(hostName, out address))
629                 {
630                     switch (address.AddressFamily)
631                     {
632                         case System.Net.Sockets.AddressFamily.InterNetwork:
633                             type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
634                             break;
635                         case System.Net.Sockets.AddressFamily.InterNetworkV6:
636                             type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv6;
637                             break;
638                         default:
639                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to parse for Ipv4 or Ipv6");
640                             break;
641                     }
642                 }
643                 else
644                 {
645                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to parse hostname " + hostName);
646                 }
647             }
648             return type;
649         }
650
651         /// <summary>
652         /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
653         /// </summary>
654         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
655         protected virtual void Dispose(bool disposing)
656         {
657             if (_disposed)
658                 return;
659
660             if (disposing)
661             {
662                 // Free managed objects
663             }
664
665             Interop.IoTConnectivity.Client.RemoteResource.Destroy(_remoteResourceHandle);
666             _disposed = true;
667         }
668
669         private void HandleCachePolicyChanged()
670         {
671             if (_cacheEnabled)
672             {
673                 _cacheUpdatedCallback = (IntPtr resource, IntPtr representation, IntPtr userData) =>
674                 {
675                     if (CacheEnabled)
676                     {
677                         Representation repr = null;
678                         try
679                         {
680                             repr = new Representation(representation);
681                         }
682                         catch (Exception exp)
683                         {
684                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new Representation: " + exp.Message);
685                             return;
686                         }
687
688                         CacheUpdatedEventArgs e = new CacheUpdatedEventArgs()
689                         {
690                             Representation = repr
691                         };
692                         CacheUpdated?.Invoke(this, e);
693                     }
694                 };
695
696                 int ret = Interop.IoTConnectivity.Client.RemoteResource.StartCaching(_remoteResourceHandle, _cacheUpdatedCallback, IntPtr.Zero);
697                 if (ret != (int)IoTConnectivityError.None)
698                 {
699                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add cache updated event handler");
700                     throw IoTConnectivityErrorFactory.GetException(ret);
701                 }
702             }
703             else
704             {
705                 int ret = Interop.IoTConnectivity.Client.RemoteResource.StopCaching(_remoteResourceHandle);
706                 if (ret != (int)IoTConnectivityError.None)
707                 {
708                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove cache updated event handler");
709                     throw IoTConnectivityErrorFactory.GetException(ret);
710                 }
711             }
712         }
713
714         private void RegisterStateChangedEvent()
715         {
716             _stateChangedCallback = (IntPtr resource, int state, IntPtr userData) =>
717             {
718                 StateChangedEventArgs e = new StateChangedEventArgs()
719                 {
720                     State = (ResourceState)state
721                 };
722                 _stateChangedEventHandler?.Invoke(null, e);
723             };
724
725             int ret = Interop.IoTConnectivity.Client.RemoteResource.StartMonitoring(_remoteResourceHandle, _stateChangedCallback, IntPtr.Zero);
726             if (ret != (int)IoTConnectivityError.None)
727             {
728                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add state changed event handler");
729                 throw IoTConnectivityErrorFactory.GetException(ret);
730             }
731         }
732
733         private void UnregisterStateChangedEvent()
734         {
735             int ret = Interop.IoTConnectivity.Client.RemoteResource.StopMonitoring(_remoteResourceHandle);
736             if (ret != (int)IoTConnectivityError.None)
737             {
738                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove state changed event handler");
739                 throw IoTConnectivityErrorFactory.GetException(ret);
740             }
741         }
742
743         private void CreateRemoteResource(IntPtr resourceTypeHandle, IntPtr resourceInterfaceHandle)
744         {
745             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = GetConnectivityType(HostAddress);
746             if (connectivityType == Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None)
747             {
748                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Unable to parse host address");
749                 throw new ArgumentException("Unable to parse host address");
750             }
751             int ret = Interop.IoTConnectivity.Client.RemoteResource.Create(HostAddress, (int)connectivityType, UriPath, (int)Policy, resourceTypeHandle, resourceInterfaceHandle, out _remoteResourceHandle);
752             if (ret != (int)IoTConnectivityError.None)
753             {
754                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get remote resource");
755                 throw IoTConnectivityErrorFactory.GetException(ret);
756             }
757         }
758
759         private void SetRemoteResource()
760         {
761             IntPtr hostAddressPtr, uriPathPtr;
762             int ret = Interop.IoTConnectivity.Client.RemoteResource.GetHostAddress(_remoteResourceHandle, out hostAddressPtr);
763             if (ret != (int)IoTConnectivityError.None)
764             {
765                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get host address");
766                 throw IoTConnectivityErrorFactory.GetException(ret);
767             }
768
769             ret = Interop.IoTConnectivity.Client.RemoteResource.GetUriPath(_remoteResourceHandle, out uriPathPtr);
770             if (ret != (int)IoTConnectivityError.None)
771             {
772                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
773                 throw IoTConnectivityErrorFactory.GetException(ret);
774             }
775
776             int policy = (int)ResourcePolicy.NoProperty;
777             ret = Interop.IoTConnectivity.Client.RemoteResource.GetPolicies(_remoteResourceHandle, out policy);
778             if (ret != (int)IoTConnectivityError.None)
779             {
780                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
781                 throw IoTConnectivityErrorFactory.GetException(ret);
782             }
783
784             IntPtr typesHandle, interfacesHandle;
785             ret = Interop.IoTConnectivity.Client.RemoteResource.GetTypes(_remoteResourceHandle, out typesHandle);
786             if (ret != (int)IoTConnectivityError.None)
787             {
788                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource types");
789                 throw IoTConnectivityErrorFactory.GetException(ret);
790             }
791
792             ret = Interop.IoTConnectivity.Client.RemoteResource.GetInterfaces(_remoteResourceHandle, out interfacesHandle);
793             if (ret != (int)IoTConnectivityError.None)
794             {
795                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource interfaces");
796                 throw IoTConnectivityErrorFactory.GetException(ret);
797             }
798
799             IntPtr deviceIdPtr;
800             ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceId(_remoteResourceHandle, out deviceIdPtr);
801             if (ret != (int)IoTConnectivityError.None)
802             {
803                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device id");
804                 throw IoTConnectivityErrorFactory.GetException(ret);
805             }
806             DeviceId = (deviceIdPtr != IntPtr.Zero) ? Marshal.PtrToStringAnsi(deviceIdPtr) : string.Empty;
807             HostAddress = (hostAddressPtr != IntPtr.Zero) ? Marshal.PtrToStringAnsi(hostAddressPtr) : string.Empty;
808             UriPath = (uriPathPtr != IntPtr.Zero) ? Marshal.PtrToStringAnsi(uriPathPtr) : string.Empty;
809             Types = new ResourceTypes(typesHandle);
810             Interfaces = new ResourceInterfaces(interfacesHandle);
811             Policy = (ResourcePolicy)policy;
812         }
813
814         private RemoteResponse GetRemoteResponse(IntPtr response)
815         {
816             int result;
817             IntPtr representationHandle, optionsHandle;
818             int ret = Interop.IoTConnectivity.Server.Response.GetResult(response, out result);
819             if (ret != (int)IoTConnectivityError.None)
820             {
821                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get result");
822                 throw IoTConnectivityErrorFactory.GetException(ret);
823             }
824
825             ret = Interop.IoTConnectivity.Server.Response.GetRepresentation(response, out representationHandle);
826             if (ret != (int)IoTConnectivityError.None)
827             {
828                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get representation");
829                 throw IoTConnectivityErrorFactory.GetException(ret);
830             }
831
832             ret = Interop.IoTConnectivity.Server.Response.GetOptions(response, out optionsHandle);
833             if (ret != (int)IoTConnectivityError.None)
834             {
835                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get options");
836                 throw IoTConnectivityErrorFactory.GetException(ret);
837             }
838             return new RemoteResponse()
839             {
840                 Result = (ResponseCode)result,
841                 Representation = new Representation(representationHandle),
842                 Options = (optionsHandle == IntPtr.Zero)? null : new ResourceOptions(optionsHandle)
843             };
844         }
845     }
846 }