3d042e0fffd47394f855b11a0c1ca4628123d8c1
[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                             EventContinue = true,
519                             Resource = resource
520                         };
521                         ResourceFound?.Invoke(null, e);
522                         Log.Info(IoTConnectivityErrorFactory.LogTag, "e.EventContinue : " + e.EventContinue);
523                         return e.EventContinue;
524                     }
525                     else
526                     {
527                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
528                     }
529                 }
530                 else
531                 {
532                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(requestId, result);
533                     FindingErrorOccurred?.Invoke(null, e);
534
535                     lock (s_resourceFoundCallbacksMap)
536                     {
537                         s_resourceFoundCallbacksMap.Remove(id);
538                     }
539                 }
540                 return true;
541             };
542             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
543             int errorCode = Interop.IoTConnectivity.Client.ResourceFinder.AddResourceFoundCb(hostAddress, (int)connectivityType, queryHandle, s_resourceFoundCallbacksMap[id], id);
544             if (errorCode != (int)IoTConnectivityError.None)
545             {
546                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register resource found event handler");
547                 lock (s_resourceFoundCallbacksMap)
548                 {
549                     s_resourceFoundCallbacksMap.Remove(id);
550                 }
551                 throw IoTConnectivityErrorFactory.GetException(errorCode);
552             }
553             return (int)id;
554         }
555
556         /// <summary>
557         /// Starts finding the device information of remote server.
558         /// </summary>
559         /// <since_tizen> 3 </since_tizen>
560         /// <remarks>
561         /// Requests server for device information.
562         /// If succeeded, <see cref="DeviceInformationFound"/> event handler will be triggered with information of the device.\n
563         /// @a hostAddress could be <see cref="MulticastAddress"/> for the IPv4 multicast.
564         /// </remarks>
565         /// <privilege>
566         /// http://tizen.org/privilege/internet
567         /// </privilege>
568         /// <privlevel>public</privlevel>
569         /// <param name="hostAddress">The host address of the remote server.</param>
570         /// <param name="query">The query specified as a filter for founding resources.</param>
571         /// <returns>RequestId - An identifier for this request.</returns>
572         /// <feature>http://tizen.org/feature/iot.ocf</feature>
573         /// <pre>Initialize() should be called to initialize.</pre>
574         /// <post>
575         /// <see cref="DeviceInformationFound" /> event handler will be invoked.
576         /// </post>
577         /// <seealso cref="IoTConnectivityServerManager.SetDeviceName()"/>
578         /// <seealso cref="DeviceInformationFound"/>
579         /// <seealso cref="DeviceInformationFoundEventArgs"/>
580         /// <seealso cref="TimeOut"/>
581         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
582         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
583         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
584         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
585         /// <code>
586         /// EventHandler<DeviceInformationFoundEventArgs> handler = (sender, e) => {
587         ///     Console.Log("Device information found, id : " + e.RequestId + ", name : " + e.Name);
588         /// }
589         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
590         ///     Console.Log("Found error :" + e.Error.Message);
591         /// }
592         /// IoTConnectivityClientManager.DeviceInformationFound += handler;
593         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
594         /// // Do not forget to remove these event handlers when they are not required any more.
595         /// int id = IoTConnectivityClientManager.StartFindingDeviceInformation(IoTConnectivityClientManager.MulticastAddress);
596         /// </code>
597         public static int StartFindingDeviceInformation(string hostAddress, ResourceQuery query = null)
598         {
599             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
600
601             IntPtr id = IntPtr.Zero;
602             lock (s_deviceInformationCallbacksMap)
603             {
604                 id = (IntPtr)s_requestId++;
605             }
606             s_deviceInformationCallbacksMap[id] = (IntPtr deviceInfoHandle, int result, IntPtr userData) =>
607             {
608                 if (DeviceInformationFound == null)
609                     return false;
610
611                 int requestId = (int)userData;
612                 if (result == (int)IoTConnectivityError.None)
613                 {
614                     if (deviceInfoHandle != IntPtr.Zero)
615                     {
616                         DeviceInformationFoundEventArgs e = GetDeviceInformationFoundEventArgs(requestId, deviceInfoHandle);
617                         if (e == null)
618                         {
619                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't get DeviceInformationFoundEventArgs");
620                             return true;
621                         }
622                         DeviceInformationFound?.Invoke(null, e);
623                         Log.Info(IoTConnectivityErrorFactory.LogTag, "e.EventContinue : " + e.EventContinue);
624                         return e.EventContinue;
625                     }
626                     else
627                     {
628                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
629                     }
630                 }
631                 else
632                 {
633                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(requestId, result);
634                     FindingErrorOccurred?.Invoke(null, e);
635
636                     lock (s_deviceInformationCallbacksMap)
637                     {
638                         s_deviceInformationCallbacksMap.Remove(id);
639                     }
640                 }
641                 return true;
642             };
643
644             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
645             int errorCode = Interop.IoTConnectivity.Client.DeviceInformation.Find(hostAddress, (int)connectivityType, queryHandle, s_deviceInformationCallbacksMap[id], id);
646             if (errorCode != (int)IoTConnectivityError.None)
647             {
648                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device information");
649                 lock (s_deviceInformationCallbacksMap)
650                 {
651                     s_deviceInformationCallbacksMap.Remove(id);
652                 }
653                 throw IoTConnectivityErrorFactory.GetException(errorCode);
654             }
655
656             return (int)id;
657         }
658
659         /// <summary>
660         /// Starts finding the platform information of remote server.
661         /// </summary>
662         /// <since_tizen> 3 </since_tizen>
663         /// <remarks>
664         /// Requests server for platform information.
665         /// If succeeded, <see cref="PlatformInformationFound" /> event handler will be triggered with information of the platform.\n
666         /// @a hostAddress could be <see cref="MulticastAddress"/> for IPv4 multicast.
667         /// </remarks>
668         /// <privilege>
669         /// http://tizen.org/privilege/internet
670         /// </privilege>
671         /// <privlevel>public</privlevel>
672         /// <param name="hostAddress">The host address of remote server.</param>
673         /// <param name="query">The query specified as a filter for founding resources.</param>
674         /// <returns>RequestId - An identifier for this request.</returns>
675         /// <feature>http://tizen.org/feature/iot.ocf</feature>
676         /// <pre>Initialize() should be called to initialize.</pre>
677         /// <post>
678         /// <see cref="PlatformInformationFound" /> event handler will be invoked.
679         /// </post>
680         /// <seealso cref="PlatformInformationFound"/>
681         /// <seealso cref="PlatformInformationFoundEventArgs"/>
682         /// <seealso cref="TimeOut"/>
683         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported.</exception>
684         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid.</exception>
685         /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have privilege to access.</exception>
686         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory.</exception>
687         /// <code>
688         /// EventHandler<PlatformInformationFoundEventArgs> handler = (sender, e) => {
689         ///     Console.Log("PlatformInformationFound :" + e.RequestId);
690         /// }
691         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
692         ///     Console.Log("Found error :" + e.Error.Message);
693         /// }
694         /// IoTConnectivityClientManager.PlatformInformationFound += handler;
695         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
696         /// // Do not forget to remove these event handlers when they are not required any more.
697         /// int id = IoTConnectivityClientManager.StartFindingPlatformInformation(IoTConnectivityClientManager.MulticastAddress);
698         /// </code>
699         public static int StartFindingPlatformInformation(string hostAddress, ResourceQuery query = null)
700         {
701             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
702
703             IntPtr id = IntPtr.Zero;
704             lock (s_platformInformationCallbacksMap)
705             {
706                 id = (IntPtr)s_requestId++;
707             }
708             s_platformInformationCallbacksMap[id] = (IntPtr platformInfoHandle, int result, IntPtr userData) =>
709             {
710                 if (PlatformInformationFound == null)
711                     return false;
712
713                 int requestId = (int)userData;
714                 if (result == (int)IoTConnectivityError.None)
715                 {
716                     if (platformInfoHandle != IntPtr.Zero)
717                     {
718                         PlatformInformationFoundEventArgs e = GetPlatformInformationFoundEventArgs(requestId, platformInfoHandle);
719                         if (e == null)
720                         {
721                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't get PlatformInformationFoundEventArgs");
722                             return true;
723                         }
724                         PlatformInformationFound?.Invoke(null, e);
725                         Log.Info(IoTConnectivityErrorFactory.LogTag, "e.EventContinue : " + e.EventContinue);
726                         return e.EventContinue;
727                     }
728                     else
729                     {
730                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
731                     }
732                 }
733                 else
734                 {
735                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(requestId, result);
736                     FindingErrorOccurred?.Invoke(null, e);
737
738                     lock (s_platformInformationCallbacksMap)
739                     {
740                         s_platformInformationCallbacksMap.Remove(id);
741                     }
742                 }
743                 return true;
744             };
745
746             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
747             int errorCode = Interop.IoTConnectivity.Client.PlatformInformation.Find(hostAddress, (int)connectivityType, queryHandle, s_platformInformationCallbacksMap[id], id);
748             if (errorCode != (int)IoTConnectivityError.None)
749             {
750                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get platform information");
751                 lock (s_platformInformationCallbacksMap)
752                 {
753                     s_platformInformationCallbacksMap.Remove(id);
754                 }
755                 throw IoTConnectivityErrorFactory.GetException(errorCode);
756             }
757
758             return (int)id;
759         }
760
761         // Private methods
762         private static PresenceReceivedEventArgs GetPresenceReceivedEventArgs(int presenceId, IntPtr presenceResponseHandle)
763         {
764             int trigger;
765             IntPtr host, type;
766
767             int ret = Interop.IoTConnectivity.Client.PresenceResponse.GetHostAddress(presenceResponseHandle, out host);
768             if (ret != (int)IoTConnectivityError.None)
769             {
770                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get host address");
771                 return null;
772             }
773
774             ret = Interop.IoTConnectivity.Client.PresenceResponse.GetResourceType(presenceResponseHandle, out type);
775             if (ret != (int)IoTConnectivityError.None)
776             {
777                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource type");
778                 return null;
779             }
780
781             ret = Interop.IoTConnectivity.Client.PresenceResponse.GetTrigger(presenceResponseHandle, out trigger);
782             if (ret != (int)IoTConnectivityError.None)
783             {
784                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get event type");
785                 return null;
786             }
787
788             PresenceReceivedEventArgs e = new PresenceReceivedEventArgs()
789             {
790                 PresenceId = presenceId,
791                 HostAddress = (host != IntPtr.Zero) ? Marshal.PtrToStringAnsi(host) : string.Empty,
792                 Type = (type != IntPtr.Zero) ? Marshal.PtrToStringAnsi(type) : string.Empty,
793                 EventType = (PresenceEventType)trigger
794             };
795
796             return e;
797         }
798
799         private static DeviceInformationFoundEventArgs GetDeviceInformationFoundEventArgs(int requestId, IntPtr deviceInfoHandle)
800         {
801             IntPtr name, specVersion, deviceId, dataModelVersion;
802
803             int ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.Name, out name);
804             if (ret != (int)IoTConnectivityError.None)
805             {
806                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get name");
807                 return null;
808             }
809
810             ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.SpecVersion, out specVersion);
811             if (ret != (int)IoTConnectivityError.None)
812             {
813                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get spec version");
814                 return null;
815             }
816
817             ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.Id, out deviceId);
818             if (ret != (int)IoTConnectivityError.None)
819             {
820                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device id");
821                 return null;
822             }
823
824             ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.DataModelVersion, out dataModelVersion);
825             if (ret != (int)IoTConnectivityError.None)
826             {
827                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get data model version");
828                 return null;
829             }
830
831             DeviceInformationFoundEventArgs e = new DeviceInformationFoundEventArgs()
832             {
833                 RequestId = requestId,
834                 EventContinue = true,
835                 Name = (name != IntPtr.Zero) ? Marshal.PtrToStringAnsi(name) : string.Empty,
836                 SpecVersion = (specVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(specVersion) : string.Empty,
837                 DeviceId = (deviceId != IntPtr.Zero) ? Marshal.PtrToStringAnsi(deviceId) : string.Empty,
838                 DataModelVersion = (dataModelVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(dataModelVersion) : string.Empty
839             };
840
841             return e;
842         }
843
844         private static PlatformInformationFoundEventArgs GetPlatformInformationFoundEventArgs(int requestId, IntPtr platformInfoHandle)
845         {
846             IntPtr platformId, manufacturerName, manufacturerUrl, modelNumber, dateOfManufacture, platformVersion, osVersion, hardwareVersion, firmwareVersion, supportUrl, systemTime;
847
848             int ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.Id, out platformId);
849             if (ret != (int)IoTConnectivityError.None)
850             {
851                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get platform id");
852                 return null;
853             }
854
855             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.MfgName, out manufacturerName);
856             if (ret != (int)IoTConnectivityError.None)
857             {
858                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get manufacturer name");
859                 return null;
860             }
861
862             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.MfgUrl, out manufacturerUrl);
863             if (ret != (int)IoTConnectivityError.None)
864             {
865                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get manufacturer url");
866                 return null;
867             }
868
869             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.ModelNumber, out modelNumber);
870             if (ret != (int)IoTConnectivityError.None)
871             {
872                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get model number");
873                 return null;
874             }
875
876             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.DateOfMfg, out dateOfManufacture);
877             if (ret != (int)IoTConnectivityError.None)
878             {
879                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get date of manufacture");
880                 return null;
881             }
882
883             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.PlatformVer, out platformVersion);
884             if (ret != (int)IoTConnectivityError.None)
885             {
886                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get platform version");
887                 return null;
888             }
889
890             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.OsVer, out osVersion);
891             if (ret != (int)IoTConnectivityError.None)
892             {
893                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to os version");
894                 return null;
895             }
896
897             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.HardwareVer, out hardwareVersion);
898             if (ret != (int)IoTConnectivityError.None)
899             {
900                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to hardware version");
901                 return null;
902             }
903
904             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.FirmwareVer, out firmwareVersion);
905             if (ret != (int)IoTConnectivityError.None)
906             {
907                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get firmware version");
908                 return null;
909             }
910
911             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.SupportUrl, out supportUrl);
912             if (ret != (int)IoTConnectivityError.None)
913             {
914                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get support url");
915                 return null;
916             }
917
918             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.SystemTime, out systemTime);
919             if (ret != (int)IoTConnectivityError.None)
920             {
921                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get system time");
922                 return null;
923             }
924
925             PlatformInformationFoundEventArgs e = new PlatformInformationFoundEventArgs()
926             {
927                 RequestId = requestId,
928                 EventContinue = true,
929                 PlatformId = (platformId != IntPtr.Zero) ? Marshal.PtrToStringAnsi(platformId) : string.Empty,
930                 ManufacturerName = (manufacturerName != IntPtr.Zero) ? Marshal.PtrToStringAnsi(manufacturerName) : string.Empty,
931                 ManufacturerURL = (manufacturerUrl != IntPtr.Zero) ? Marshal.PtrToStringAnsi(manufacturerUrl) : string.Empty,
932                 DateOfManufacture = (dateOfManufacture != IntPtr.Zero) ? Marshal.PtrToStringAnsi(dateOfManufacture) : string.Empty,
933                 ModelNumber = (modelNumber != IntPtr.Zero) ? Marshal.PtrToStringAnsi(modelNumber) : string.Empty,
934                 PlatformVersion = (platformVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(platformVersion) : string.Empty,
935                 OsVersion = (osVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(osVersion) : string.Empty,
936                 HardwareVersion = (hardwareVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(hardwareVersion) : string.Empty,
937                 FirmwareVersion = (firmwareVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(firmwareVersion) : string.Empty,
938                 SupportUrl = (supportUrl != IntPtr.Zero) ? Marshal.PtrToStringAnsi(supportUrl) : string.Empty,
939                 SystemTime = (systemTime != IntPtr.Zero) ? Marshal.PtrToStringAnsi(systemTime) : string.Empty
940             };
941
942             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.RequestId is " + e.RequestId);
943             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.PlatformId is " + e.PlatformId);
944             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.ManufacturerName is " + e.ManufacturerName);
945             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.ManufacturerURL is " + e.ManufacturerURL);
946             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.DateOfManufacture is " + e.DateOfManufacture);
947             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.ModelNumber is " + e.ModelNumber);
948             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.PlatformVersion is " + e.PlatformVersion);
949             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.OsVersion is " + e.OsVersion);
950             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.HardwareVersion is " + e.HardwareVersion);
951             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.FirmwareVersion is " + e.FirmwareVersion);
952             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.SupportUrl is " + e.SupportUrl);
953             Log.Info(IoTConnectivityErrorFactory.LogTag, "e.SystemTime is " + e.SystemTime);
954
955             return e;
956         }
957
958         private static FindingErrorOccurredEventArgs GetFindingErrorOccurredEventArgs(int requestId, int err)
959         {
960             FindingErrorOccurredEventArgs e = new FindingErrorOccurredEventArgs()
961             {
962                 RequestId = requestId,
963                 Error = IoTConnectivityErrorFactory.GetException(err)
964             };
965             return e;
966         }
967     }
968 }