[Nsd] Implemented Dnssd and Ssdp apis and properties
authorshikha.ta <shikha.ta@samsung.com>
Fri, 17 Mar 2017 06:23:15 +0000 (11:53 +0530)
committershikha.ta <shikha.ta@samsung.com>
Wed, 22 Mar 2017 06:21:12 +0000 (11:51 +0530)
Change-Id: I5e66da168fa67cf01f12870e83763d8fa49cd9e7
Signed-off-by: shikha.ta <shikha.ta@samsung.com>
src/Tizen.Network.Nsd/Interop/Interop.Nsd.cs
src/Tizen.Network.Nsd/Tizen.Network.Nsd/DnssdBrowser.cs
src/Tizen.Network.Nsd/Tizen.Network.Nsd/DnssdService.cs
src/Tizen.Network.Nsd/Tizen.Network.Nsd/NsdError.cs
src/Tizen.Network.Nsd/Tizen.Network.Nsd/NsdManager.cs
src/Tizen.Network.Nsd/Tizen.Network.Nsd/SsdpBrowser.cs
src/Tizen.Network.Nsd/Tizen.Network.Nsd/SsdpService.cs

index 940d922..5979c1d 100755 (executable)
@@ -70,7 +70,7 @@ internal static partial class Interop
             [DllImport(Libraries.Dnssd, EntryPoint = "dnssd_service_get_name")]
             internal static extern int GetName(uint service, out string name);
             [DllImport(Libraries.Dnssd, EntryPoint = "dnssd_service_get_ip")]
-            internal static extern int GetIp(uint service, out string ipV4, out string ipV6);
+            internal static extern int GetIP(uint service, out string ipV4, out string ipV6);
             [DllImport(Libraries.Dnssd, EntryPoint = "dnssd_service_get_port")]
             internal static extern int GetPort(uint service, out int port);
             [DllImport(Libraries.Dnssd, EntryPoint = "dnssd_service_get_all_txt_record")]
index 8dd3911..020a58a 100755 (executable)
@@ -24,10 +24,12 @@ namespace Tizen.Network.Nsd
     public class DnssdBrowser : INsdBrowser
     {
         private string _serviceType;
+        private uint _browserHandle;
         private event EventHandler<DnssdServiceFoundEventArgs> _serviceFound;
+        private Interop.Nsd.Dnssd.ServiceFoundCallback _serviceFoundCallback;
 
         /// <summary>
-        /// This event is raised when service state changes during service discovery using DNSSD.
+        /// This event is raised when a DNSSD service is found during service discovery.
         /// </summary>
         public event EventHandler<DnssdServiceFoundEventArgs> ServiceFound
         {
@@ -48,7 +50,43 @@ namespace Tizen.Network.Nsd
         /// <param name="serviceType">The DNSSD service type</param>
         public DnssdBrowser(string serviceType)
         {
+            DnssdInitializer dnssdInit = Globals.s_threadDns.Value;
+            Log.Info(Globals.LogTag, "Initialize ThreadLocal<DnssdInitializer> instance = " + dnssdInit);
+
             _serviceType = serviceType;
         }
+
+        internal void StartDiscovery()
+        {
+            DnssdInitializer dnssdInit = Globals.s_threadDns.Value;
+            Log.Info(Globals.LogTag, "Initialize ThreadLocal<DnssdInitializer> instance = " + dnssdInit);
+
+            _serviceFoundCallback = (DnssdServiceState state, uint service, IntPtr userData) =>
+            {
+                if (_serviceFound != null)
+                {
+                    Log.Info(Globals.LogTag, "Inside Service found callback");
+                    DnssdService dnsService = new DnssdService(service);
+                    _serviceFound(null, new DnssdServiceFoundEventArgs(state, dnsService));
+                }
+            };
+
+            int ret = Interop.Nsd.Dnssd.StartBrowsing(_serviceType, out _browserHandle, _serviceFoundCallback, IntPtr.Zero);
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to discover Dnssd remote service, Error - " + (DnssdError)ret);
+                NsdErrorFactory.ThrowDnssdException(ret);
+            }
+        }
+
+        internal void StopDiscovery()
+        {
+            int ret = Interop.Nsd.Dnssd.StopBrowsing(_browserHandle);
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to stop discovery of Dnssd remote service, Error - " + (DnssdError)ret);
+                NsdErrorFactory.ThrowDnssdException(ret);
+            }
+        }
     }
 }
