Release 4.0.0-preview1-00051
[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     /// <since_tizen> 4 </since_tizen>
44     public class DnssdService : INsdService
45     {
46         private uint _serviceHandle;
47         private string _serviceType;
48         private ushort _dnsRecordtype = 16;
49         private Interop.Nsd.Dnssd.ServiceRegisteredCallback _serviceRegisteredCallback;
50
51         /// <summary>
52         /// Constructor to create DnssdService instance that sets the serviceType to a given value.
53         /// </summary>
54         /// <since_tizen> 4 </since_tizen>
55         /// <param name="serviceType">The DNSSD service type. It is expressed as type followed by protocol, separated by a dot(e.g. "_ftp._tcp").
56         /// It must begin with an underscore, followed by 1-15 characters which may be letters, digits or hyphens.
57         /// </param>
58         /// <feature>http://tizen.org/feature/network.dnssd</feature>
59         /// <exception cref="NotSupportedException">Thrown while setting this property when DNSSD is not supported.</exception>
60         /// <exception cref="ArgumentException">Thrown when serviceType is set to null.</exception>
61         public DnssdService(string serviceType)
62         {
63             _serviceType = serviceType;
64             DnssdInitializeCreateService();
65         }
66
67         internal DnssdService(uint service)
68         {
69             _serviceHandle = service;
70         }
71
72         internal void DnssdInitializeCreateService()
73         {
74             DnssdInitializer dnssdInit = Globals.s_threadDns.Value;
75             Log.Info(Globals.LogTag, "Initialize ThreadLocal<DnssdInitializer> instance = " + dnssdInit);
76             int ret = Interop.Nsd.Dnssd.CreateService(_serviceType, out _serviceHandle);
77             if (ret != (int)DnssdError.None)
78             {
79                 Log.Error(Globals.LogTag, "Failed to create a local Dnssd service handle, Error - " + (DnssdError)ret);
80                 NsdErrorFactory.ThrowDnssdException(ret);
81             }
82         }
83
84         /// <summary>
85         /// Name of DNSSD service.
86         /// </summary>
87         /// <remarks>
88         /// Set Name for only unregistered service created locally.
89         /// It may be up to 63 bytes.
90         /// In case of error, null will be returned during get and exception will be thrown during set.
91         /// </remarks>
92         /// <since_tizen> 4 </since_tizen>
93         /// <feature>http://tizen.org/feature/network.dnssd</feature>
94         /// <exception cref="NotSupportedException">Thrown while setting this property when DNSSD is not supported.</exception>
95         /// <exception cref="ArgumentException">Thrown when Name value is set to null.</exception>
96         /// <exception cref="InvalidOperationException">Thrown while setting this property when any other error occurred.</exception>
97         public string Name
98         {
99             get
100             {
101                 string name;
102                 int ret = Interop.Nsd.Dnssd.GetName(_serviceHandle, out name);
103                 if (ret != (int)DnssdError.None)
104                 {
105                     Log.Error(Globals.LogTag, "Failed to get name of service, Error: " + (DnssdError)ret);
106                     return null;
107                 }
108
109                 return name;
110             }
111
112             set
113             {
114                 if (!Globals.s_threadDns.IsValueCreated)
115                 {
116                     DnssdInitializeCreateService();
117                 }
118
119                 int ret = Interop.Nsd.Dnssd.SetName(_serviceHandle, value);
120                 if (ret != (int)DnssdError.None)
121                 {
122                     Log.Error(Globals.LogTag, "Failed to set name of service, Error: " + (DnssdError)ret);
123                     NsdErrorFactory.ThrowDnssdException(ret);
124                 }
125             }
126         }
127
128         /// <summary>
129         /// Type of DNSSD local/remote service.
130         /// </summary>
131         /// <remarks>
132         /// It is expressed as type followed by protocol, separated by a dot(e.g. "_ftp._tcp").
133         /// It must begin with an underscore, followed by 1-15 characters which may be letters, digits or hyphens.
134         /// In case of error, null will be returned.
135         /// </remarks>
136         /// <since_tizen> 4 </since_tizen>
137         public string Type
138         {
139             get
140             {
141                 string type;
142                 int ret = Interop.Nsd.Dnssd.GetType(_serviceHandle, out type);
143                 if (ret != (int)DnssdError.None)
144                 {
145                     Log.Error(Globals.LogTag, "Failed to get type of service, Error: " + (DnssdError)ret);
146                     return null;
147                 }
148
149                 return type;
150             }
151         }
152
153         /// <summary>
154         /// Port number of DNSSD local/remote service.
155         /// </summary>
156         /// <remarks>
157         /// Set Port for only unregistered service created locally. The default value of Port is 0.
158         /// In case of error, -1 will be returned during get and exception will be thrown during set.
159         /// </remarks>
160         /// <since_tizen> 4 </since_tizen>
161         /// <feature>http://tizen.org/feature/network.dnssd</feature>
162         /// <exception cref="NotSupportedException">Thrown while setting this property when DNSSD is not supported.</exception>
163         /// <exception cref="ArgumentException">Thrown if value of Port is set to less than 0 or more than 65535.</exception>
164         /// <exception cref="InvalidOperationException">Thrown while setting this property when any other error occurred.</exception>
165         public int Port
166         {
167             get
168             {
169                 int port;
170                 int ret = Interop.Nsd.Dnssd.GetPort(_serviceHandle, out port);
171                 if (ret != (int)DnssdError.None)
172                 {
173                     Log.Error(Globals.LogTag, "Failed to get port number of Dnssd service, Error: " + (DnssdError)ret);
174                     return -1;
175                 }
176
177                 return port;
178             }
179
180             set
181             {
182                 if (!Globals.s_threadDns.IsValueCreated)
183                 {
184                     DnssdInitializeCreateService();
185                 }
186
187                 int ret = Interop.Nsd.Dnssd.SetPort(_serviceHandle, value);
188                 if (ret != (int)DnssdError.None)
189                 {
190                     Log.Error(Globals.LogTag, "Failed to set port number of Dnssd service, Error: " + (DnssdError)ret);
191                     NsdErrorFactory.ThrowDnssdException(ret);
192                 }
193             }
194         }
195
196         /// <summary>
197         /// IP address of DNSSD remote service.
198         /// </summary>
199         /// <remarks>
200         /// If the remote service has no IPv4 Address, then IPv4Address would contain null and if it has no IPv6 Address, then IPv6Address would contain null.
201         /// In case of error, null object will be returned.
202         /// </remarks>
203         /// <since_tizen> 4 </since_tizen>
204         public IPAddressInformation IP
205         {
206             get
207             {
208                 string IPv4, IPv6;
209                 int ret = Interop.Nsd.Dnssd.GetIP(_serviceHandle, out IPv4, out IPv6);
210                 if (ret != (int)DnssdError.None)
211                 {
212                     Log.Error(Globals.LogTag, "Failed to get the IP of Dnssd remote service, Error: " + (DnssdError)ret);
213                     return null;
214                 }
215
216                 IPAddressInformation IPAddressInstance = new IPAddressInformation(IPv4, IPv6);
217                 return IPAddressInstance;
218             }
219         }
220
221         private void GetTxtRecord(out ushort length, out byte[] value)
222         {
223             int ret = Interop.Nsd.Dnssd.GetAllTxtRecord(_serviceHandle, out length, out value);
224             if (ret != (int)DnssdError.None)
225             {
226                 Log.Error(Globals.LogTag, "Failed to get the TXT record, Error: " + (DnssdError)ret);
227                 NsdErrorFactory.ThrowDnssdException(ret);
228             }
229         }
230
231         /// <summary>
232         /// Adds the TXT record.
233         /// </summary>
234         /// <remarks>
235         /// TXT record should be added after registering local service using RegisterService().
236         /// </remarks>
237         /// <since_tizen> 4 </since_tizen>
238         /// <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>
239         /// <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>
240         /// <feature>http://tizen.org/feature/network.dnssd</feature>
241         /// <exception cref="NotSupportedException">Thrown when DNSSD is not supported.</exception>
242         /// <exception cref="ArgumentException">Thrown when value of key is null.</exception>
243         /// <exception cref="InvalidOperationException">Thrown when any other error occurred.</exception>
244         public void AddTXTRecord(string key, string value)
245         {
246             byte[] byteValue = Encoding.UTF8.GetBytes(value);
247             ushort length = Convert.ToUInt16(byteValue.Length);
248             int ret = Interop.Nsd.Dnssd.AddTxtRecord(_serviceHandle, key, length, byteValue);
249             if (ret != (int)DnssdError.None)
250             {
251                 Log.Error(Globals.LogTag, "Failed to add the TXT record, Error: " + (DnssdError)ret);
252                 NsdErrorFactory.ThrowDnssdException(ret);
253             }
254
255             byte[] txtValue;
256             ushort txtLength;
257             GetTxtRecord(out txtLength, out txtValue);
258
259             ret = Interop.Nsd.Dnssd.SetRecord(_serviceHandle, _dnsRecordtype, txtLength, txtValue);
260             if (ret != (int)DnssdError.None)
261             {
262                 Log.Error(Globals.LogTag, "Failed to set the DNS resource record, Error: " + (DnssdError)ret);
263                 NsdErrorFactory.ThrowDnssdException(ret);
264             }
265         }
266
267         /// <summary>
268         /// Removes the TXT record.
269         /// </summary>
270         /// <since_tizen> 4 </since_tizen>
271         /// <param name="key">The key of the TXT record to be removed.</param>
272         /// <feature>http://tizen.org/feature/network.dnssd</feature>
273         /// <exception cref="NotSupportedException">Thrown when DNSSD is not supported.</exception>
274         /// <exception cref="ArgumentException">Thrown when value of key is null.</exception>
275         /// <exception cref="InvalidOperationException">Thrown when any other error occurred.</exception>
276         public void RemoveTXTRecord(string key)
277         {
278             int ret = Interop.Nsd.Dnssd.RemoveTxtRecord(_serviceHandle, key);
279             if (ret != (int)DnssdError.None)
280             {
281                 Log.Error(Globals.LogTag, "Failed to remove the TXT record, Error: " + (DnssdError)ret);
282                 NsdErrorFactory.ThrowDnssdException(ret);
283             }
284
285             byte[] txtValue;
286             ushort txtLength;
287             GetTxtRecord(out txtLength, out txtValue);
288             if (txtLength == 0)
289             {
290                 ret = Interop.Nsd.Dnssd.UnsetRecord(_serviceHandle, _dnsRecordtype);
291                 if (ret != (int)DnssdError.None)
292                 {
293                     Log.Error(Globals.LogTag, "Failed to unset the DNS resource record, Error: " + (DnssdError)ret);
294                     NsdErrorFactory.ThrowDnssdException(ret);
295                 }
296             }
297         }
298
299         /// <summary>
300         /// Registers the DNSSD local service for publishing.
301         /// </summary>
302         /// Name of the service must be set.
303         /// <since_tizen> 4 </since_tizen>
304         /// <privilege>http://tizen.org/privilege/internet</privilege>
305         /// <feature>http://tizen.org/feature/network.dnssd</feature>
306         /// <exception cref="InvalidOperationException">Thrown when any other error occurred.</exception>
307         /// <exception cref="NotSupportedException">Thrown when DNSSD is not supported.</exception>
308         /// <exception cref="UnauthorizedAccessException">Thrown when permission is denied.</exception>
309         public void RegisterService()
310         {
311             if (!Globals.s_threadDns.IsValueCreated)
312             {
313                 DnssdInitializeCreateService();
314             }
315
316             _serviceRegisteredCallback = (DnssdError result, uint service, IntPtr userData) =>
317             {
318                 if (result != DnssdError.None)
319                 {
320                     Log.Error(Globals.LogTag, "Failed to finish the registration of Dnssd local service, Error: " + result);
321                     NsdErrorFactory.ThrowDnssdException((int)result);
322                 }
323             };
324
325             int ret = Interop.Nsd.Dnssd.RegisterService(_serviceHandle, _serviceRegisteredCallback, IntPtr.Zero);
326             if (ret != (int)DnssdError.None)
327             {
328                 Log.Error(Globals.LogTag, "Failed to register the Dnssd local service, Error: " + (DnssdError)ret);
329                 NsdErrorFactory.ThrowDnssdException(ret);
330             }
331         }
332
333         /// <summary>
334         /// Deregisters the DNSSD local service.
335         /// </summary>
336         /// <remarks>
337         /// A local service registered using RegisterService() must be passed.
338         /// </remarks>
339         /// <since_tizen> 4 </since_tizen>
340         /// <feature>http://tizen.org/feature/network.dnssd</feature>
341         /// <exception cref="InvalidOperationException">Thrown when any other error occurred.</exception>
342         /// <exception cref="NotSupportedException">Thrown when DNSSD is not supported.</exception>
343         public void DeregisterService()
344         {
345             int ret = Interop.Nsd.Dnssd.DeregisterService(_serviceHandle);
346             if (ret != (int)DnssdError.None)
347             {
348                 Log.Error(Globals.LogTag, "Failed to deregister the Dnssd local service, Error: " + (DnssdError)ret);
349                 NsdErrorFactory.ThrowDnssdException(ret);
350             }
351         }
352
353         #region IDisposable Support
354         private bool _disposedValue = false; // To detect redundant calls
355
356         private void Dispose(bool disposing)
357         {
358             if (!_disposedValue)
359             {
360                 if (disposing)
361                 {
362                     if (_serviceHandle != 0)
363                     {
364                         int ret = Interop.Nsd.Dnssd.DestroyService(_serviceHandle);
365                         if (ret != (int)DnssdError.None)
366                         {
367                             Log.Error(Globals.LogTag, "Failed to destroy the local Dnssd service handle, Error - " + (DnssdError)ret);
368                         }
369                     }
370                 }
371
372                 _disposedValue = true;
373             }
374         }
375
376          ~DnssdService()
377         {
378             Dispose(false);
379         }
380
381         /// <summary>
382         /// Disposes the memory allocated to unmanaged resources.
383         /// </summary>
384         /// <since_tizen> 4 </since_tizen>
385         public void Dispose()
386         {
387             Dispose(true);
388             GC.SuppressFinalize(this);
389         }
390         #endregion
391     }
392
393     /// <summary>
394     /// This class manages the IP address properties of DNSSD service.
395     /// </summary>
396     /// <since_tizen> 4 </since_tizen>
397     public class IPAddressInformation
398     {
399         private string _ipv4, _ipv6;
400         internal IPAddressInformation()
401         {
402         }
403
404         internal IPAddressInformation(string ipv4, string ipv6)
405         {
406             _ipv4 = ipv4;
407             _ipv6 = ipv6;
408         }
409
410         /// <summary>
411         /// The IP version 4 address of DNSSD service.
412         /// </summary>
413         /// <since_tizen> 4 </since_tizen>
414         public IPAddress IPv4Address
415         {
416             get
417             {
418                 if (_ipv4 == null)
419                     return IPAddress.Parse("0.0.0.0");
420                 return IPAddress.Parse(_ipv4);
421             }
422         }
423
424         /// <summary>
425         /// The IP version 6 address of DNSSD service.
426         /// </summary>
427         /// <since_tizen> 4 </since_tizen>
428         public IPAddress IPv6Address
429         {
430             get
431             {
432                 if (_ipv6 == null)
433                     return IPAddress.Parse("0:0:0:0:0:0:0:0");
434                 return IPAddress.Parse(_ipv6);
435             }
436         }
437     }
438 }