95d42c7c983cde1877824ec94446f7956ed86cd5
[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         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
170         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
171         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
172         /// <code>
173         /// string filePath = "../../res/iotcon-test-svr-db-client.dat";
174         /// IoTConnectivityClientManager.Initialize(filePath);
175         /// </code>
176         public static void Initialize(string filePath)
177         {
178             int ret = Interop.IoTConnectivity.Client.IoTCon.Initialize(filePath);
179             if (ret != (int)IoTConnectivityError.None)
180             {
181                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to initialize");
182                 throw IoTConnectivityErrorFactory.GetException(ret);
183             }
184         }
185
186         /// <summary>
187         /// Deinitializes IoTCon.
188         /// </summary>
189         /// <remarks>
190         /// This API must be called if IoTCon API is no longer needed.
191         /// </remarks>
192         /// <pre>
193         /// Initialize() should be called to initialize.
194         /// </pre>
195         /// <seealso cref="Initialize()"/>
196         /// <seealso cref="SecureInitialize()"/>
197         /// <code>
198         /// IoTConnectivityClientManager.Deinitialize();
199         /// </code>
200         public static void Deinitialize()
201         {
202             s_presenceListenerId = 1;
203             s_presenceCallbacksMap.Clear();
204             s_presenceHandlesMap.Clear();
205
206             s_requestId = 1;
207             s_resourceFoundCallbacksMap.Clear();
208             s_deviceInformationCallbacksMap.Clear();
209             s_platformInformationCallbacksMap.Clear();
210
211             PresenceReceived = delegate{};
212             ResourceFound = delegate{};
213             PlatformInformationFound = delegate{};
214             DeviceInformationFound = delegate{};
215             FindingErrorOccurred = delegate{};
216
217             Interop.IoTConnectivity.Client.IoTCon.Deinitialize();
218         }
219
220         /// <summary>
221         /// Invokes a next message from a queue for receiving messages from others, immediately.
222         /// </summary>
223         /// <remarks>
224         /// This API invokes a next message from a queue for receiving messages from others, immediately.
225         /// After calling the API, it continues the polling with existing interval.
226         /// </remarks>
227         /// <pre>
228         /// Initialize() should be called to initialize.
229         /// </pre>
230         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
231         /// <code>
232         /// IoTConnectivityClientManager.InvokePolling();
233         /// </code>
234         public static void InvokePolling()
235         {
236             int ret = Interop.IoTConnectivity.Client.IoTCon.InvokePolling();
237             if (ret != (int)IoTConnectivityError.None)
238             {
239                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to invoke polling");
240                 throw IoTConnectivityErrorFactory.GetException(ret);
241             }
242         }
243
244         /// <summary>
245         /// Starts receiving presence events
246         /// </summary>
247         /// <remarks>
248         /// Sends request to receive presence to an interested server's resource with resourceType.
249         /// If succeeded, <see cref="PresenceReceived"/> event handler will be triggered when the server sends presence.
250         /// A server sends presence events when adds / removes / alters a resource or start / stop presence.\n
251         /// @a hostAddress could be <see cref="MulticastAddress"/> for IPv4 multicast.
252         /// 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
253         /// of lowercase alphabetic, numeric, ".", or "-" characters, and contains no white space.
254         /// </remarks>
255         /// <privilege>
256         /// http://tizen.org/privilege/internet
257         /// </privilege>
258         /// <param name="hostAddress">The address or addressable name of the server</param>
259         /// <param name="resourceType">A resource type that a client is interested in</param>
260         /// <returns>PresenceId - An identifier for this request</returns>
261         /// <pre>Initialize() should be called to initialize.</pre>
262         /// <post>
263         /// When the resource receive presence, <see cref="PresenceReceived"/> event handler will be invoked.\n
264         /// You must destroy presence by calling StopReceivingPresence() if presence event is no longer needed.
265         /// </post>
266         /// <seealso cref="IoTConnectivityServerManager.StartSendingPresence()"/>
267         /// <seealso cref="IoTConnectivityServerManager.StopSendingPresence()"/>
268         /// <seealso cref="StopReceivingPresence()"/>
269         /// <seealso cref="PresenceReceived"/>
270         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
271         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
272         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
273         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
274         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
275         /// <code>
276         /// EventHandler<PresenceReceivedEventArgs> handler = (sender, e) => {
277         ///     Console.Log("PresenceReceived, presence id :" + e.PresenceId);
278         /// }
279         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
280         ///     Console.Log("Found error :" + e.Error.Message);
281         /// }
282         /// IoTConnectivityClientManager.PresenceReceived += handler;
283         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
284         /// // Do not forget to remove these event handlers when they are not required any more.
285         /// int id = IoTConnectivityClientManager.StartReceivingPresence(IoTConnectivityClientManager.MulticastAddress, "oic.iot.door");
286         /// </code>
287         public static int StartReceivingPresence(string hostAddress, string resourceType)
288         {
289             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
290
291             if (resourceType != null && !ResourceTypes.IsValid(resourceType))
292             {
293                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Invalid type");
294                 throw new ArgumentException("Invalid type");
295             }
296
297             IntPtr id = IntPtr.Zero;
298             lock (s_presenceCallbacksMap)
299             {
300                 id = (IntPtr)s_presenceListenerId++;
301             }
302             s_presenceCallbacksMap[id] = (IntPtr presence, int result, IntPtr presenceResponseHandle, IntPtr userData) =>
303             {
304                 int presenceId = (int)userData;
305                 if (result == (int)IoTConnectivityError.None)
306                 {
307                     if (presenceResponseHandle != IntPtr.Zero)
308                     {
309                         PresenceReceivedEventArgs e = GetPresenceReceivedEventArgs(presenceId, presenceResponseHandle);
310                         if (e == null)
311                         {
312                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't get PresenceReceivedEventArgs");
313                             return;
314                         }
315                         PresenceReceived?.Invoke(null, e);
316                     }
317                     else
318                     {
319                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
320                         return;
321                     }
322                 }
323                 else
324                 {
325                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(presenceId, result);
326                     FindingErrorOccurred?.Invoke(null, e);
327                 }
328             };
329
330             IntPtr presenceHandle;
331             int errorCode = Interop.IoTConnectivity.Client.Presence.AddPresenceCb(hostAddress, (int)connectivityType, resourceType, s_presenceCallbacksMap[id], id, out presenceHandle);
332             if (errorCode != (int)IoTConnectivityError.None)
333             {
334                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register presence event handler");
335                 lock (s_presenceCallbacksMap)
336                 {
337                     s_presenceCallbacksMap.Remove(id);
338                 }
339                 throw IoTConnectivityErrorFactory.GetException(errorCode);
340             }
341
342             lock (s_presenceHandlesMap)
343             {
344                 s_presenceHandlesMap[id] = presenceHandle;
345             }
346             return (int)id;
347         }
348
349         /// <summary>
350         /// Stops receiving presence events
351         /// </summary>
352         /// <remarks>
353         /// Sends request to not to receive server's presence any more.
354         /// </remarks>
355         /// <privilege>
356         /// http://tizen.org/privilege/internet
357         /// </privilege>
358         /// <param name="presenceId">The start presence request identifier</param>
359         /// <pre>
360         /// Initialize() should be called to initialize.
361         /// </pre>
362         /// <seealso cref="IoTConnectivityServerManager.StartSendingPresence()"/>
363         /// <seealso cref="IoTConnectivityServerManager.StopSendingPresence()"/>
364         /// <seealso cref="StartReceivingPresence()"/>
365         /// <seealso cref="PresenceReceived"/>
366         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
367         /// <exception cref="ArgumentException">Thrown when there is an invalid parameter</exception>
368         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
369         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
370         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
371         /// <code>
372         /// EventHandler<PresenceReceivedEventArgs> handler = (sender, e) => {
373         ///     Console.Log("PresenceReceived, presence id :" + e.PresenceId);
374         /// }
375         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
376         ///     Console.Log("Found error :" + e.Error.Message);
377         /// }
378         /// IoTConnectivityClientManager.PresenceReceived += handler;
379         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
380         /// int id = IoTConnectivityClientManager.StartReceivingPresence(IoTConnectivityClientManager.MulticastAddress, "oic.iot.door");
381         /// await Task.Delay(5000); // Do other things here
382         /// // Call StopReceivingPresence() when receiving presence is not required any more
383         /// IoTConnectivityClientManager.PresenceReceived -= handler;
384         /// IoTConnectivityClientManager.FindingErrorOccurred -= errorHandler;
385         /// IoTConnectivityClientManager.StopReceivingPresence(id);
386         /// </code>
387         public static void StopReceivingPresence(int presenceId)
388         {
389             if (!s_presenceHandlesMap.ContainsKey((IntPtr)presenceId))
390             {
391                 Log.Error(IoTConnectivityErrorFactory.LogTag, "this presenceId does not exist");
392                 throw new ArgumentException("this presenceId does not exist");
393             }
394
395             if (s_presenceHandlesMap.ContainsKey((IntPtr)presenceId))
396             {
397                 IntPtr presenceHandle = s_presenceHandlesMap[(IntPtr)presenceId];
398                 int ret = Interop.IoTConnectivity.Client.Presence.RemovePresenceCb(presenceHandle);
399                 if (ret != (int)IoTConnectivityError.None)
400                 {
401                     Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to deregister presence event handler");
402                     throw IoTConnectivityErrorFactory.GetException(ret);
403                 }
404
405                 lock (s_presenceHandlesMap)
406                 {
407                     s_presenceHandlesMap.Remove((IntPtr)presenceId);
408                 }
409             }
410
411             if (s_presenceCallbacksMap.ContainsKey((IntPtr)presenceId))
412             {
413                 lock (s_presenceCallbacksMap)
414                 {
415                     s_presenceCallbacksMap.Remove((IntPtr)presenceId);
416                 }
417             }
418         }
419
420         /// <summary>
421         /// Starts finding resources.
422         /// </summary>
423         /// <remarks>
424         /// Sends request to find a resource of @a hostAddress server with @a resourceType.
425         /// If succeeded, <see cref="ResourceFound"/> event handler will be triggered with information of the resource.\n
426         /// @a hostAddress could be <see cref="MulticastAddress"/> for IPv4 multicast.
427         /// 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
428         /// of lowercase alphabetic, numeric, ".", or "-" characters, and contains no white space.
429         /// </remarks>
430         /// <privilege>
431         /// http://tizen.org/privilege/internet
432         /// </privilege>
433         /// <param name="hostAddress">The address or addressable name of the server. The address includes a protocol like coaps://</param>
434         /// <param name="query">The query specified as a filter for founding resources</param>
435         /// <returns>RequestId - An identifier for this request</returns>
436         /// <pre>Initialize() should be called to initialize.</pre>
437         /// <post>
438         /// When the resource is found, <see cref="ResourceFound"/> event handler will be invoked.
439         /// </post>
440         /// <seealso cref="ResourceFound"/>
441         /// <seealso cref="ResourceFoundEventArgs"/>
442         /// <seealso cref="TimeOut"/>
443         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
444         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
445         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
446         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
447         /// <code>
448         /// EventHandler<ResourceFoundEventArgs> handler = (sender, e) => {
449         ///     Console.Log("Found resource at host address :" + e.Resource.HostAddress + ", uri :" + e.Resource.UriPath);
450         /// }
451         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
452         ///     Console.Log("Found error :" + e.Error.Message);
453         /// }
454         /// IoTConnectivityClientManager.ResourceFound += handler;
455         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
456         /// ResourceQuery query = new ResourceQuery();
457         /// query.Type = "oic.iot.door";
458         /// // Do not forget to remove these event handlers when they are not required any more.
459         /// int id = IoTConnectivityClientManager.StartFindingResource(null, query);
460         /// </code>
461         public static int StartFindingResource(string hostAddress, ResourceQuery query = null)
462         {
463             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
464
465             IntPtr id = IntPtr.Zero;
466             lock (s_resourceFoundCallbacksMap)
467             {
468                 id = (IntPtr)s_requestId++;
469             }
470             s_resourceFoundCallbacksMap[id] = (IntPtr remoteResourceHandle, int result, IntPtr userData) =>
471             {
472                 if (ResourceFound == null)
473                     return false;
474
475                 int requestId = (int)userData;
476                 if (result == (int)IoTConnectivityError.None)
477                 {
478                     if (remoteResourceHandle != IntPtr.Zero)
479                     {
480                         RemoteResource resource = null;
481                         try
482                         {
483                             resource = new RemoteResource(remoteResourceHandle);
484                         }
485                         catch (Exception exp)
486                         {
487                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't clone RemoteResource's handle: " + exp.Message);
488                             return true;
489                         }
490                         ResourceFoundEventArgs e = new ResourceFoundEventArgs()
491                         {
492                             RequestId = requestId,
493                             Resource = resource
494                         };
495                         ResourceFound?.Invoke(null, e);
496                         Log.Info(IoTConnectivityErrorFactory.LogTag, "e.EventContinue : " + e.EventContinue);
497                         return e.EventContinue;
498                     }
499                     else
500                     {
501                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
502                     }
503                 }
504                 else
505                 {
506                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(requestId, result);
507                     FindingErrorOccurred?.Invoke(null, e);
508
509                     lock (s_resourceFoundCallbacksMap)
510                     {
511                         s_resourceFoundCallbacksMap.Remove(id);
512                     }
513                 }
514                 return true;
515             };
516             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
517             int errorCode = Interop.IoTConnectivity.Client.ResourceFinder.AddResourceFoundCb(hostAddress, (int)connectivityType, queryHandle, s_resourceFoundCallbacksMap[id], id);
518             if (errorCode != (int)IoTConnectivityError.None)
519             {
520                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register resource found event handler");
521                 lock (s_resourceFoundCallbacksMap)
522                 {
523                     s_resourceFoundCallbacksMap.Remove(id);
524                 }
525                 throw IoTConnectivityErrorFactory.GetException(errorCode);
526             }
527             return (int)id;
528         }
529
530         /// <summary>
531         /// Starts finding the device information of remote server.
532         /// </summary>
533         /// <remarks>
534         /// Requests server for device information.
535         /// If succeeded, <see cref="DeviceInformationFound"/> event handler will be triggered with information of the device.\n
536         /// @a hostAddress could be <see cref="MulticastAddress"/> for IPv4 multicast.
537         /// </remarks>
538         /// <privilege>
539         /// http://tizen.org/privilege/internet
540         /// </privilege>
541         /// <param name="hostAddress">The host address of remote server</param>
542         /// <param name="query">The query specified as a filter for founding resources</param>
543         /// <returns>RequestId - An identifier for this request</returns>
544         /// <pre>Initialize() should be called to initialize.</pre>
545         /// <post>
546         /// <see cref="DeviceInformationFound" /> event handler will be invoked.
547         /// </post>
548         /// <seealso cref="IoTConnectivityServerManager.SetDeviceName()"/>
549         /// <seealso cref="DeviceInformationFound"/>
550         /// <seealso cref="DeviceInformationFoundEventArgs"/>
551         /// <seealso cref="TimeOut"/>
552         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
553         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
554         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
555         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
556         /// <code>
557         /// EventHandler<DeviceInformationFoundEventArgs> handler = (sender, e) => {
558         ///     Console.Log("Device information found, id : " + e.RequestId + ", name : " + e.Name);
559         /// }
560         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
561         ///     Console.Log("Found error :" + e.Error.Message);
562         /// }
563         /// IoTConnectivityClientManager.DeviceInformationFound += handler;
564         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
565         /// // Do not forget to remove these event handlers when they are not required any more.
566         /// int id = IoTConnectivityClientManager.StartFindingDeviceInformation(IoTConnectivityClientManager.MulticastAddress);
567         /// </code>
568         public static int StartFindingDeviceInformation(string hostAddress, ResourceQuery query = null)
569         {
570             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
571
572             IntPtr id = IntPtr.Zero;
573             lock (s_deviceInformationCallbacksMap)
574             {
575                 id = (IntPtr)s_requestId++;
576             }
577             s_deviceInformationCallbacksMap[id] = (IntPtr deviceInfoHandle, int result, IntPtr userData) =>
578             {
579                 if (DeviceInformationFound == null)
580                     return false;
581
582                 int requestId = (int)userData;
583                 if (result == (int)IoTConnectivityError.None)
584                 {
585                     if (deviceInfoHandle != IntPtr.Zero)
586                     {
587                         DeviceInformationFoundEventArgs e = GetDeviceInformationFoundEventArgs(requestId, deviceInfoHandle);
588                         if (e == null)
589                         {
590                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't get DeviceInformationFoundEventArgs");
591                             return true;
592                         }
593                         DeviceInformationFound?.Invoke(null, e);
594                         Log.Info(IoTConnectivityErrorFactory.LogTag, "e.EventContinue : " + e.EventContinue);
595                         return e.EventContinue;
596                     }
597                     else
598                     {
599                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
600                     }
601                 }
602                 else
603                 {
604                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(requestId, result);
605                     FindingErrorOccurred?.Invoke(null, e);
606
607                     lock (s_deviceInformationCallbacksMap)
608                     {
609                         s_deviceInformationCallbacksMap.Remove(id);
610                     }
611                 }
612                 return true;
613             };
614
615             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
616             int errorCode = Interop.IoTConnectivity.Client.DeviceInformation.Find(hostAddress, (int)connectivityType, queryHandle, s_deviceInformationCallbacksMap[id], id);
617             if (errorCode != (int)IoTConnectivityError.None)
618             {
619                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device information");
620                 lock (s_deviceInformationCallbacksMap)
621                 {
622                     s_deviceInformationCallbacksMap.Remove(id);
623                 }
624                 throw IoTConnectivityErrorFactory.GetException(errorCode);
625             }
626
627             return (int)id;
628         }
629
630         /// <summary>
631         /// Starts finding the platform information of remote server.
632         /// </summary>
633         /// <remarks>
634         /// Requests server for platform information.
635         /// If succeeded, <see cref="PlatformInformationFound" /> event handler will be triggered with information of the platform.\n
636         /// @a hostAddress could be <see cref="MulticastAddress"/> for IPv4 multicast.
637         /// </remarks>
638         /// <privilege>
639         /// http://tizen.org/privilege/internet
640         /// </privilege>
641         /// <param name="hostAddress">The host address of remote server</param>
642         /// <param name="query">The query specified as a filter for founding resources</param>
643         /// <returns>RequestId - An identifier for this request</returns>
644         /// <pre>Initialize() should be called to initialize.</pre>
645         /// <post>
646         /// <see cref="PlatformInformationFound" /> event handler will be invoked.
647         /// </post>
648         /// <seealso cref="PlatformInformationFound"/>
649         /// <seealso cref="PlatformInformationFoundEventArgs"/>
650         /// <seealso cref="TimeOut"/>
651         /// <exception cref="NotSupportedException">Thrown when the iotcon is not supported</exception>
652         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid</exception>
653         /// <exception cref="UnauthorizedAccessException">Thrown when app does not have privilege to access</exception>
654         /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory</exception>
655         /// <code>
656         /// EventHandler<PlatformInformationFoundEventArgs> handler = (sender, e) => {
657         ///     Console.Log("PlatformInformationFound :" + e.RequestId);
658         /// }
659         /// EventHandler<FindingErrorOccurredEventArgs> errorHandler = (sender, e) => {
660         ///     Console.Log("Found error :" + e.Error.Message);
661         /// }
662         /// IoTConnectivityClientManager.PlatformInformationFound += handler;
663         /// IoTConnectivityClientManager.FindingErrorOccurred += errorHandler;
664         /// // Do not forget to remove these event handlers when they are not required any more.
665         /// int id = IoTConnectivityClientManager.StartFindingPlatformInformation(IoTConnectivityClientManager.MulticastAddress);
666         /// </code>
667         public static int StartFindingPlatformInformation(string hostAddress, ResourceQuery query = null)
668         {
669             Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ip;
670
671             IntPtr id = IntPtr.Zero;
672             lock (s_platformInformationCallbacksMap)
673             {
674                 id = (IntPtr)s_requestId++;
675             }
676             s_platformInformationCallbacksMap[id] = (IntPtr platformInfoHandle, int result, IntPtr userData) =>
677             {
678                 if (PlatformInformationFound == null)
679                     return false;
680
681                 int requestId = (int)userData;
682                 if (result == (int)IoTConnectivityError.None)
683                 {
684                     if (platformInfoHandle != IntPtr.Zero)
685                     {
686                         PlatformInformationFoundEventArgs e = GetPlatformInformationFoundEventArgs(requestId, platformInfoHandle);
687                         if (e == null)
688                         {
689                             Log.Error(IoTConnectivityErrorFactory.LogTag, "Can't get PlatformInformationFoundEventArgs");
690                             return true; ;
691                         }
692                         PlatformInformationFound?.Invoke(null, e);
693                         Log.Info(IoTConnectivityErrorFactory.LogTag, "e.EventContinue : " + e.EventContinue);
694                         return e.EventContinue;
695                     }
696                     else
697                     {
698                         Log.Error(IoTConnectivityErrorFactory.LogTag, "Handle is null");
699                     }
700                 }
701                 else
702                 {
703                     FindingErrorOccurredEventArgs e = GetFindingErrorOccurredEventArgs(requestId, result);
704                     FindingErrorOccurred?.Invoke(null, e);
705
706                     lock (s_platformInformationCallbacksMap)
707                     {
708                         s_platformInformationCallbacksMap.Remove(id);
709                     }
710                 }
711                 return true;
712             };
713
714             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
715             int errorCode = Interop.IoTConnectivity.Client.PlatformInformation.Find(hostAddress, (int)connectivityType, queryHandle, s_platformInformationCallbacksMap[id], id);
716             if (errorCode != (int)IoTConnectivityError.None)
717             {
718                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get platform information");
719                 lock (s_platformInformationCallbacksMap)
720                 {
721                     s_platformInformationCallbacksMap.Remove(id);
722                 }
723                 throw IoTConnectivityErrorFactory.GetException(errorCode);
724             }
725
726             return (int)id;
727         }
728
729         // Private methods
730         private static PresenceReceivedEventArgs GetPresenceReceivedEventArgs(int presenceId, IntPtr presenceResponseHandle)
731         {
732             int trigger;
733             IntPtr host, type;
734
735             int ret = Interop.IoTConnectivity.Client.PresenceResponse.GetHostAddress(presenceResponseHandle, out host);
736             if (ret != (int)IoTConnectivityError.None)
737             {
738                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get host address");
739                 return null;
740             }
741
742             ret = Interop.IoTConnectivity.Client.PresenceResponse.GetResourceType(presenceResponseHandle, out type);
743             if (ret != (int)IoTConnectivityError.None)
744             {
745                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource type");
746                 return null;
747             }
748
749             ret = Interop.IoTConnectivity.Client.PresenceResponse.GetTrigger(presenceResponseHandle, out trigger);
750             if (ret != (int)IoTConnectivityError.None)
751             {
752                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get event type");
753                 return null;
754             }
755
756             PresenceReceivedEventArgs e = new PresenceReceivedEventArgs()
757             {
758                 PresenceId = presenceId,
759                 HostAddress = (host != IntPtr.Zero) ? Marshal.PtrToStringAnsi(host) : string.Empty,
760                 Type = (type != IntPtr.Zero) ? Marshal.PtrToStringAnsi(type) : string.Empty,
761                 EventType = (PresenceEventType)trigger
762             };
763
764             return e;
765         }
766
767         private static DeviceInformationFoundEventArgs GetDeviceInformationFoundEventArgs(int requestId, IntPtr deviceInfoHandle)
768         {
769             IntPtr name, specVersion, deviceId, dataModelVersion;
770
771             int ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.Name, out name);
772             if (ret != (int)IoTConnectivityError.None)
773             {
774                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get name");
775                 return null;
776             }
777
778             ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.SpecVersion, out specVersion);
779             if (ret != (int)IoTConnectivityError.None)
780             {
781                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get spec version");
782                 return null;
783             }
784
785             ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.Id, out deviceId);
786             if (ret != (int)IoTConnectivityError.None)
787             {
788                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device id");
789                 return null;
790             }
791
792             ret = Interop.IoTConnectivity.Client.DeviceInformation.GetProperty(deviceInfoHandle, (int)Interop.IoTConnectivity.Client.DeviceInformation.Property.DataModelVersion, out dataModelVersion);
793             if (ret != (int)IoTConnectivityError.None)
794             {
795                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get data model version");
796                 return null;
797             }
798
799             DeviceInformationFoundEventArgs e = new DeviceInformationFoundEventArgs()
800             {
801                 RequestId = requestId,
802                 EventContinue = true,
803                 Name = (name != IntPtr.Zero) ? Marshal.PtrToStringAnsi(name) : string.Empty,
804                 SpecVersion = (specVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(specVersion) : string.Empty,
805                 DeviceId = (deviceId != IntPtr.Zero) ? Marshal.PtrToStringAnsi(deviceId) : string.Empty,
806                 DataModelVersion = (dataModelVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(dataModelVersion) : string.Empty
807             };
808
809             return e;
810         }
811
812         private static PlatformInformationFoundEventArgs GetPlatformInformationFoundEventArgs(int requestId, IntPtr platformInfoHandle)
813         {
814             IntPtr platformId, manufacturerName, manufacturerUrl, modelNumber, dateOfManufacture, platformVersion, osVersion, hardwareVersion, firmwareVersion, supportUrl, systemTime;
815
816             int ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.Id, out platformId);
817             if (ret != (int)IoTConnectivityError.None)
818             {
819                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get platform id");
820                 return null;
821             }
822
823             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.MfgName, out manufacturerName);
824             if (ret != (int)IoTConnectivityError.None)
825             {
826                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get manufacturer name");
827                 return null;
828             }
829
830             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.MfgUrl, out manufacturerUrl);
831             if (ret != (int)IoTConnectivityError.None)
832             {
833                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get manufacturer url");
834                 return null;
835             }
836
837             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.ModelNumber, out modelNumber);
838             if (ret != (int)IoTConnectivityError.None)
839             {
840                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get model number");
841                 return null;
842             }
843
844             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.DateOfMfg, out dateOfManufacture);
845             if (ret != (int)IoTConnectivityError.None)
846             {
847                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get date of manufacture");
848                 return null;
849             }
850
851             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.PlatformVer, out platformVersion);
852             if (ret != (int)IoTConnectivityError.None)
853             {
854                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get platform version");
855                 return null;
856             }
857
858             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.OsVer, out osVersion);
859             if (ret != (int)IoTConnectivityError.None)
860             {
861                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to os version");
862                 return null;
863             }
864
865             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.HardwareVer, out hardwareVersion);
866             if (ret != (int)IoTConnectivityError.None)
867             {
868                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to hardware version");
869                 return null;
870             }
871
872             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.FirmwareVer, out firmwareVersion);
873             if (ret != (int)IoTConnectivityError.None)
874             {
875                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get firmware version");
876                 return null;
877             }
878
879             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.SupportUrl, out supportUrl);
880             if (ret != (int)IoTConnectivityError.None)
881             {
882                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get support url");
883                 return null;
884             }
885
886             ret = Interop.IoTConnectivity.Client.PlatformInformation.GetProperty(platformInfoHandle, (int)Interop.IoTConnectivity.Client.PlatformInformation.Propery.SystemTime, out systemTime);
887             if (ret != (int)IoTConnectivityError.None)
888             {
889                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get system time");
890                 return null;
891             }
892
893             PlatformInformationFoundEventArgs e = new PlatformInformationFoundEventArgs()
894             {
895                 RequestId = requestId,
896                 PlatformId = (platformId != IntPtr.Zero) ? Marshal.PtrToStringAnsi(platformId) : string.Empty,
897                 ManufacturerName = (manufacturerName != IntPtr.Zero) ? Marshal.PtrToStringAnsi(manufacturerName) : string.Empty,
898                 ManufacturerURL = (manufacturerUrl != IntPtr.Zero) ? Marshal.PtrToStringAnsi(manufacturerUrl) : string.Empty,
899                 DateOfManufacture = (dateOfManufacture != IntPtr.Zero) ? Marshal.PtrToStringAnsi(dateOfManufacture) : string.Empty,
900                 ModelNumber = (modelNumber != IntPtr.Zero) ? Marshal.PtrToStringAnsi(modelNumber) : string.Empty,
901                 PlatformVersion = (platformVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(platformVersion) : string.Empty,
902                 OsVersion = (osVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(osVersion) : string.Empty,
903                 HardwareVersion = (hardwareVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(hardwareVersion) : string.Empty,
904                 FirmwareVersion = (firmwareVersion != IntPtr.Zero) ? Marshal.PtrToStringAnsi(firmwareVersion) : string.Empty,
905                 SupportUrl = (supportUrl != IntPtr.Zero) ? Marshal.PtrToStringAnsi(supportUrl) : string.Empty,
906                 SystemTime = (systemTime != IntPtr.Zero) ? Marshal.PtrToStringAnsi(systemTime) : string.Empty
907             };
908
909             return e;
910         }
911
912         private static FindingErrorOccurredEventArgs GetFindingErrorOccurredEventArgs(int requestId, int err)
913         {
914             FindingErrorOccurredEventArgs e = new FindingErrorOccurredEventArgs()
915             {
916                 RequestId = requestId,
917                 Error = IoTConnectivityErrorFactory.GetException(err)
918             };
919             return e;
920         }
921     }
922 }