index 852c9f0..e84ddcc 100755 (executable)
  * limitations under the License.
  */
 
+using System;
+using System.Text;
+using System.Threading;
+using System.Net;
+
 namespace Tizen.Network.Nsd
 {
+    internal class DnssdInitializer
+    {
+        internal DnssdInitializer()
+        {
+            Globals.DnssdInitialize();
+        }
+
+        ~DnssdInitializer()
+        {
+            int ret = Interop.Nsd.Dnssd.Deinitialize();
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to deinitialize Dnssd, Error - " + (DnssdError)ret);
+            }
+        }
+    }
     /// <summary>
-    /// This class is used for managing local service discovery using DNSSD.
+    /// This class is used for managing local service registration and its properties using DNSSD.
     /// </summary>
     public class DnssdService : INsdService
     {
-        private uint _service;
+        private uint _serviceHandle;
+        private string _serviceType;
+        private ushort _dnsRecordtype = 16;
+        private Interop.Nsd.Dnssd.ServiceRegisteredCallback _serviceRegisteredCallback;
 
         /// <summary>
-        /// Name of DNSSD local service.
+        /// Constructor to create DnssdService instance that sets the serviceType to a given value.
         /// </summary>
+        /// <param name="serviceType">The DNSSD service type. It is expressed as type followed by protocol, separated by a dot(e.g. "_ftp._tcp").
+        /// It must begin with an underscore, followed by 1-15 characters which may be letters, digits or hyphens.
+        /// </param>
+        public DnssdService(string serviceType)
+        {
+            _serviceType = serviceType;
+            DnssdInitializeCreateService();
+        }
+
+        internal DnssdService(uint service)
+        {
+            _serviceHandle = service;
+        }
+
+        internal void DnssdInitializeCreateService()
+        {
+            DnssdInitializer dnssdInit = Globals.s_threadDns.Value;
+            Log.Info(Globals.LogTag, "Initialize ThreadLocal<DnssdInitializer> instance = " + dnssdInit);
+            int ret = Interop.Nsd.Dnssd.CreateService(_serviceType, out _serviceHandle);
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to create a local Dnssd service handle, Error - " + (DnssdError)ret);
+                NsdErrorFactory.ThrowDnssdException(ret);
+            }
+        }
+
+        /// <summary>
+        /// Name of DNSSD service.
+        /// </summary>
+        /// <remarks>
+        /// Set Name for only unregistered service created locally.
+        /// In case of error, null will be returned during get and exception will be thrown during set.
+        /// </remarks>
+        /// <exception cref="NotSupportedException">Thrown while setting this property when DNSSD is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown while setting this property when any other error occured.</exception>
         public string Name
         {
             get
             {
                 string name;
-                int ret = Interop.Nsd.Dnssd.GetName(_service, out name);
+                int ret = Interop.Nsd.Dnssd.GetName(_serviceHandle, out name);
                 if (ret != (int)DnssdError.None)
                 {
                     Log.Error(Globals.LogTag, "Failed to get name of service, Error: " + (DnssdError)ret);
@@ -43,7 +102,12 @@ namespace Tizen.Network.Nsd
 
             set
             {
-                int ret = Interop.Nsd.Dnssd.SetName(_service, value.ToString());
+                if (!Globals.s_threadDns.IsValueCreated)
+                {
+                    DnssdInitializeCreateService();
+                }
+
+                int ret = Interop.Nsd.Dnssd.SetName(_serviceHandle, value.ToString());
                 if (ret != (int)DnssdError.None)
                 {
                     Log.Error(Globals.LogTag, "Failed to set name of service, Error: " + (DnssdError)ret);
@@ -55,12 +119,15 @@ namespace Tizen.Network.Nsd
         /// <summary>
         /// Type of DNSSD local/remote service.
         /// </summary>
+        /// <remarks>
+        /// In case of error, null will be returned.
+        /// </remarks>
         public string Type
         {
             get
             {
                 string type;
-                int ret = Interop.Nsd.Dnssd.GetType(_service, out type);
+                int ret = Interop.Nsd.Dnssd.GetType(_serviceHandle, out type);
                 if (ret != (int)DnssdError.None)
                 {
                     Log.Error(Globals.LogTag, "Failed to get type of service, Error: " + (DnssdError)ret);
@@ -70,5 +137,223 @@ namespace Tizen.Network.Nsd
                 return type;
             }
         }
+
+        /// <summary>
+        /// Port number of DNSSD local/remote service.
+        /// </summary>
+        /// <remarks>
+        /// Set Port for only unregistered service created locally.
+        /// In case of error, -1 will be returned during get and exception will be thrown during set.
+        /// </remarks>
+        /// <exception cref="NotSupportedException">Thrown while setting this property when DNSSD is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown while setting this property when any other error occured.</exception>
+        public int Port
+        {
+            get
+            {
+                int port;
+                int ret = Interop.Nsd.Dnssd.GetPort(_serviceHandle, out port);
+                if (ret != (int)DnssdError.None)
+                {
+                    Log.Error(Globals.LogTag, "Failed to get port number of Dnssd service, Error: " + (DnssdError)ret);
+                    return -1;
+                }
+
+                return port;
+            }
+
+            set
+            {
+                if (!Globals.s_threadDns.IsValueCreated)
+                {
+                    DnssdInitializeCreateService();
+                }
+
+                int ret = Interop.Nsd.Dnssd.SetPort(_serviceHandle, value);
+                if (ret != (int)DnssdError.None)
+                {
+                    Log.Error(Globals.LogTag, "Failed to set port number of Dnssd service, Error: " + (DnssdError)ret);
+                    NsdErrorFactory.ThrowDnssdException(ret);
+                }
+            }
+        }
+
+        /// <summary>
+        /// IP of DNSSD remote service.
+        /// </summary>
+        /// <remarks>
+        /// If there is no IPv4 Address, then IPV4Address would contain null and if there is no IPv6 Address, then IPV6Address would contain null.
+        /// In case of error, null object will be returned.
+        /// </remarks>
+        public IPAddressInformation IP
+        {
+            get
+            {
+                string IPv4, IPv6;
+                int ret = Interop.Nsd.Dnssd.GetIP(_serviceHandle, out IPv4, out IPv6);
+                if (ret != (int)DnssdError.None)
+                {
+                    Log.Error(Globals.LogTag, "Failed to get the IP of Dnssd remote service, Error: " + (DnssdError)ret);
+                    return null;
+                }
+
+                IPAddressInformation IPAddressInstance = new IPAddressInformation(IPv4, IPv6);
+                return IPAddressInstance;
+            }
+        }
+
+        private void GetTxtRecord(out ushort length, out byte[] value)
+        {
+            int ret = Interop.Nsd.Dnssd.GetAllTxtRecord(_serviceHandle, out length, out value);
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to get the TXT record, Error: " + (DnssdError)ret);
+                NsdErrorFactory.ThrowDnssdException(ret);
+            }
+        }
+
+        /// <summary>
+        /// Adds the TXT record.
+        /// </summary>
+        /// <remarks>
+        /// TXT record should be added after registering local service using RegisterService().
+        /// </remarks>
+        /// <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>
+        /// <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>
+        /// <exception cref="NotSupportedException">Thrown when DNSSD is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown when any other error occured.</exception>
+        public void AddTXTRecord(string key, string value)
+        {
+            byte[] byteValue = Encoding.UTF8.GetBytes(value);
+            ushort length = Convert.ToUInt16(byteValue.Length);
+            int ret = Interop.Nsd.Dnssd.AddTxtRecord(_serviceHandle, key, length, byteValue);
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to add the TXT record, Error: " + (DnssdError)ret);
+                NsdErrorFactory.ThrowDnssdException(ret);
+            }
+
+            byte[] txtValue;
+            ushort txtLength;
+            GetTxtRecord(out txtLength, out txtValue);
+
+            ret = Interop.Nsd.Dnssd.SetRecord(_serviceHandle, _dnsRecordtype, txtLength, txtValue);
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to set the DNS resource record, Error: " + (DnssdError)ret);
+                NsdErrorFactory.ThrowDnssdException(ret);
+            }
+        }
+
+        /// <summary>
+        /// Removes the TXT record.
+        /// </summary>
+        /// <param name="key">The key of the TXT record to be removed.</param>
+        /// <exception cref="NotSupportedException">Thrown when DNSSD is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown when any other error occured.</exception>
+        public void RemoveTXTRecord(string key)
+        {
+            int ret = Interop.Nsd.Dnssd.RemoveTxtRecord(_serviceHandle, key);
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to remove the TXT record, Error: " + (DnssdError)ret);
+                NsdErrorFactory.ThrowDnssdException(ret);
+            }
+
+            byte[] txtValue;
+            ushort txtLength;
+            GetTxtRecord(out txtLength, out txtValue);
+            if (txtLength == 0)
+            {
+                ret = Interop.Nsd.Dnssd.UnsetRecord(_serviceHandle, _dnsRecordtype);
+                if (ret != (int)DnssdError.None)
+                {
+                    Log.Error(Globals.LogTag, "Failed to unset the DNS resource record, Error: " + (DnssdError)ret);
+                    NsdErrorFactory.ThrowDnssdException(ret);
+                }
+            }
+        }
+
+        internal void RegisterService()
+        {
+            if (Globals.s_threadDns.IsValueCreated)
+            {
+                DnssdInitializeCreateService();
+            }
+
+            _serviceRegisteredCallback = (DnssdError result, uint service, IntPtr userData) =>
+            {
+                if (result != DnssdError.None)
+                {
+                    Log.Error(Globals.LogTag, "Failed to finish the registration of Dnssd local service, Error: " + result);
+                    NsdErrorFactory.ThrowDnssdException((int)result);
+                }
+            };
+
+            int ret = Interop.Nsd.Dnssd.RegisterService(_serviceHandle, _serviceRegisteredCallback, IntPtr.Zero);
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to register the Dnssd local service, Error: " + (DnssdError)ret);
+                NsdErrorFactory.ThrowDnssdException(ret);
+            }
+        }
+
+        internal void DeregisterService()
+        {
+            int ret = Interop.Nsd.Dnssd.DeregisterService(_serviceHandle);
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to deregister the Dnssd local service, Error: " + (DnssdError)ret);
+                NsdErrorFactory.ThrowDnssdException(ret);
+            }
+        }
+
+        ~DnssdService()
+        {
+            int ret = Interop.Nsd.Dnssd.DestroyService(_serviceHandle);
+            if (ret != (int)DnssdError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to destroy the local Dnssd service handle, Error - " + (DnssdError)ret);
+            }
+        }
+    }
+
+    /// <summary>
+    /// This class manages the IP address properties of DNSSD service.
+    /// </summary>
+    public class IPAddressInformation
+    {
+        private string _ipv4, _ipv6;
+        internal IPAddressInformation()
+        {
+        }
+
+        internal IPAddressInformation(string ipv4, string ipv6)
+        {
+            _ipv4 = ipv4;
+            _ipv6 = ipv6;
+        }
+
+        /// <summary>
+        /// The IP version 4 address of DNSSD service.
+        /// </summary>
+        public IPAddress IPV4Address
+        {
+            get
+            {
+                return IPAddress.Parse(_ipv4);
+            }
+        }
+
+        /// <summary>
+        /// The IP version 6 address of DNSSD service.
+        /// </summary>
+        public IPAddress IPV6Address
+        {
+            get
+            {
+                return IPAddress.Parse(_ipv6);
+            }
+        }
     }
