Release 4.0.0-preview1-00052
[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()"/>
210         /// <seealso cref="SecureInitialize()"/>
211         /// <code>
212         /// IoTConnectivityClientManager.Deinitialize();
213         /// </code>
214         public static void Deinitialize()
215         {
216             s_presenceListenerId = 1;
217             s_presenceCallbacksMap.Clear();
218             s_presenceHandlesMap.Clear();
219
220             s_requestId = 1;
221             s_resourceFoundCallbacksMap.Clear();
222             s_deviceInformationCallbacksMap.Clear();
223             s_platformInformationCallbacksMap.Clear();
224
225             PresenceReceived = delegate{};
226             ResourceFound = delegate{};
227             PlatformInformationFound = delegate{};
228             DeviceInformationFound = delegate{};
229             FindingErrorOccurred = delegate{};
230
231             Interop.IoTConnectivity.Client.IoTCon.Deinitialize();
232         }
233
234         /// <summary>
235         /// Invokes a next message from a queue for receiving messages from others, immediately.
236         /// </summary>
237         /// <since_tizen> 3 </since_tizen>
238         /// <remarks>
239         /// This API invokes a next message from a queue for receiving messages from others, immediately.
240         /// After calling the API, it continues the polling with existing interval.
241         /// </remarks>
242         /// <feature>http://tizen.org/feature/iot.ocf</feature>
243         /// <pre>
244         /// Initialize() should be called to initialize.
245         /// </pre>
246         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
247         /// <code>
248         /// IoTConnectivityClientManager.InvokePolling();
249         /// </code>
250         public static void InvokePolling()
251         {
252             int ret = Interop.IoTConnectivity.Client.IoTCon.InvokePolling();
253             if (ret != (int)IoTConnectivityError.None)
254             {
255                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to invoke polling");
256                 throw IoTConnectivityErrorFactory.GetException(ret);
257             }
258         }
259
260         /// <summary>
261         /// Starts receiving presence events.
262         /// </summary>
263         /// <since_tizen> 3 </since_tizen>
264         /// <remarks>
265         /// Sends request to receive presence to an interested server's resource with resourceType.
266         /// If succeeded, <see cref="PresenceReceived"/> event handler will be triggered when the server sends presence.
267         /// A server sends presence events when adds / removes / alters a resource or start / stop presence.\n
268         /// @a hostAddress could be <see cref="MulticastAddress"/> for IPv4 multicast.
269         /// 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
270         /// of lowercase alphabetic, numeric, ".", or "-" characters, and contains no white space.
271         /// </remarks>
272         /// <privilege>
273         /// http://tizen.org/privilege/internet
274         /// </privilege>
275         /// <privlevel>public</privlevel>
276         /// <param name="hostAddress">The address or addressable name of the server.</param>
277         /// <param name="resourceType">A resource type that a client is interested in.</param>
278         /// <returns>PresenceId - An identifier for this request.</returns>
279         /// <feature>http://tizen.org/feature/iot.ocf</feature>
280         /// <pre>Initialize() should be called to initialize.</pre>
281         /// <post>
282         /// When the resource receive presence, <see cref="PresenceReceived"/> event handler will be invoked.\n
283         /// You must destroy presence by calling StopReceivingPresence() if presence event is no longer needed.
284         /// </post>
285         /// <seealso cref="IoTConnectivityServerManager.StartSendingPresence()"/>
286         /// <seealso cref="IoTConnectivityServerManager.StopSendingPresence()"/>
287         /// <seealso cref="StopReceivingPresence()"/>
288         /// <seealso cref="PresenceReceived"/>
289         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
290         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter.</exception>
291         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
292         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
293         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
294         /// <code>
295         /// EventHandler<PresenceReceivedEventArgs> handler = (sender, e) => {
296         ///     Console.Log("PresenceReceived, presence id :" + e.PresenceId);
297         /// }
298         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
299         ///     Console.Log("Found error :" + e.Error.Message);
300         /// }
301         /// IoTConnectivityClientManager.PresenceReceived += handler;
302         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
303         /// // Do not forget to remove these event handlers when they are not required any more.
304         /// int id = IoTConnectivityClientManager.StartReceivingPresence(IoTConnectivityClientManager.MulticastAddress, "oic.iot.door");
305         /// </code>
306         public static int StartReceivingPresence(string hostAddress, string resourceType)
307         {
308             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
309
310             if (resourceType != null && !ResourceTypes.IsValid(resourceType))
311             {
312                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Invalid type");
313                 throw new ArgumentException("Invalid type");
314             }
315
316             IntPtr id = IntPtr.Zero;
317             lock (s_presenceCallbacksMap)
318             {
319                 id = (IntPtr)s_presenceListenerId++;
320             }
321             s_presenceCallbacksMap[id] = (IntPtr presence, int result, IntPtr presenceResponseHandle, IntPtr userData) =>
322             {
323                 int presenceId = (int)userData;
324                 if (result == (int)IoTConnectivityError.None)
325                 {
326                     if (presenceResponseHandle != IntPtr.Zero)
327                     {
328                         PresenceReceivedEventArgs e = GetPresenceReceivedEventArgs(presenceId, presenceResponseHandle);
329                         if (e == null)
330                         {
331                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't get PresenceReceivedEventArgs");
332                             return;
333                         }
334                         PresenceReceived?.Invoke(null, e);
335                     }
336                     else
337                     {
338                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
339                         return;
340                     }
341                 }
342                 else
343                 {
344                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(presenceId, result);
345                     FindingErrorOccurred?.Invoke(null, e);
346                 }
347             };
348
349             IntPtr presenceHandle;
350             int errorCode = Interop.IoTConnectivity.Client.Presence.AddPresenceCb(hostAddress, (int)connectivityType, resourceType, s_presenceCallbacksMap[id], id, out presenceHandle);
351             if (errorCode != (int)IoTConnectivityError.None)
352             {
353                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register presence event handler");
354                 lock (s_presenceCallbacksMap)
355                 {
356                     s_presenceCallbacksMap.Remove(id);
357                 }
358                 throw IoTConnectivityErrorFactory.GetException(errorCode);
359             }
360
361             lock (s_presenceHandlesMap)
362             {
363                 s_presenceHandlesMap[id] = presenceHandle;
364             }
365             return (int)id;
366         }
367
368         /// <summary>
369         /// Stops receiving presence events.
370         /// </summary>
371         /// <since_tizen> 3 </since_tizen>
372         /// <remarks>
373         /// Sends request to not to receive server's presence any more.
374         /// </remarks>
375         /// <privilege>
376         /// http://tizen.org/privilege/internet
377         /// </privilege>
378         /// <privlevel>public</privlevel>
379         /// <param name="presenceId">The start presence request identifier.</param>
380         /// <feature>http://tizen.org/feature/iot.ocf</feature>
381         /// <pre>
382         /// Initialize() should be called to initialize.
383         /// </pre>
384         /// <seealso cref="IoTConnectivityServerManager.StartSendingPresence()"/>
385         /// <seealso cref="IoTConnectivityServerManager.StopSendingPresence()"/>
386         /// <seealso cref="StartReceivingPresence()"/>
387         /// <seealso cref="PresenceReceived"/>
388         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
389         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter.</exception>
390         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
391         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
392         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
393         /// <code>
394         /// EventHandler<PresenceReceivedEventArgs> handler = (sender, e) => {
395         ///     Console.Log("PresenceReceived, presence id :" + e.PresenceId);
396         /// }
397         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
398         ///     Console.Log("Found error :" + e.Error.Message);
399         /// }
400         /// IoTConnectivityClientManager.PresenceReceived += handler;
401         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
402         /// int id = IoTConnectivityClientManager.StartReceivingPresence(IoTConnectivityClientManager.MulticastAddress, "oic.iot.door");
403         /// await Task.Delay(5000); // Do other things here
404         /// // Call StopReceivingPresence() when receiving presence is not required any more
405         /// IoTConnectivityClientManager.PresenceReceived -= handler;
406         /// IoTConnectivityClientManager.FindingErrorOccurred -= errorHandler;
407         /// IoTConnectivityClientManager.StopReceivingPresence(id);
408         /// </code>
409         public static void StopReceivingPresence(int presenceId)
410         {
411             if (!s_presenceHandlesMap.ContainsKey((IntPtr)presenceId))
412             {
413                 Log.Error(IoTConnectivityErrorFactory.LogTag, "this presenceId does not exist");
414                 throw new ArgumentException("this presenceId does not exist");
415             }
416
417             if (s_presenceHandlesMap.ContainsKey((IntPtr)presenceId))
418             {
419                 IntPtr presenceHandle = s_presenceHandlesMap[(IntPtr)presenceId];
420                 int ret = Interop.IoTConnectivity.Client.Presence.RemovePresenceCb(presenceHandle);
421                 if (ret != (int)IoTConnectivityError.None)
422                 {
423                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to deregister presence event handler");
424                     throw IoTConnectivityErrorFactory.GetException(ret);
425                 }
426
427                 lock (s_presenceHandlesMap)
428                 {
429                     s_presenceHandlesMap.Remove((IntPtr)presenceId);
430                 }
431             }
432
433             if (s_presenceCallbacksMap.ContainsKey((IntPtr)presenceId))
434             {
435                 lock (s_presenceCallbacksMap)
436                 {
437                     s_presenceCallbacksMap.Remove((IntPtr)presenceId);
438                 }
439             }
440         }
441
442         /// <summary>
443         /// Starts finding resources.
444         /// </summary>
445         /// <since_tizen> 3 </since_tizen>
446         /// <remarks>
447         /// Sends request to find a resource of @a hostAddress server with @a resourceType.
448         /// If succeeded, <see cref="ResourceFound"/> event handler will be triggered with information of the resource.\n
449         /// @a hostAddress could be <see cref="MulticastAddress"/> for the IPv4 multicast.
450         /// 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
451         /// of lowercase alphabetic, numeric, ".", or "-" characters, and contains no white space.
452         /// </remarks>
453         /// <privilege>
454         /// http://tizen.org/privilege/internet
455         /// </privilege>
456         /// <privlevel>public</privlevel>
457         /// <param name="hostAddress">The address or addressable name of the server. The address includes a protocol like coaps://.</param>
458         /// <param name="query">The query specified as a filter for founding resources.</param>
459         /// <returns>RequestId - An identifier for this request.</returns>
460         /// <feature>http://tizen.org/feature/iot.ocf</feature>
461         /// <pre>Initialize() should be called to initialize.</pre>
462         /// <post>
463         /// When the resource is found, <see cref="ResourceFound"/> event handler will be invoked.
464         /// </post>
465         /// <seealso cref="ResourceFound"/>
466         /// <seealso cref="ResourceFoundEventArgs"/>
467         /// <seealso cref="TimeOut"/>
468         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
469         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
470         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
471         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
472         /// <code>
473         /// EventHandler<ResourceFoundEventArgs> handler = (sender, e) => {
474         ///     Console.Log("Found resource at host address :" + e.Resource.HostAddress + ", uri :" + e.Resource.UriPath);
475         /// }
476         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
477         ///     Console.Log("Found error :" + e.Error.Message);
478         /// }
479         /// IoTConnectivityClientManager.ResourceFound += handler;
480         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
481         /// ResourceQuery query = new ResourceQuery();
482         /// query.Type = "oic.iot.door";
483         /// // Do not forget to remove these event handlers when they are not required any more.
484         /// int id = IoTConnectivityClientManager.StartFindingResource(null, query);
485         /// </code>
486         public static int StartFindingResource(string hostAddress, ResourceQuery query = null)
487         {
488             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
489
490             IntPtr id = IntPtr.Zero;
491             lock (s_resourceFoundCallbacksMap)
492             {
493                 id = (IntPtr)s_requestId++;
494             }
495             s_resourceFoundCallbacksMap[id] = (IntPtr remoteResourceHandle, int result, IntPtr userData) =>
496             {
497                 if (ResourceFound == null)
498                     return false;
499
500                 int requestId = (int)userData;
501                 if (result == (int)IoTConnectivityError.None)
502                 {
503                     if (remoteResourceHandle != IntPtr.Zero)
504                     {
505                         RemoteResource resource = null;
506                         try
507                         {
508                             resource = new RemoteResource(remoteResourceHandle);
509                         }
510                         catch (Exception exp)
511                         {
512                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't clone RemoteResource's handle: " + exp.Message);
513                             return true;
514                         }
515                         ResourceFoundEventArgs e = new ResourceFoundEventArgs()
516                         {
517                             RequestId = requestId,
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                 PlatformId = (platformId != IntPtr.Zero) ? Marshal.PtrToStringAnsi(platformId) : string.Empty,
928                 ManufacturerName = (manufacturerName != IntPtr.Zero) ? Marshal.PtrToStringAnsi(manufacturerName) : string.Empty,
929                 ManufacturerURL = (manufacturerUrl != IntPtr.Zero) ? Marshal.PtrToStringAnsi(manufacturerUrl) : string.Empty,
930                 DateOfManufacture = (dateOfManufacture != IntPtr.Zero) ? Marshal.PtrToStringAnsi(dateOfManufacture) : string.Empty,
931                 ModelNumber = (modelNumber != IntPtr.Zero) ? Marshal.PtrToStringAnsi(modelNumber) : string.Empty,
932                 PlatformVersion = (platformVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(platformVersion) : string.Empty,
933                 OsVersion = (osVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(osVersion) : string.Empty,
934                 HardwareVersion = (hardwareVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(hardwareVersion) : string.Empty,
935                 FirmwareVersion = (firmwareVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(firmwareVersion) : string.Empty,
936                 SupportUrl = (supportUrl != IntPtr.Zero) ? Marshal.PtrToStringAnsi(supportUrl) : string.Empty,
937                 SystemTime = (systemTime != IntPtr.Zero) ? Marshal.PtrToStringAnsi(systemTime) : string.Empty
938             };
939
940             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.RequestId is " + e.RequestId);
941             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.PlatformId is " + e.PlatformId);
942             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.ManufacturerName is " + e.ManufacturerName);
943             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.ManufacturerURL is " + e.ManufacturerURL);
944             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.DateOfManufacture is " + e.DateOfManufacture);
945             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.ModelNumber is " + e.ModelNumber);
946             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.PlatformVersion is " + e.PlatformVersion);
947             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.OsVersion is " + e.OsVersion);
948             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.HardwareVersion is " + e.HardwareVersion);
949             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.FirmwareVersion is " + e.FirmwareVersion);
950             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.SupportUrl is " + e.SupportUrl);
951             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.SystemTime is " + e.SystemTime);
952
953             return e;
954         }
955
956         private static FindingErrorOccurredEventArgs GetFindingErrorOccurredEventArgs(int requestId, int err)
957         {
958             FindingErrorOccurredEventArgs e = new FindingErrorOccurredEventArgs()
959             {
960                 RequestId = requestId,
961                 Error = IoTConnectivityErrorFactory.GetException(err)
962             };
963             return e;
964         }
965     }
966 }