[Nsd] Implemented Dnssd and Ssdp apis and properties
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Nsd / Tizen.Network.Nsd / DnssdService.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.Text;
19 using System.Threading;
20 using System.Net;
21
22 namespace Tizen.Network.Nsd
23 {
24     internal class DnssdInitializer
25     {
26         internal DnssdInitializer()
27         {
28             Globals.DnssdInitialize();
29         }
30
31         ~DnssdInitializer()
32         {
33             int ret = Interop.Nsd.Dnssd.Deinitialize();
34             if (ret != (int)DnssdError.None)
35             {
36                 Log.Error(Globals.LogTag, "Failed to deinitialize Dnssd, Error - " + (DnssdError)ret);
37             }
38         }
39     }
40     /// <summary>
41     /// This class is used for managing local service registration and its properties using DNSSD.
42     /// </summary>
43     public class DnssdService : INsdService
44     {
45         private uint _serviceHandle;
46         private string _serviceType;
47         private ushort _dnsRecordtype = 16;
48         private Interop.Nsd.Dnssd.ServiceRegisteredCallback _serviceRegisteredCallback;
49
50         /// <summary>
51         /// Constructor to create DnssdService instance that sets the serviceType to a given value.
52         /// </summary>
53         /// <param name="serviceType">The DNSSD service type. It is expressed as type followed by protocol, separated by a dot(e.g. "_ftp._tcp").
54         /// It must begin with an underscore, followed by 1-15 characters which may be letters, digits or hyphens.
55         /// </param>
56         public DnssdService(string serviceType)
57         {
58             _serviceType = serviceType;
59             DnssdInitializeCreateService();
60         }
61
62         internal DnssdService(uint service)
63         {
64             _serviceHandle = service;
65         }
66
67         internal void DnssdInitializeCreateService()
68         {
69             DnssdInitializer dnssdInit = Globals.s_threadDns.Value;
70             Log.Info(Globals.LogTag, "Initialize ThreadLocal<DnssdInitializer> instance = " + dnssdInit);
71             int ret = Interop.Nsd.Dnssd.CreateService(_serviceType, out _serviceHandle);
72             if (ret != (int)DnssdError.None)
73             {
74                 Log.Error(Globals.LogTag, "Failed to create a local Dnssd service handle, Error - " + (DnssdError)ret);
75                 NsdErrorFactory.ThrowDnssdException(ret);
76             }
77         }
78
79         /// <summary>
80         /// Name of DNSSD service.
81         /// </summary>
82         /// <remarks>
83         /// Set Name for only unregistered service created locally.
84         /// In case of error, null will be returned during get and exception will be thrown during set.
85         /// </remarks>
86         /// <exception cref="NotSupportedException">Thrown while setting this property when DNSSD is not supported.</exception>
87         /// <exception cref="InvalidOperationException">Thrown while setting this property when any other error occured.</exception>
88         public string Name
89         {
90             get
91             {
92                 string name;
93                 int ret = Interop.Nsd.Dnssd.GetName(_serviceHandle, out name);
94                 if (ret != (int)DnssdError.None)
95                 {
96                     Log.Error(Globals.LogTag, "Failed to get name of service, Error: " + (DnssdError)ret);
97                     return null;
98                 }
99
100                 return name;
101             }
102
103             set
104             {
105                 if (!Globals.s_threadDns.IsValueCreated)
106                 {
107                     DnssdInitializeCreateService();
108                 }
109
110                 int ret = Interop.Nsd.Dnssd.SetName(_serviceHandle, value.ToString());
111                 if (ret != (int)DnssdError.None)
112                 {
113                     Log.Error(Globals.LogTag, "Failed to set name of service, Error: " + (DnssdError)ret);
114                     NsdErrorFactory.ThrowDnssdException(ret);
115                 }
116             }
117         }
118
119         /// <summary>
120         /// Type of DNSSD local/remote service.
121         /// </summary>
122         /// <remarks>
123         /// In case of error, null will be returned.
124         /// </remarks>
125         public string Type
126         {
127             get
128             {
129                 string type;
130                 int ret = Interop.Nsd.Dnssd.GetType(_serviceHandle, out type);
131                 if (ret != (int)DnssdError.None)
132                 {
133                     Log.Error(Globals.LogTag, "Failed to get type of service, Error: " + (DnssdError)ret);
134                     return null;
135                 }
136
137                 return type;
138             }
139         }
140
141         /// <summary>
142         /// Port number of DNSSD local/remote service.
143         /// </summary>
144         /// <remarks>
145         /// Set Port for only unregistered service created locally.
146         /// In case of error, -1 will be returned during get and exception will be thrown during set.
147         /// </remarks>
148         /// <exception cref="NotSupportedException">Thrown while setting this property when DNSSD is not supported.</exception>
149         /// <exception cref="InvalidOperationException">Thrown while setting this property when any other error occured.</exception>
150         public int Port
151         {
152             get
153             {
154                 int port;
155                 int ret = Interop.Nsd.Dnssd.GetPort(_serviceHandle, out port);
156                 if (ret != (int)DnssdError.None)
157                 {
158                     Log.Error(Globals.LogTag, "Failed to get port number of Dnssd service, Error: " + (DnssdError)ret);
159                     return -1;
160                 }
161
162                 return port;
163             }
164
165             set
166             {
167                 if (!Globals.s_threadDns.IsValueCreated)
168                 {
169                     DnssdInitializeCreateService();
170                 }
171
172                 int ret = Interop.Nsd.Dnssd.SetPort(_serviceHandle, value);
173                 if (ret != (int)DnssdError.None)
174                 {
175                     Log.Error(Globals.LogTag, "Failed to set port number of Dnssd service, Error: " + (DnssdError)ret);
176                     NsdErrorFactory.ThrowDnssdException(ret);
177                 }
178             }
179         }
180
181         /// <summary>
182         /// IP of DNSSD remote service.
183         /// </summary>
184         /// <remarks>
185         /// If there is no IPv4 Address, then IPV4Address would contain null and if there is no IPv6 Address, then IPV6Address would contain null.
186         /// In case of error, null object will be returned.
187         /// </remarks>
188         public IPAddressInformation IP
189         {
190             get
191             {
192                 string IPv4, IPv6;
193                 int ret = Interop.Nsd.Dnssd.GetIP(_serviceHandle, out IPv4, out IPv6);
194                 if (ret != (int)DnssdError.None)
195                 {
196                     Log.Error(Globals.LogTag, "Failed to get the IP of Dnssd remote service, Error: " + (DnssdError)ret);
197                     return null;
198                 }
199
200                 IPAddressInformation IPAddressInstance = new IPAddressInformation(IPv4, IPv6);
201                 return IPAddressInstance;
202             }
203         }
204
205         private void GetTxtRecord(out ushort length, out byte[] value)
206         {
207             int ret = Interop.Nsd.Dnssd.GetAllTxtRecord(_serviceHandle, out length, out value);
208             if (ret != (int)DnssdError.None)
209             {
210                 Log.Error(Globals.LogTag, "Failed to get the TXT record, Error: " + (DnssdError)ret);
211                 NsdErrorFactory.ThrowDnssdException(ret);
212             }
213         }
214
215         /// <summary>
216         /// Adds the TXT record.
217         /// </summary>
218         /// <remarks>
219         /// TXT record should be added after registering local service using RegisterService().
220         /// </remarks>
221         /// <param name="key">The key of the TXT record. It must be a null-terminated string with 9 characters or fewer excluding null. It is case insensitive.</param>
222         /// <param name="value">The value of the TXT record.If null, then "key" will be added with no value. If non-null but value_length is zero, then "key=" will be added with empty value.</param>
223         /// <exception cref="NotSupportedException">Thrown when DNSSD is not supported.</exception>
224         /// <exception cref="InvalidOperationException">Thrown when any other error occured.</exception>
225         public void AddTXTRecord(string key, string value)
226         {
227             byte[] byteValue = Encoding.UTF8.GetBytes(value);
228             ushort length = Convert.ToUInt16(byteValue.Length);
229             int ret = Interop.Nsd.Dnssd.AddTxtRecord(_serviceHandle, key, length, byteValue);
230             if (ret != (int)DnssdError.None)
231             {
232                 Log.Error(Globals.LogTag, "Failed to add the TXT record, Error: " + (DnssdError)ret);
233                 NsdErrorFactory.ThrowDnssdException(ret);
234             }
235
236             byte[] txtValue;
237             ushort txtLength;
238             GetTxtRecord(out txtLength, out txtValue);
239
240             ret = Interop.Nsd.Dnssd.SetRecord(_serviceHandle, _dnsRecordtype, txtLength, txtValue);
241             if (ret != (int)DnssdError.None)
242             {
243                 Log.Error(Globals.LogTag, "Failed to set the DNS resource record, Error: " + (DnssdError)ret);
244                 NsdErrorFactory.ThrowDnssdException(ret);
245             }
246         }
247
248         /// <summary>
249         /// Removes the TXT record.
250         /// </summary>
251         /// <param name="key">The key of the TXT record to be removed.</param>
252         /// <exception cref="NotSupportedException">Thrown when DNSSD is not supported.</exception>
253         /// <exception cref="InvalidOperationException">Thrown when any other error occured.</exception>
254         public void RemoveTXTRecord(string key)
255         {
256             int ret = Interop.Nsd.Dnssd.RemoveTxtRecord(_serviceHandle, key);
257             if (ret != (int)DnssdError.None)
258             {
259                 Log.Error(Globals.LogTag, "Failed to remove the TXT record, Error: " + (DnssdError)ret);
260                 NsdErrorFactory.ThrowDnssdException(ret);
261             }
262
263             byte[] txtValue;
264             ushort txtLength;
265             GetTxtRecord(out txtLength, out txtValue);
266             if (txtLength == 0)
267             {
268                 ret = Interop.Nsd.Dnssd.UnsetRecord(_serviceHandle, _dnsRecordtype);
269                 if (ret != (int)DnssdError.None)
270                 {
271                     Log.Error(Globals.LogTag, "Failed to unset the DNS resource record, Error: " + (DnssdError)ret);
272                     NsdErrorFactory.ThrowDnssdException(ret);
273                 }
274             }
275         }
276
277         internal void RegisterService()
278         {
279             if (Globals.s_threadDns.IsValueCreated)
280             {
281                 DnssdInitializeCreateService();
282             }
283
284             _serviceRegisteredCallback = (DnssdError result, uint service, IntPtr userData) =>
285             {
286                 if (result != DnssdError.None)
287                 {
288                     Log.Error(Globals.LogTag, "Failed to finish the registration of Dnssd local service, Error: " + result);
289                     NsdErrorFactory.ThrowDnssdException((int)result);
290                 }
291             };
292
293             int ret = Interop.Nsd.Dnssd.RegisterService(_serviceHandle, _serviceRegisteredCallback, IntPtr.Zero);
294             if (ret != (int)DnssdError.None)
295             {
296                 Log.Error(Globals.LogTag, "Failed to register the Dnssd local service, Error: " + (DnssdError)ret);
297                 NsdErrorFactory.ThrowDnssdException(ret);
298             }
299         }
300
301         internal void DeregisterService()
302         {
303             int ret = Interop.Nsd.Dnssd.DeregisterService(_serviceHandle);
304             if (ret != (int)DnssdError.None)
305             {
306                 Log.Error(Globals.LogTag, "Failed to deregister the Dnssd local service, Error: " + (DnssdError)ret);
307                 NsdErrorFactory.ThrowDnssdException(ret);
308             }
309         }
310
311         ~DnssdService()
312         {
313             int ret = Interop.Nsd.Dnssd.DestroyService(_serviceHandle);
314             if (ret != (int)DnssdError.None)
315             {
316                 Log.Error(Globals.LogTag, "Failed to destroy the local Dnssd service handle, Error - " + (DnssdError)ret);
317             }
318         }
319     }
320
321     /// <summary>
322     /// This class manages the IP address properties of DNSSD service.
323     /// </summary>
324     public class IPAddressInformation
325     {
326         private string _ipv4, _ipv6;
327         internal IPAddressInformation()
328         {
329         }
330
331         internal IPAddressInformation(string ipv4, string ipv6)
332         {
333             _ipv4 = ipv4;
334             _ipv6 = ipv6;
335         }
336
337         /// <summary>
338         /// The IP version 4 address of DNSSD service.
339         /// </summary>
340         public IPAddress IPV4Address
341         {
342             get
343             {
344                 return IPAddress.Parse(_ipv4);
345             }
346         }
347
348         /// <summary>
349         /// The IP version 6 address of DNSSD service.
350         /// </summary>
351         public IPAddress IPV6Address
352         {
353             get
354             {
355                 return IPAddress.Parse(_ipv6);
356             }
357         }
358     }
359 }