-}
+}
\ No newline at end of file
index a26f265..36891f4 100755 (executable)
@@ -32,7 +32,7 @@ namespace Tizen.Network.Nsd
             case DnssdError.InvalidParameter:
                 throw new InvalidOperationException("Invalid parameter");
             case DnssdError.NotSupported:
-                throw new InvalidOperationException("Not supported");
+                throw new NotSupportedException("Not supported");
             case DnssdError.NotInitialized:
                 throw new InvalidOperationException("Not initialized");
             case DnssdError.AlreadyRegistered:
@@ -58,7 +58,7 @@ namespace Tizen.Network.Nsd
                 case SsdpError.InvalidParameter:
                     throw new InvalidOperationException("Invalid parameter");
                 case SsdpError.NotSupported:
-                    throw new InvalidOperationException("Not supported");
+                    throw new NotSupportedException("Not supported");
                 case SsdpError.NotInitialized:
                     throw new InvalidOperationException("Not initialized");
                 case SsdpError.OperationFailed:
index 5c52965..b80c273 100755 (executable)
  * limitations under the License.
  */
 
+using System.Threading;
+
 namespace Tizen.Network.Nsd
 {
     internal static class Globals
     {
         internal const string LogTag = "Tizen.Network.Nsd";
+
+        internal static void DnssdInitialize()
+        {
+            int ret = Interop.Nsd.Dnssd.Initialize();
+            if(ret!=(int)DnssdError.None)
+            {
+                Log.Error(LogTag, "Failed to initialize Dnssd, Error - "+ (DnssdError)ret);
+                NsdErrorFactory.ThrowDnssdException(ret);
+            }
+        }
+
+        internal static void SsdpInitialize()
+        {
+            int ret = Interop.Nsd.Ssdp.Initialize();
+            if (ret != (int)SsdpError.None)
+            {
+                Log.Error(LogTag, "Failed to initialize Ssdp, Error - " + (SsdpError)ret);
+                NsdErrorFactory.ThrowSsdpException(ret);
+            }
+        }
+
+        internal static ThreadLocal<DnssdInitializer> s_threadDns = new ThreadLocal<DnssdInitializer>(() =>
+       {
+           Log.Info(LogTag, "Inside Dnssd ThreadLocal delegate");
+           return new DnssdInitializer();
+       });
+
+        internal static ThreadLocal<SsdpInitializer> s_threadSsd = new ThreadLocal<SsdpInitializer>(() =>
+        {
+            Log.Info(LogTag, "Inside Ssdp ThreadLocal delegate");
+            return new SsdpInitializer();
+        });
     }
 
     /// <summary>
-    /// This class is used for managing local/network service discovery using DNSSD/SSDP.
+    /// This class is used for managing local/network service registration and discovery using DNSSD/SSDP.
     /// </summary>
     public static class NsdManager
     {
+        /// <summary>
+        /// Registers the DNSSD/SSDP local service for publishing.
+        /// </summary>
+        /// <remarks>
+        /// A service created locally must be passed.
+        /// Name of the service must be set for DNSSD/SSDP both. Also, Port and Url must be set for DNSSD and SSDP respectively.
+        /// </remarks>
+        /// <param name="service">The DNSSD/SSDP service instance.</param>
+        /// <exception cref="NotSupportedException">Thrown when DNSSD/SSDP is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown when any other error occured.</exception>
+        public static void RegisterService(INsdService service)
+        {
+            if (service.GetType() == typeof(DnssdService))
+            {
+                DnssdService dnsService = (DnssdService)service;
+                dnsService.RegisterService();
+            }
+
+            else if (service.GetType() == typeof(SsdpService))
+            {
+                SsdpService ssdService = (SsdpService)service;
+                ssdService.RegisterService();
+            }
+        }
+
+        /// <summary>
+        /// Deregisters the DNSSD/SSDP local service.
+        /// </summary>
+        /// <remarks>
+        /// A local service registered using RegisterService() must be passed.
+        /// </remarks>
+        /// <param name="service">The DNSSD/SSDP service instance.</param>
+        /// <exception cref="NotSupportedException">Thrown when DNSSD/SSDP is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown when any other error occured.</exception>
+        public static void UnregisterService(INsdService service)
+        {
+            if (service.GetType() == typeof(DnssdService))
+            {
+                DnssdService dnsService = (DnssdService)service;
+                dnsService.DeregisterService();
+            }
+
+            else if (service.GetType() == typeof(SsdpService))
+            {
+                SsdpService ssdService = (SsdpService)service;
+                ssdService.DeregisterService();
+            }
+        }
+
+        /// <summary>
+        /// Starts browsing the DNSSD/SSDP remote service.
+        /// </summary>
+        /// <remarks>
+        /// If there are any services available, ServiceFound event will be invoked.
+        /// Application will keep browsing for available/unavailable services until it calls StopDiscovery().
+        /// </remarks>
+        /// <param name="browser">The DNSSD/SSDP browser instance.</param>
+        /// <exception cref="NotSupportedException">Thrown when DNSSD/SSDP is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown when any other error occured.</exception>
+        public static void StartDiscovery(INsdBrowser browser)
+        {
+            if (browser.GetType() == typeof(DnssdBrowser))
+            {
+                DnssdBrowser dnsBrowser = (DnssdBrowser)browser;
+                dnsBrowser.StartDiscovery();
+            }
+
+            else if (browser.GetType() == typeof(SsdpBrowser))
+            {
+                SsdpBrowser ssdBrowser = (SsdpBrowser)browser;
+                ssdBrowser.StartDiscovery();
+            }
+        }
+
+        /// <summary>
+        /// Stops browsing the DNSSD/SSDP remote service.
+        /// </summary>
+        /// <param name="browser">The DNSSD/SSDP browser instance.</param>
+        /// <exception cref="NotSupportedException">Thrown when DNSSD/SSDP is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown when any other error occured.</exception>
+        public static void StopDiscovery(INsdBrowser browser)
+        {
+            if (browser.GetType() == typeof(DnssdBrowser))
+            {
+                DnssdBrowser dnsBrowser = (DnssdBrowser)browser;
+                dnsBrowser.StopDiscovery();
+            }
+
+            else if (browser.GetType() == typeof(SsdpBrowser))
+            {
+                SsdpBrowser ssdBrowser = (SsdpBrowser)browser;
+                ssdBrowser.StopDiscovery();
+            }
+        }
     }
 }
