Release 4.0.0-preview1-00213
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.IoTConnectivity / Tizen.Network.IoTConnectivity / IoTConnectivityClientManager.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.Runtime.InteropServices;
20
21 namespace Tizen.Network.IoTConnectivity
22 {
23     /// <summary>
24     /// IoT connectivity client manager consists of client side APIs.
25     /// </summary>
26     /// <since_tizen> 3 </since_tizen>
27     public static class IoTConnectivityClientManager
28     {
29         /// <summary>
30         /// The IP Address for multicast.
31         /// </summary>
32         /// <since_tizen> 3 </since_tizen>
33         public const string MulticastAddress = null;
34
35         private static int s_presenceListenerId = 1;
36         private static Dictionary<IntPtr, Interop.IoTConnectivity.Client.Presence.PresenceCallback> s_presenceCallbacksMap = new Dictionary<IntPtr, Interop.IoTConnectivity.Client.Presence.PresenceCallback>();
37         private static Dictionary<IntPtr, IntPtr> s_presenceHandlesMap = new Dictionary<IntPtr, IntPtr>();
38
39         private static int s_requestId = 1;
40         private static Dictionary<IntPtr, Interop.IoTConnectivity.Client.ResourceFinder.FoundResourceCallback> s_resourceFoundCallbacksMap = new Dictionary<IntPtr, Interop.IoTConnectivity.Client.ResourceFinder.FoundResourceCallback>();
41         private static Dictionary<IntPtr, Interop.IoTConnectivity.Client.DeviceInformation.DeviceInformationCallback> s_deviceInformationCallbacksMap = new Dictionary<IntPtr, Interop.IoTConnectivity.Client.DeviceInformation.DeviceInformationCallback>();
42         private static Dictionary<IntPtr, Interop.IoTConnectivity.Client.PlatformInformation.PlatformInformationCallback> s_platformInformationCallbacksMap = new Dictionary<IntPtr, Interop.IoTConnectivity.Client.PlatformInformation.PlatformInformationCallback>();
43
44         /// <summary>
45         /// PresenceReceived event. This event occurs when server starts sending presence of a resource.
46         /// </summary>
47         /// <since_tizen> 3 </since_tizen>
48         public static event EventHandler<PresenceReceivedEventArgs> PresenceReceived;
49
50         /// <summary>
51         /// ResourceFound event. This event occurs when a resource is found from the remote server
52         /// after sending request using API StartFindingResource().
53         /// </summary>
54         /// <since_tizen> 3 </since_tizen>
55         public static event EventHandler<ResourceFoundEventArgs> ResourceFound;
56
57         /// <summary>
58         /// PlatformInformationFound event. This event occurs when platform information is found
59         /// after sending request using API StartFindingPlatformInformation().
60         /// </summary>
61         /// <since_tizen> 3 </since_tizen>
62         public static event EventHandler<PlatformInformationFoundEventArgs> PlatformInformationFound;
63
64         /// <summary>
65         /// DeviceInformationFound event. This event occurs when device information is found
66         /// after sending request using API StartFindingDeviceInformation().
67         /// </summary>
68         /// <since_tizen> 3 </since_tizen>
69         public static event EventHandler<DeviceInformationFoundEventArgs> DeviceInformationFound;
70
71         /// <summary>
72         /// FindingError event. This event occurs when an error is found.
73         /// </summary>
74         /// <since_tizen> 3 </since_tizen>
75         public static event EventHandler<FindingErrorOccurredEventArgs> FindingErrorOccurred;
76
77         /// <summary>
78         /// Timeout in seconds.
79         /// </summary>
80         /// <since_tizen> 3 </since_tizen>
81         /// <value>
82         /// Value to be set must be in range from 1 to 3600. Default timeout interval value is 30.\n
83         /// Sets/gets the timeout of StartFindingResource(), StartFindingDeviceInformation(), StartFindingPlatformInformation(),
84         /// RemoteResource.GetAsync(), RemoteResource.PutAsync(), RemoteResource.PostAsync() and RemoteResource.DeleteAsync() APIs.\n
85         /// Setter can throw exception.
86         /// </value>
87         /// <pre>
88         /// Initialize() should be called to initialize.
89         /// </pre>
90         /// <code>
91         /// IoTConnectivityClientManager.Initialize();
92         /// IoTConnectivityClientManager.TimeOut = 120;
93         /// </code>
94         public static int TimeOut
95         {
96             get
97             {
98                 int timeout;
99                 int ret = Interop.IoTConnectivity.Client.IoTCon.GetTimeout(out timeout);
100                 if (ret != (int)IoTConnectivityError.None)
101                 {
102                     Log.Warn(IoTConnectivityErrorFactory.LogTag, "Failed to get timeout");
103                     return 0;
104                 }
105                 return timeout;
106             }
107             set
108             {
109                 int ret = Interop.IoTConnectivity.Client.IoTCon.SetTimeout(value);
110                 if (ret != (int)IoTConnectivityError.None)
111                 {
112                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set timeout");
113                     throw IoTConnectivityErrorFactory.GetException(ret);
114                 }
115             }
116         }
117
118         /// <summary>
119         /// Polling interval of IoTConnectivity.
120         /// </summary>
121         /// <since_tizen> 3 </since_tizen>
122         /// <value>
123         /// Sets/Gets the polling inerval(milliseconds) of IoTCon. Default value is 100 milliseconds.
124         /// Value to be set must be in range from 1 to 999. The closer to 0, the faster it operates.
125         /// Setter is invoked immediately for changing the interval.
126         /// If you want the faster operation, we recommend you set 10 milliseconds for polling interval.
127         /// Setter can throw exception.
128         /// </value>
129         /// <pre>
130         /// Initialize() should be called to initialize.
131         /// </pre>
132         /// <code>
133         /// IoTConnectivityClientManager.Initialize();
134         /// IoTConnectivityClientManager.PollingInterval = 100;
135         /// </code>
136         public static int PollingInterval
137         {
138             get
139             {
140                 int interval;
141                 int ret = Interop.IoTConnectivity.Client.IoTCon.GetPollingInterval(out interval);
142                 if (ret != (int)IoTConnectivityError.None)
143                 {
144                     Log.Warn(IoTConnectivityErrorFactory.LogTag, "Failed to get polling interval");
145                     return 0;
146                 }
147                 return interval;
148             }
149             set
150             {
151                 int ret = Interop.IoTConnectivity.Client.IoTCon.SetPollingInterval(value);
152                 if (ret != (int)IoTConnectivityError.None)
153                 {
154                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set polling interval");
155                     throw IoTConnectivityErrorFactory.GetException(ret);
156                 }
157             }
158         }
159
160         /// <summary>
161         /// Initializes IoTCon.
162         /// Call this function to start IoTCon.
163         /// </summary>
164         /// <since_tizen> 3 </since_tizen>
165         /// <remarks>
166         /// @a filePath point to a file for handling secure virtual resources.
167         /// The file that is CBOR(Concise Binary Object Representation)-format must already exist
168         /// in @a filePath. We recommend to use application-local file for @a filePath.
169         /// </remarks>
170         /// <privilege>
171         /// http://tizen.org/privilege/network.get \n
172         /// http://tizen.org/privilege/internet
173         /// </privilege>
174         /// <privlevel>public</privlevel>
175         /// <param name="filePath">The file path to point to storage for handling secure virtual resources.</param>
176         /// <feature>http://tizen.org/feature/iot.ocf</feature>
177         /// <post>
178         /// You must call Deinitialize() if IoTCon API is no longer needed.
179         /// </post>
180         /// <seealso cref="Deinitialize()"/>
181         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
182         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter.</exception>
183         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
184         /// <code>
185         /// string filePath = "../../res/iotcon-test-svr-db-client.dat";
186         /// IoTConnectivityClientManager.Initialize(filePath);
187         /// </code>
188         public static void Initialize(string filePath)
189         {
190             int ret = Interop.IoTConnectivity.Client.IoTCon.Initialize(filePath);
191             if (ret != (int)IoTConnectivityError.None)
192             {
193                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to initialize");
194                 throw IoTConnectivityErrorFactory.GetException(ret);
195             }
196         }
197
198         /// <summary>
199         /// Deinitializes IoTCon.
200         /// </summary>
201         /// <since_tizen> 3 </since_tizen>
202         /// <remarks>
203         /// This API must be called if IoTCon API is no longer needed.
204         /// </remarks>
205         /// <feature>http://tizen.org/feature/iot.ocf</feature>
206         /// <pre>
207         /// Initialize() should be called to initialize.
208         /// </pre>
209         /// <seealso cref="Initialize(string)"/>
210         /// <code>
211         /// IoTConnectivityClientManager.Deinitialize();
212         /// </code>
213         public static void Deinitialize()
214         {
215             s_presenceListenerId = 1;
216             s_presenceCallbacksMap.Clear();
217             s_presenceHandlesMap.Clear();
218
219             s_requestId = 1;
220             s_resourceFoundCallbacksMap.Clear();
221             s_deviceInformationCallbacksMap.Clear();
222             s_platformInformationCallbacksMap.Clear();
223
224             PresenceReceived = delegate{};
225             ResourceFound = delegate{};
226             PlatformInformationFound = delegate{};
227             DeviceInformationFound = delegate{};
228             FindingErrorOccurred = delegate{};
229
230             Interop.IoTConnectivity.Client.IoTCon.Deinitialize();
231         }
232
233         /// <summary>
234         /// Invokes a next message from a queue for receiving messages from others, immediately.
235         /// </summary>
236         /// <since_tizen> 3 </since_tizen>
237         /// <remarks>
238         /// This API invokes a next message from a queue for receiving messages from others, immediately.
239         /// After calling the API, it continues the polling with existing interval.
240         /// </remarks>
241         /// <feature>http://tizen.org/feature/iot.ocf</feature>
242         /// <pre>
243         /// Initialize() should be called to initialize.
244         /// </pre>
245         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
246         /// <code>
247         /// IoTConnectivityClientManager.InvokePolling();
248         /// </code>
249         public static void InvokePolling()
250         {
251             int ret = Interop.IoTConnectivity.Client.IoTCon.InvokePolling();
252             if (ret != (int)IoTConnectivityError.None)
253             {
254                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to invoke polling");
255                 throw IoTConnectivityErrorFactory.GetException(ret);
256             }
257         }
258
259         /// <summary>
260         /// Starts receiving presence events.
261         /// </summary>
262         /// <since_tizen> 3 </since_tizen>
263         /// <remarks>
264         /// Sends request to receive presence to an interested server's resource with resourceType.
265         /// If succeeded, <see cref="PresenceReceived"/> event handler will be triggered when the server sends presence.
266         /// A server sends presence events when adds / removes / alters a resource or start / stop presence.\n
267         /// @a hostAddress could be <see cref="MulticastAddress"/> for IPv4 multicast.
268         /// The length of @ resourceType should be less than or equal to 61. The @ resourceType must start with a lowercase alphabetic character, followed by a sequence
269         /// of lowercase alphabetic, numeric, ".", or "-" characters, and contains no white space.
270         /// </remarks>
271         /// <privilege>
272         /// http://tizen.org/privilege/internet
273         /// </privilege>
274         /// <privlevel>public</privlevel>
275         /// <param name="hostAddress">The address or addressable name of the server.</param>
276         /// <param name="resourceType">A resource type that a client is interested in.</param>
277         /// <returns>PresenceId - An identifier for this request.</returns>
278         /// <feature>http://tizen.org/feature/iot.ocf</feature>
279         /// <pre>Initialize() should be called to initialize.</pre>
280         /// <post>
281         /// When the resource receive presence, <see cref="PresenceReceived"/> event handler will be invoked.\n
282         /// You must destroy presence by calling StopReceivingPresence() if presence event is no longer needed.
283         /// </post>
284         /// <seealso cref="IoTConnectivityServerManager.StartSendingPresence()"/>
285         /// <seealso cref="IoTConnectivityServerManager.StopSendingPresence()"/>
286         /// <seealso cref="StopReceivingPresence()"/>
287         /// <seealso cref="PresenceReceived"/>
288         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
289         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter.</exception>
290         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
291         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
292         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
293         /// <code>
294         /// EventHandler<PresenceReceivedEventArgs> handler = (sender, e) => {
295         ///     Console.Log("PresenceReceived, presence id :" + e.PresenceId);
296         /// }
297         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
298         ///     Console.Log("Found error :" + e.Error.Message);
299         /// }
300         /// IoTConnectivityClientManager.PresenceReceived += handler;
301         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
302         /// // Do not forget to remove these event handlers when they are not required any more.
303         /// int id = IoTConnectivityClientManager.StartReceivingPresence(IoTConnectivityClientManager.MulticastAddress, "oic.iot.door");
304         /// </code>
305         public static int StartReceivingPresence(string hostAddress, string resourceType)
306         {
307             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
308
309             if (resourceType != null && !ResourceTypes.IsValid(resourceType))
310             {
311                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Invalid type");
312                 throw new ArgumentException("Invalid type");
313             }
314
315             IntPtr id = IntPtr.Zero;
316             lock (s_presenceCallbacksMap)
317             {
318                 id = (IntPtr)s_presenceListenerId++;
319             }
320             s_presenceCallbacksMap[id] = (IntPtr presence, int result, IntPtr presenceResponseHandle, IntPtr userData) =>
321             {
322                 int presenceId = (int)userData;
323                 if (result == (int)IoTConnectivityError.None)
324                 {
325                     if (presenceResponseHandle != IntPtr.Zero)
326                     {
327                         PresenceReceivedEventArgs e = GetPresenceReceivedEventArgs(presenceId, presenceResponseHandle);
328                         if (e == null)
329                         {
330                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't get PresenceReceivedEventArgs");
331                             return;
332                         }
333                         PresenceReceived?.Invoke(null, e);
334                     }
335                     else
336                     {
337                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
338                         return;
339                     }
340                 }
341                 else
342                 {
343                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(presenceId, result);
344                     FindingErrorOccurred?.Invoke(null, e);
345                 }
346             };
347
348             IntPtr presenceHandle;
349             int errorCode = Interop.IoTConnectivity.Client.Presence.AddPresenceCb(hostAddress, (int)connectivityType, resourceType, s_presenceCallbacksMap[id], id, out presenceHandle);
350             if (errorCode != (int)IoTConnectivityError.None)
351             {
352                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register presence event handler");
353                 lock (s_presenceCallbacksMap)
354                 {
355                     s_presenceCallbacksMap.Remove(id);
356                 }
357                 throw IoTConnectivityErrorFactory.GetException(errorCode);
358             }
359
360             lock (s_presenceHandlesMap)
361             {
362                 s_presenceHandlesMap[id] = presenceHandle;
363             }
364             return (int)id;
365         }
366
367         /// <summary>
368         /// Stops receiving presence events.
369         /// </summary>
370         /// <since_tizen> 3 </since_tizen>
371         /// <remarks>
372         /// Sends request to not to receive server's presence any more.
373         /// </remarks>
374         /// <privilege>
375         /// http://tizen.org/privilege/internet
376         /// </privilege>
377         /// <privlevel>public</privlevel>
378         /// <param name="presenceId">The start presence request identifier.</param>
379         /// <feature>http://tizen.org/feature/iot.ocf</feature>
380         /// <pre>
381         /// Initialize() should be called to initialize.
382         /// </pre>
383         /// <seealso cref="IoTConnectivityServerManager.StartSendingPresence()"/>
384         /// <seealso cref="IoTConnectivityServerManager.StopSendingPresence()"/>
385         /// <seealso cref="StartReceivingPresence()"/>
386         /// <seealso cref="PresenceReceived"/>
387         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
388         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter.</exception>
389         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
390         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
391         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
392         /// <code>
393         /// EventHandler<PresenceReceivedEventArgs> handler = (sender, e) => {
394         ///     Console.Log("PresenceReceived, presence id :" + e.PresenceId);
395         /// }
396         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
397         ///     Console.Log("Found error :" + e.Error.Message);
398         /// }
399         /// IoTConnectivityClientManager.PresenceReceived += handler;
400         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
401         /// int id = IoTConnectivityClientManager.StartReceivingPresence(IoTConnectivityClientManager.MulticastAddress, "oic.iot.door");
402         /// await Task.Delay(5000); // Do other things here
403         /// // Call StopReceivingPresence() when receiving presence is not required any more
404         /// IoTConnectivityClientManager.PresenceReceived -= handler;
405         /// IoTConnectivityClientManager.FindingErrorOccurred -= errorHandler;
406         /// IoTConnectivityClientManager.StopReceivingPresence(id);
407         /// </code>
408         public static void StopReceivingPresence(int presenceId)
409         {
410             if (!s_presenceHandlesMap.ContainsKey((IntPtr)presenceId))
411             {
412                 Log.Error(IoTConnectivityErrorFactory.LogTag, "this presenceId does not exist");
413                 throw new ArgumentException("this presenceId does not exist");
414             }
415
416             if (s_presenceHandlesMap.ContainsKey((IntPtr)presenceId))
417             {
418                 IntPtr presenceHandle = s_presenceHandlesMap[(IntPtr)presenceId];
419                 int ret = Interop.IoTConnectivity.Client.Presence.RemovePresenceCb(presenceHandle);
420                 if (ret != (int)IoTConnectivityError.None)
421                 {
422                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to deregister presence event handler");
423                     throw IoTConnectivityErrorFactory.GetException(ret);
424                 }
425
426                 lock (s_presenceHandlesMap)
427                 {
428                     s_presenceHandlesMap.Remove((IntPtr)presenceId);
429                 }
430             }
431
432             if (s_presenceCallbacksMap.ContainsKey((IntPtr)presenceId))
433             {
434                 lock (s_presenceCallbacksMap)
435                 {
436                     s_presenceCallbacksMap.Remove((IntPtr)presenceId);
437                 }
438             }
439         }
440
441         /// <summary>
442         /// Starts finding resources.
443         /// </summary>
444         /// <since_tizen> 3 </since_tizen>
445         /// <remarks>
446         /// Sends request to find a resource of @a hostAddress server with @a resourceType.
447         /// If succeeded, <see cref="ResourceFound"/> event handler will be triggered with information of the resource.\n
448         /// @a hostAddress could be <see cref="MulticastAddress"/> for the IPv4 multicast.
449         /// The length of @a resourceType should be less than or equal to 61. The @ resourceType must start with a lowercase alphabetic character, followed by a sequence
450         /// of lowercase alphabetic, numeric, ".", or "-" characters, and contains no white space.
451         /// </remarks>
452         /// <privilege>
453         /// http://tizen.org/privilege/internet
454         /// </privilege>
455         /// <privlevel>public</privlevel>
456         /// <param name="hostAddress">The address or addressable name of the server. The address includes a protocol like coaps://.</param>
457         /// <param name="query">The query specified as a filter for founding resources.</param>
458         /// <returns>RequestId - An identifier for this request.</returns>
459         /// <feature>http://tizen.org/feature/iot.ocf</feature>
460         /// <pre>Initialize() should be called to initialize.</pre>
461         /// <post>
462         /// When the resource is found, <see cref="ResourceFound"/> event handler will be invoked.
463         /// </post>
464         /// <seealso cref="ResourceFound"/>
465         /// <seealso cref="ResourceFoundEventArgs"/>
466         /// <seealso cref="TimeOut"/>
467         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
468         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
469         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
470         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
471         /// <code>
472         /// EventHandler<ResourceFoundEventArgs> handler = (sender, e) => {
473         ///     Console.Log("Found resource at host address :" + e.Resource.HostAddress + ", uri :" + e.Resource.UriPath);
474         /// }
475         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
476         ///     Console.Log("Found error :" + e.Error.Message);
477         /// }
478         /// IoTConnectivityClientManager.ResourceFound += handler;
479         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
480         /// ResourceQuery query = new ResourceQuery();
481         /// query.Type = "oic.iot.door";
482         /// // Do not forget to remove these event handlers when they are not required any more.
483         /// int id = IoTConnectivityClientManager.StartFindingResource(null, query);
484         /// </code>
485         public static int StartFindingResource(string hostAddress, ResourceQuery query = null)
486         {
487             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
488
489             IntPtr id = IntPtr.Zero;
490             lock (s_resourceFoundCallbacksMap)
491             {
492                 id = (IntPtr)s_requestId++;
493             }
494             s_resourceFoundCallbacksMap[id] = (IntPtr remoteResourceHandle, int result, IntPtr userData) =>
495             {
496                 if (ResourceFound == null)
497                     return false;
498
499                 int requestId = (int)userData;
500                 if (result == (int)IoTConnectivityError.None)
501                 {
502                     if (remoteResourceHandle != IntPtr.Zero)
503                     {
504                         RemoteResource resource = null;
505                         try
506                         {
507                             resource = new RemoteResource(remoteResourceHandle);
508                         }
509                         catch (Exception exp)
510                         {
511                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't clone RemoteResource's handle: " + exp.Message);
512                             return true;
513                         }
514                         ResourceFoundEventArgs e = new ResourceFoundEventArgs()
515                         {
516                             RequestId = requestId,
517                             EventContinue = true,
518                             Resource = resource
519                         };
520                         ResourceFound?.Invoke(null, e);
521                         Log.Info(IoTConnectivityErrorFactory.LogTag, "e.EventContinue : " + e.EventContinue);
522                         return e.EventContinue;
523                     }
524                     else
525                     {
526                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
527                     }
528                 }
529                 else
530                 {
531                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(requestId, result);
532                     FindingErrorOccurred?.Invoke(null, e);
533
534                     lock (s_resourceFoundCallbacksMap)
535                     {
536                         s_resourceFoundCallbacksMap.Remove(id);
537                     }
538                 }
539                 return true;
540             };
541             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
542             int errorCode = Interop.IoTConnectivity.Client.ResourceFinder.AddResourceFoundCb(hostAddress, (int)connectivityType, queryHandle, s_resourceFoundCallbacksMap[id], id);
543             if (errorCode != (int)IoTConnectivityError.None)
544             {
545                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register resource found event handler");
546                 lock (s_resourceFoundCallbacksMap)
547                 {
548                     s_resourceFoundCallbacksMap.Remove(id);
549                 }
550                 throw IoTConnectivityErrorFactory.GetException(errorCode);
551             }
552             return (int)id;
553         }
554
555         /// <summary>
556         /// Starts finding the device information of remote server.
557         /// </summary>
558         /// <since_tizen> 3 </since_tizen>
559         /// <remarks>
560         /// Requests server for device information.
561         /// If succeeded, <see cref="DeviceInformationFound"/> event handler will be triggered with information of the device.\n
562         /// @a hostAddress could be <see cref="MulticastAddress"/> for the IPv4 multicast.
563         /// </remarks>
564         /// <privilege>
565         /// http://tizen.org/privilege/internet
566         /// </privilege>
567         /// <privlevel>public</privlevel>
568         /// <param name="hostAddress">The host address of the remote server.</param>
569         /// <param name="query">The query specified as a filter for founding resources.</param>
570         /// <returns>RequestId - An identifier for this request.</returns>
571         /// <feature>http://tizen.org/feature/iot.ocf</feature>
572         /// <pre>Initialize() should be called to initialize.</pre>
573         /// <post>
574         /// <see cref="DeviceInformationFound" /> event handler will be invoked.
575         /// </post>
576         /// <seealso cref="IoTConnectivityServerManager.SetDeviceName()"/>
577         /// <seealso cref="DeviceInformationFound"/>
578         /// <seealso cref="DeviceInformationFoundEventArgs"/>
579         /// <seealso cref="TimeOut"/>
580         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
581         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
582         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
583         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
584         /// <code>
585         /// EventHandler<DeviceInformationFoundEventArgs> handler = (sender, e) => {
586         ///     Console.Log("Device information found, id : " + e.RequestId + ", name : " + e.Name);
587         /// }
588         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
589         ///     Console.Log("Found error :" + e.Error.Message);
590         /// }
591         /// IoTConnectivityClientManager.DeviceInformationFound += handler;
592         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
593         /// // Do not forget to remove these event handlers when they are not required any more.
594         /// int id = IoTConnectivityClientManager.StartFindingDeviceInformation(IoTConnectivityClientManager.MulticastAddress);
595         /// </code>
596         public static int StartFindingDeviceInformation(string hostAddress, ResourceQuery query = null)
597         {
598             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
599
600             IntPtr id = IntPtr.Zero;
601             lock (s_deviceInformationCallbacksMap)
602             {
603                 id = (IntPtr)s_requestId++;
604             }
605             s_deviceInformationCallbacksMap[id] = (IntPtr deviceInfoHandle, int result, IntPtr userData) =>
606             {
607                 if (DeviceInformationFound == null)
608                     return false;
609
610                 int requestId = (int)userData;
611                 if (result == (int)IoTConnectivityError.None)
612                 {
613                     if (deviceInfoHandle != IntPtr.Zero)
614                     {
615                         DeviceInformationFoundEventArgs e = GetDeviceInformationFoundEventArgs(requestId, deviceInfoHandle);
616                         if (e == null)
617                         {
618                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't get DeviceInformationFoundEventArgs");
619                             return true;
620                         }
621                         DeviceInformationFound?.Invoke(null, e);
622                         Log.Info(IoTConnectivityErrorFactory.LogTag, "e.EventContinue : " + e.EventContinue);
623                         return e.EventContinue;
624                     }
625                     else
626                     {
627                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
628                     }
629                 }
630                 else
631                 {
632                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(requestId, result);
633                     FindingErrorOccurred?.Invoke(null, e);
634
635                     lock (s_deviceInformationCallbacksMap)
636                     {
637                         s_deviceInformationCallbacksMap.Remove(id);
638                     }
639                 }
640                 return true;
641             };
642
643             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
644             int errorCode = Interop.IoTConnectivity.Client.DeviceInformation.Find(hostAddress, (int)connectivityType, queryHandle, s_deviceInformationCallbacksMap[id], id);
645             if (errorCode != (int)IoTConnectivityError.None)
646             {
647                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device information");
648                 lock (s_deviceInformationCallbacksMap)
649                 {
650                     s_deviceInformationCallbacksMap.Remove(id);
651                 }
652                 throw IoTConnectivityErrorFactory.GetException(errorCode);
653             }
654
655             return (int)id;
656         }
657
658         /// <summary>
659         /// Starts finding the platform information of remote server.
660         /// </summary>
661         /// <since_tizen> 3 </since_tizen>
662         /// <remarks>
663         /// Requests server for platform information.
664         /// If succeeded, <see cref="PlatformInformationFound" /> event handler will be triggered with information of the platform.\n
665         /// @a hostAddress could be <see cref="MulticastAddress"/> for IPv4 multicast.
666         /// </remarks>
667         /// <privilege>
668         /// http://tizen.org/privilege/internet
669         /// </privilege>
670         /// <privlevel>public</privlevel>
671         /// <param name="hostAddress">The host address of remote server.</param>
672         /// <param name="query">The query specified as a filter for founding resources.</param>
673         /// <returns>RequestId - An identifier for this request.</returns>
674         /// <feature>http://tizen.org/feature/iot.ocf</feature>
675         /// <pre>Initialize() should be called to initialize.</pre>
676         /// <post>
677         /// <see cref="PlatformInformationFound" /> event handler will be invoked.
678         /// </post>
679         /// <seealso cref="PlatformInformationFound"/>
680         /// <seealso cref="PlatformInformationFoundEventArgs"/>
681         /// <seealso cref="TimeOut"/>
682         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
683         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
684         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
685         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
686         /// <code>
687         /// EventHandler<PlatformInformationFoundEventArgs> handler = (sender, e) => {
688         ///     Console.Log("PlatformInformationFound :" + e.RequestId);
689         /// }
690         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
691         ///     Console.Log("Found error :" + e.Error.Message);
692         /// }
693         /// IoTConnectivityClientManager.PlatformInformationFound += handler;
694         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
695         /// // Do not forget to remove these event handlers when they are not required any more.
696         /// int id = IoTConnectivityClientManager.StartFindingPlatformInformation(IoTConnectivityClientManager.MulticastAddress);
697         /// </code>
698         public static int StartFindingPlatformInformation(string hostAddress, ResourceQuery query = null)
699         {
700             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
701
702             IntPtr id = IntPtr.Zero;
703             lock (s_platformInformationCallbacksMap)
704             {
705                 id = (IntPtr)s_requestId++;
706             }
707             s_platformInformationCallbacksMap[id] = (IntPtr platformInfoHandle, int result, IntPtr userData) =>
708             {
709                 if (PlatformInformationFound == null)
710                     return false;
711
712                 int requestId = (int)userData;
713                 if (result == (int)IoTConnectivityError.None)
714                 {
715                     if (platformInfoHandle != IntPtr.Zero)
716                     {
717                         PlatformInformationFoundEventArgs e = GetPlatformInformationFoundEventArgs(requestId, platformInfoHandle);
718                         if (e == null)
719                         {
720                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't get PlatformInformationFoundEventArgs");
721                             return true;
722                         }
723                         PlatformInformationFound?.Invoke(null, e);
724                         Log.Info(IoTConnectivityErrorFactory.LogTag, "e.EventContinue : " + e.EventContinue);
725                         return e.EventContinue;
726                     }
727                     else
728                     {
729                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
730                     }
731                 }
732                 else
733                 {
734                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(requestId, result);
735                     FindingErrorOccurred?.Invoke(null, e);
736
737                     lock (s_platformInformationCallbacksMap)
738                     {
739                         s_platformInformationCallbacksMap.Remove(id);
740                     }
741                 }
742                 return true;
743             };
744
745             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
746             int errorCode = Interop.IoTConnectivity.Client.PlatformInformation.Find(hostAddress, (int)connectivityType, queryHandle, s_platformInformationCallbacksMap[id], id);
747             if (errorCode != (int)IoTConnectivityError.None)
748             {
749                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get platform information");
750                 lock (s_platformInformationCallbacksMap)
751                 {
752                     s_platformInformationCallbacksMap.Remove(id);
753                 }
754                 throw IoTConnectivityErrorFactory.GetException(errorCode);
755             }
756
757             return (int)id;
758         }
759
760         // Private methods
761         private static PresenceReceivedEventArgs GetPresenceReceivedEventArgs(int presenceId, IntPtr presenceResponseHandle)
762         {
763             int trigger;
764             IntPtr host, type;
765
766             int ret = Interop.IoTConnectivity.Client.PresenceResponse.GetHostAddress(presenceResponseHandle, out host);
767             if (ret != (int)IoTConnectivityError.None)
768             {
769                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get host address");
770                 return null;
771             }
772
773             ret = Interop.IoTConnectivity.Client.PresenceResponse.GetResourceType(presenceResponseHandle, out type);
774             if (ret != (int)IoTConnectivityError.None)
775             {
776                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource type");
777                 return null;
778             }
779
780             ret = Interop.IoTConnectivity.Client.PresenceResponse.GetTrigger(presenceResponseHandle, out trigger);
781             if (ret != (int)IoTConnectivityError.None)
782             {
783                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get event type");
784                 return null;
785             }
786
787             PresenceReceivedEventArgs e = new PresenceReceivedEventArgs()
788             {
789                 PresenceId = presenceId,
790                 HostAddress = (host != IntPtr.Zero) ? Marshal.PtrToStringAnsi(host) : string.Empty,
791                 Type = (type != IntPtr.Zero) ? Marshal.PtrToStringAnsi(type) : string.Empty,
792                 EventType = (PresenceEventType)trigger
793             };
794
795             return e;
796         }
797
798         private static DeviceInformationFoundEventArgs GetDeviceInformationFoundEventArgs(int requestId, IntPtr deviceInfoHandle)
799         {
800             IntPtr name, specVersion, deviceId, dataModelVersion;
801
802             int ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.Name, out name);
803             if (ret != (int)IoTConnectivityError.None)
804             {
805                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get name");
806                 return null;
807             }
808
809             ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.SpecVersion, out specVersion);
810             if (ret != (int)IoTConnectivityError.None)
811             {
812                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get spec version");
813                 return null;
814             }
815
816             ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.Id, out deviceId);
817             if (ret != (int)IoTConnectivityError.None)
818             {
819                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device id");
820                 return null;
821             }
822
823             ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.DataModelVersion, out dataModelVersion);
824             if (ret != (int)IoTConnectivityError.None)
825             {
826                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get data model version");
827                 return null;
828             }
829
830             DeviceInformationFoundEventArgs e = new DeviceInformationFoundEventArgs()
831             {
832                 RequestId = requestId,
833                 EventContinue = true,
834                 Name = (name != IntPtr.Zero) ? Marshal.PtrToStringAnsi(name) : string.Empty,
835                 SpecVersion = (specVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(specVersion) : string.Empty,
836                 DeviceId = (deviceId != IntPtr.Zero) ? Marshal.PtrToStringAnsi(deviceId) : string.Empty,
837                 DataModelVersion = (dataModelVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(dataModelVersion) : string.Empty
838             };
839
840             return e;
841         }
842
843         private static PlatformInformationFoundEventArgs GetPlatformInformationFoundEventArgs(int requestId, IntPtr platformInfoHandle)
844         {
845             IntPtr platformId, manufacturerName, manufacturerUrl, modelNumber, dateOfManufacture, platformVersion, osVersion, hardwareVersion, firmwareVersion, supportUrl, systemTime;
846
847             int ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.Id, out platformId);
848             if (ret != (int)IoTConnectivityError.None)
849             {
850                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get platform id");
851                 return null;
852             }
853
854             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.MfgName, out manufacturerName);
855             if (ret != (int)IoTConnectivityError.None)
856             {
857                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get manufacturer name");
858                 return null;
859             }
860
861             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.MfgUrl, out manufacturerUrl);
862             if (ret != (int)IoTConnectivityError.None)
863             {
864                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get manufacturer url");
865                 return null;
866             }
867
868             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.ModelNumber, out modelNumber);
869             if (ret != (int)IoTConnectivityError.None)
870             {
871                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get model number");
872                 return null;
873             }
874
875             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.DateOfMfg, out dateOfManufacture);
876             if (ret != (int)IoTConnectivityError.None)
877             {
878                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get date of manufacture");
879                 return null;
880             }
881
882             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.PlatformVer, out platformVersion);
883             if (ret != (int)IoTConnectivityError.None)
884             {
885                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get platform version");
886                 return null;
887             }
888
889             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.OsVer, out osVersion);
890             if (ret != (int)IoTConnectivityError.None)
891             {
892                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to os version");
893                 return null;
894             }
895
896             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.HardwareVer, out hardwareVersion);
897             if (ret != (int)IoTConnectivityError.None)
898             {
899                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to hardware version");
900                 return null;
901             }
902
903             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.FirmwareVer, out firmwareVersion);
904             if (ret != (int)IoTConnectivityError.None)
905             {
906                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get firmware version");
907                 return null;
908             }
909
910             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.SupportUrl, out supportUrl);
911             if (ret != (int)IoTConnectivityError.None)
912             {
913                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get support url");
914                 return null;
915             }
916
917             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.SystemTime, out systemTime);
918             if (ret != (int)IoTConnectivityError.None)
919             {
920                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get system time");
921                 return null;
922             }
923
924             PlatformInformationFoundEventArgs e = new PlatformInformationFoundEventArgs()
925             {
926                 RequestId = requestId,
927                 EventContinue = true,
928                 PlatformId = (platformId != IntPtr.Zero) ? Marshal.PtrToStringAnsi(platformId) : string.Empty,
929                 ManufacturerName = (manufacturerName != IntPtr.Zero) ? Marshal.PtrToStringAnsi(manufacturerName) : string.Empty,
930                 ManufacturerURL = (manufacturerUrl != IntPtr.Zero) ? Marshal.PtrToStringAnsi(manufacturerUrl) : string.Empty,
931                 DateOfManufacture = (dateOfManufacture != IntPtr.Zero) ? Marshal.PtrToStringAnsi(dateOfManufacture) : string.Empty,
932                 ModelNumber = (modelNumber != IntPtr.Zero) ? Marshal.PtrToStringAnsi(modelNumber) : string.Empty,
933                 PlatformVersion = (platformVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(platformVersion) : string.Empty,
934                 OsVersion = (osVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(osVersion) : string.Empty,
935                 HardwareVersion = (hardwareVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(hardwareVersion) : string.Empty,
936                 FirmwareVersion = (firmwareVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(firmwareVersion) : string.Empty,
937                 SupportUrl = (supportUrl != IntPtr.Zero) ? Marshal.PtrToStringAnsi(supportUrl) : string.Empty,
938                 SystemTime = (systemTime != IntPtr.Zero) ? Marshal.PtrToStringAnsi(systemTime) : string.Empty
939             };
940
941             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.RequestId is " + e.RequestId);
942             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.PlatformId is " + e.PlatformId);
943             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.ManufacturerName is " + e.ManufacturerName);
944             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.ManufacturerURL is " + e.ManufacturerURL);
945             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.DateOfManufacture is " + e.DateOfManufacture);
946             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.ModelNumber is " + e.ModelNumber);
947             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.PlatformVersion is " + e.PlatformVersion);
948             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.OsVersion is " + e.OsVersion);
949             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.HardwareVersion is " + e.HardwareVersion);
950             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.FirmwareVersion is " + e.FirmwareVersion);
951             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.SupportUrl is " + e.SupportUrl);
952             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.SystemTime is " + e.SystemTime);
953
954             return e;
955         }
956
957         private static FindingErrorOccurredEventArgs GetFindingErrorOccurredEventArgs(int requestId, int err)
958         {
959             FindingErrorOccurredEventArgs e = new FindingErrorOccurredEventArgs()
960             {
961                 RequestId = requestId,
962                 Error = IoTConnectivityErrorFactory.GetException(err)
963             };
964             return e;
965         }
966     }
967 }