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