index 3753610..7f7d1ed 100755 (executable)
@@ -24,10 +24,12 @@ namespace Tizen.Network.Nsd
     public class SsdpBrowser : INsdBrowser
     {
         private string _target;
+        private uint _browserHandle;
         private event EventHandler<SsdpServiceFoundEventArgs> _serviceFound;
+        private Interop.Nsd.Ssdp.ServiceFoundCallback _serviceFoundCallback;
 
         /// <summary>
-        /// This event is raised when service state changes during service discovery using SSDP.
+        /// This event is raised when service has become available or unavailable during service discovery using SSDP.
         /// </summary>
         public event EventHandler<SsdpServiceFoundEventArgs> ServiceFound
         {
@@ -48,7 +50,43 @@ namespace Tizen.Network.Nsd
         /// <param name="target">The target to browse for the service.</param>
         public SsdpBrowser(string target)
         {
+            SsdpInitializer ssdpInit = Globals.s_threadSsd.Value;
+            Log.Info(Globals.LogTag, "Initialize ThreadLocal<SsdpInitializer> instance = " + ssdpInit);
+
             _target = target;
         }
+
+        internal void StartDiscovery()
+        {
+            SsdpInitializer ssdpInit = Globals.s_threadSsd.Value;
+            Log.Info(Globals.LogTag, "Initialize ThreadLocal<SsdpInitializer> instance = " + ssdpInit);
+
+            _serviceFoundCallback = (SsdpServiceState state, uint service, IntPtr userData) =>
+            {
+                if (_serviceFound != null)
+                {
+                    Log.Info(Globals.LogTag, "Inside Service found callback");
+                    SsdpService ssdpService = new SsdpService(service);
+                    _serviceFound(null, new SsdpServiceFoundEventArgs(state, ssdpService));
+                }
+            };
+
+            int ret = Interop.Nsd.Ssdp.StartBrowsing(_target, out _browserHandle, _serviceFoundCallback, IntPtr.Zero);
+            if (ret != (int)SsdpError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to discover Ssdp remote service, Error - " + (SsdpError)ret);
+                NsdErrorFactory.ThrowSsdpException(ret);
+            }
+        }
+
+        internal void StopDiscovery()
+        {
+            int ret = Interop.Nsd.Ssdp.StopBrowsing(_browserHandle);
+            if (ret != (int)SsdpError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to stop discovery of Ssdp remote service, Error - " + (SsdpError)ret);
+                NsdErrorFactory.ThrowSsdpException(ret);
+            }
+        }
     }
 }
