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