index 86f2187..77f18ae 100755 (executable)
  * limitations under the License.
  */
 
+using System;
+
 namespace Tizen.Network.Nsd
 {
+    internal class SsdpInitializer
+    {
+        internal SsdpInitializer()
+        {
+            Globals.SsdpInitialize();
+        }
+
+        ~SsdpInitializer()
+        {
+            int ret = Interop.Nsd.Ssdp.Deinitialize();
+            if (ret != (int)SsdpError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to deinitialize Ssdp, Error - " + (SsdpError)ret);
+            }
+        }
+    }
+
     /// <summary>
-    /// This class is used for managing local service discovery using SSDP.
+    /// This class is used for managing local service registration and its properties using SSDP.
     /// </summary>
     public class SsdpService : INsdService
     {
-        private uint _service;
+        private uint _serviceHandle;
+        private string _target;
+        private Interop.Nsd.Ssdp.ServiceRegisteredCallback _serviceRegisteredCallback;
+
+        /// <summary>
+        /// Constructor to create SsdpService instance that sets the target to a given value.
+        /// </summary>
+        /// <param name="target">The SSDP local service's target. It may be a device type or a service type.</param>
+        public SsdpService(string target)
+        {
+            _target = target;
+            SsdpInitializeCreateService();
+        }
+
+        internal SsdpService(uint service)
+        {
+            _serviceHandle = service;
+        }
+
+        internal void SsdpInitializeCreateService()
+        {
+            SsdpInitializer ssdpInit = Globals.s_threadSsd.Value;
+            Log.Info(Globals.LogTag, "Initialize ThreadLocal<SsdpInitializer> instance = " + ssdpInit);
+            int ret = Interop.Nsd.Ssdp.CreateService(_target, out _serviceHandle);
+            if (ret != (int)SsdpError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to create a local Ssdp service handle, Error - " + (SsdpError)ret);
+                NsdErrorFactory.ThrowSsdpException(ret);
+            }
+        }
 
         /// <summary>
-        /// Name of SSDP local service.
+        /// Unique Service Name of SSDP service.
         /// </summary>
+        /// <remarks>
+        /// Set Name for only unregistered service created locally. If service is already registered, Name will not be set.
+        /// In case of error, null will be returned during get and exception will be thrown during set.
+        /// </remarks>
+        /// <exception cref="NotSupportedException">Thrown while setting this property when SSDP is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown while setting this property when any other error occured.</exception>
         public string Name
         {
             get
             {
                 string name;
-                int ret = Interop.Nsd.Ssdp.GetUsn(_service, out name);
+                int ret = Interop.Nsd.Ssdp.GetUsn(_serviceHandle, out name);
                 if (ret != (int)SsdpError.None)
                 {
                     Log.Error(Globals.LogTag, "Failed to get name of service, Error: " + (SsdpError)ret);
@@ -43,7 +97,12 @@ namespace Tizen.Network.Nsd
 
             set
             {
-                int ret = Interop.Nsd.Ssdp.SetUsn(_service, value.ToString());
+                if (Globals.s_threadSsd.IsValueCreated)
+                {
+                    SsdpInitializeCreateService();
+                }
+
+                int ret = Interop.Nsd.Ssdp.SetUsn(_serviceHandle, value.ToString());
                 if (ret != (int)SsdpError.None)
                 {
                     Log.Error(Globals.LogTag, "Failed to set name of service, Error: " + (SsdpError)ret);
@@ -53,14 +112,17 @@ namespace Tizen.Network.Nsd
         }
 
         /// <summary>
-        /// Type of SSDP local/remote service.
+        /// Type of SSDP service.
         /// </summary>
+        /// <remarks>
+        /// In case of error, null will be returned.
+        /// </remarks>
         public string Type
         {
             get
             {
                 string type;
-                int ret = Interop.Nsd.Ssdp.GetTarget(_service, out type);
+                int ret = Interop.Nsd.Ssdp.GetTarget(_serviceHandle, out type);
                 if (ret != (int)SsdpError.None)
                 {
                     Log.Error(Globals.LogTag, "Failed to get type of service, Error: " + (SsdpError)ret);
@@ -70,5 +132,83 @@ namespace Tizen.Network.Nsd
                 return type;
             }
         }
+
+        /// <summary>
+        /// URL of SSDP service.
+        /// </summary>
+        /// <remarks>
+        /// Set Url for only unregistered service created locally. If service is already registered, Url will not be set.
+        /// In case of error, null will be returned during get and exception will be thrown during set.
+        /// </remarks>
+        /// <exception cref="NotSupportedException">Thrown while setting this property when SSDP is not supported.</exception>
+        /// <exception cref="InvalidOperationException">Thrown while setting this property when any other error occured.</exception>
+        public string Url
+        {
+            get
+            {
+                string url;
+                int ret = Interop.Nsd.Ssdp.GetUrl(_serviceHandle, out url);
+                if (ret != (int)SsdpError.None)
+                {
+                    Log.Error(Globals.LogTag, "Failed to get url of Ssdp service, Error: " + (SsdpError)ret);
+                    return null;
+                }
+
+                return url;
+            }
+
+            set
+            {
+                if (Globals.s_threadSsd.IsValueCreated)
+                {
+                    SsdpInitializeCreateService();
+                }
+
+                int ret = Interop.Nsd.Ssdp.SetUrl(_serviceHandle, value.ToString());
+                if (ret != (int)SsdpError.None)
+                {
+                    Log.Error(Globals.LogTag, "Failed to set url of Ssdp service, Error: " + (SsdpError)ret);
+                    NsdErrorFactory.ThrowSsdpException(ret);
+                }
+            }
+        }
+
+        internal void RegisterService()
+        {
+            if (Globals.s_threadSsd.IsValueCreated)
+            {
+                SsdpInitializeCreateService();
+            }
+
+            _serviceRegisteredCallback = (SsdpError result, uint service, IntPtr userData) =>
+            {
+            };
+
+            int ret = Interop.Nsd.Ssdp.RegisterService(_serviceHandle, _serviceRegisteredCallback, IntPtr.Zero);
+            if (ret != (int)SsdpError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to register the Ssdp local service, Error: " + (SsdpError)ret);
+                NsdErrorFactory.ThrowSsdpException(ret);
+            }
+        }
+
+        internal void DeregisterService()
+        {
+            int ret = Interop.Nsd.Ssdp.DeregisterService(_serviceHandle);
+            if (ret != (int)SsdpError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to deregister the Ssdp local service, Error: " + (SsdpError)ret);
+                NsdErrorFactory.ThrowSsdpException(ret);
+            }
+        }
+
+        ~SsdpService()
+        {
+            int ret = Interop.Nsd.Ssdp.DestroyService(_serviceHandle);
+            if (ret != (int)SsdpError.None)
+            {
+                Log.Error(Globals.LogTag, "Failed to destroy the local Ssdp service handle, Error - " + (SsdpError)ret);
+            }
+        }
     }
 }