Home | History | Annotate | Download | only in avahi-sharp
      1 /***
      2   This file is part of avahi.
      3 
      4   avahi is free software; you can redistribute it and/or modify it
      5   under the terms of the GNU Lesser General Public License as
      6   published by the Free Software Foundation; either version 2.1 of the
      7   License, or (at your option) any later version.
      8 
      9   avahi is distributed in the hope that it will be useful, but WITHOUT
     10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     11   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
     12   Public License for more details.
     13 
     14   You should have received a copy of the GNU Lesser General Public
     15   License along with avahi; if not, write to the Free Software
     16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
     17   USA.
     18 ***/
     19 
     20 
     21 using System;
     22 using System.Threading;
     23 using System.Collections;
     24 using System.Runtime.InteropServices;
     25 using Mono.Unix;
     26 using Mono.Unix.Native;
     27 
     28 using Stdlib = Mono.Unix.Native.Stdlib;
     29 
     30 namespace Avahi
     31 {
     32     internal enum ResolverEvent {
     33         Found,
     34         Failure
     35     }
     36 
     37     internal enum BrowserEvent {
     38         Added,
     39         Removed,
     40         CacheExhausted,
     41         AllForNow,
     42         Failure
     43     }
     44 
     45     internal delegate int PollCallback (IntPtr ufds, uint nfds, int timeout);
     46     internal delegate void ClientCallback (IntPtr client, ClientState state, IntPtr userData);
     47 
     48     public delegate void ClientStateHandler (object o, ClientStateArgs state);
     49 
     50     public class ClientStateArgs : EventArgs
     51     {
     52         private ClientState state;
     53         private ErrorCode error;
     54 
     55         public ClientState State
     56         {
     57             get { return state; }
     58         }
     59 
     60         public ErrorCode Error
     61         {
     62             get { return error; }
     63         }
     64 
     65         public ClientStateArgs (ClientState state, ErrorCode error)
     66         {
     67             this.state = state;
     68             this.error = error;
     69         }
     70     }
     71 
     72     public enum Protocol {
     73         Unspecified = -1,
     74         IPv4 = 0,
     75         IPv6 = 1
     76     }
     77 
     78     internal enum ServerState {
     79         Invalid,
     80         Registering,
     81         Running,
     82         Collision
     83     }
     84 
     85     public enum ClientState {
     86         Registering = ServerState.Registering,
     87         Running = ServerState.Running,
     88         Collision = ServerState.Collision,
     89         Failure = 100,
     90         Connecting = 101
     91     }
     92 
     93     [Flags]
     94     public enum LookupFlags {
     95         None = 0,
     96         UseWideArea = 1,
     97         UseMulticast = 2,
     98 	NoTxt = 4,
     99         NoAddress = 8
    100     }
    101 
    102     [Flags]
    103     public enum LookupResultFlags {
    104         None = 0,
    105         Cached = 1,
    106         WideArea = 2,
    107         Multicast = 4,
    108         Local = 8,
    109         OurOwn = 16,
    110     }
    111 
    112     [Flags]
    113     public enum ClientFlags {
    114         None = 0,
    115         IgnoreUserConfig = 1,
    116         NoFail = 2
    117     }
    118 
    119     public class Client : IDisposable
    120     {
    121         private IntPtr handle;
    122         private ClientCallback cb;
    123         private PollCallback pollcb;
    124         private IntPtr spoll;
    125 
    126         private Thread thread;
    127 
    128         [DllImport ("avahi-client")]
    129         private static extern IntPtr avahi_client_new (IntPtr poll, ClientFlags flags, ClientCallback handler,
    130                                                        IntPtr userData, out int error);
    131 
    132         [DllImport ("avahi-client")]
    133         private static extern void avahi_client_free (IntPtr handle);
    134 
    135         [DllImport ("avahi-client")]
    136         private static extern IntPtr avahi_client_get_version_string (IntPtr handle);
    137 
    138         [DllImport ("avahi-client")]
    139         private static extern IntPtr avahi_client_get_host_name (IntPtr handle);
    140 
    141         [DllImport ("avahi-client")]
    142         private static extern IntPtr avahi_client_get_domain_name (IntPtr handle);
    143 
    144         [DllImport ("avahi-client")]
    145         private static extern IntPtr avahi_client_get_host_name_fqdn (IntPtr handle);
    146 
    147         [DllImport ("avahi-client")]
    148         private static extern ClientState avahi_client_get_state (IntPtr handle);
    149 
    150         [DllImport ("avahi-client")]
    151         private static extern int avahi_client_errno (IntPtr handle);
    152 
    153         [DllImport ("avahi-common")]
    154         private static extern IntPtr avahi_simple_poll_new ();
    155 
    156         [DllImport ("avahi-common")]
    157         private static extern IntPtr avahi_simple_poll_get (IntPtr spoll);
    158 
    159         [DllImport ("avahi-common")]
    160         private static extern void avahi_simple_poll_free (IntPtr spoll);
    161 
    162         [DllImport ("avahi-common")]
    163         private static extern int avahi_simple_poll_loop (IntPtr spoll);
    164 
    165         [DllImport ("avahi-common")]
    166         private static extern void avahi_simple_poll_set_func (IntPtr spoll, PollCallback cb);
    167 
    168         [DllImport ("avahi-common")]
    169         private static extern void avahi_simple_poll_quit (IntPtr spoll);
    170 
    171         [DllImport ("avahi-client")]
    172         private static extern uint avahi_client_get_local_service_cookie (IntPtr client);
    173 
    174         [DllImport ("avahi-common")]
    175         private static extern int avahi_service_name_join (IntPtr buf, int len, byte[] name, byte[] type,
    176                                                            byte[] domain);
    177 
    178         [DllImport ("avahi-common")]
    179         private static extern int avahi_service_name_split (byte[] service, IntPtr name, int name_len,
    180                                                             IntPtr type, int type_len,
    181                                                             IntPtr domain, int domain_len);
    182 
    183 
    184         [DllImport ("libc")]
    185         private static extern int poll(IntPtr ufds, uint nfds, int timeout);
    186 
    187         public event ClientStateHandler StateChanged;
    188 
    189         internal IntPtr Handle
    190         {
    191             get { return handle; }
    192         }
    193 
    194         public string Version
    195         {
    196             get {
    197                 lock (this) {
    198                     return Utility.PtrToString (avahi_client_get_version_string (handle));
    199                 }
    200             }
    201         }
    202 
    203         public string HostName
    204         {
    205             get {
    206                 lock (this) {
    207                     return Utility.PtrToString (avahi_client_get_host_name (handle));
    208                 }
    209             }
    210         }
    211 
    212         public string DomainName
    213         {
    214             get {
    215                 lock (this) {
    216                     return Utility.PtrToString (avahi_client_get_domain_name (handle));
    217                 }
    218             }
    219         }
    220 
    221         public string HostNameFqdn
    222         {
    223             get {
    224                 lock (this) {
    225                     return Utility.PtrToString (avahi_client_get_host_name_fqdn (handle));
    226                 }
    227             }
    228         }
    229 
    230         public ClientState State
    231         {
    232             get {
    233                 lock (this) {
    234                     return (ClientState) avahi_client_get_state (handle);
    235                 }
    236             }
    237         }
    238 
    239         public uint LocalServiceCookie
    240         {
    241             get {
    242                 lock (this) {
    243                     return avahi_client_get_local_service_cookie (handle);
    244                 }
    245             }
    246         }
    247 
    248         internal ErrorCode LastError
    249         {
    250             get {
    251                 lock (this) {
    252                     return (ErrorCode) avahi_client_errno (handle);
    253                 }
    254             }
    255         }
    256 
    257         public Client (ClientFlags flags)
    258         {
    259             spoll = avahi_simple_poll_new ();
    260 
    261             pollcb = OnPollCallback;
    262             avahi_simple_poll_set_func (spoll, pollcb);
    263             IntPtr poll = avahi_simple_poll_get (spoll);
    264             cb = OnClientCallback;
    265 
    266             int error;
    267             handle = avahi_client_new (poll, flags, cb, IntPtr.Zero, out error);
    268             if (error != 0)
    269                 throw new ClientException (error);
    270 
    271             thread = new Thread (PollLoop);
    272             thread.IsBackground = true;
    273             thread.Start ();
    274         }
    275 
    276         public Client () : this (ClientFlags.None) {
    277         }
    278 
    279         ~Client ()
    280         {
    281             Dispose ();
    282         }
    283 
    284         public void Dispose ()
    285         {
    286             if (handle != IntPtr.Zero) {
    287                 lock (this) {
    288                     avahi_client_free (handle);
    289                     handle = IntPtr.Zero;
    290 
    291                     avahi_simple_poll_quit (spoll);
    292                     Monitor.Wait (this);
    293 
    294                     avahi_simple_poll_free (spoll);
    295                 }
    296             }
    297         }
    298 
    299         public static string JoinServiceName (string name, string type, string domain)
    300         {
    301             int len = 4 * (name.Length + type.Length + domain.Length) + 4;
    302             IntPtr buf = Stdlib.malloc ((ulong) len);
    303 
    304             int ret = avahi_service_name_join (buf, len,
    305                                                Utility.StringToBytes (name),
    306                                                Utility.StringToBytes (type),
    307                                                Utility.StringToBytes (domain));
    308 
    309             if (ret < 0) {
    310                 Utility.Free (buf);
    311                 return null; // FIXME, should throw exception
    312             }
    313 
    314             string service = Utility.PtrToString (buf);
    315             Utility.Free (buf);
    316 
    317             return service;
    318         }
    319 
    320         public static void SplitServiceName (string service, out string name, out string type, out string domain)
    321         {
    322             int len = 1024;
    323 
    324             IntPtr namePtr = Stdlib.malloc ((ulong) len);
    325             IntPtr typePtr = Stdlib.malloc ((ulong) len);
    326             IntPtr domainPtr = Stdlib.malloc ((ulong) len);
    327 
    328             int ret = avahi_service_name_split (Utility.StringToBytes (service), namePtr, len, typePtr, len,
    329                                                 domainPtr, len);
    330 
    331             if (ret < 0) {
    332                 Utility.Free (namePtr);
    333                 Utility.Free (typePtr);
    334                 Utility.Free (domainPtr);
    335 
    336                 name = null;
    337                 type = null;
    338                 domain = null;
    339                 return;
    340             }
    341 
    342             name = Utility.PtrToString (namePtr);
    343             type = Utility.PtrToString (typePtr);
    344             domain = Utility.PtrToString (domainPtr);
    345 
    346             Utility.Free (namePtr);
    347             Utility.Free (typePtr);
    348             Utility.Free (domainPtr);
    349         }
    350 
    351         internal void ThrowError ()
    352         {
    353             ErrorCode error = LastError;
    354 
    355             if (error != ErrorCode.Ok)
    356                 throw new ClientException (error);
    357         }
    358 
    359         private void OnClientCallback (IntPtr client, ClientState state, IntPtr userData)
    360         {
    361             if (StateChanged != null)
    362                 StateChanged (this, new ClientStateArgs (state, LastError));
    363         }
    364 
    365         private int OnPollCallback (IntPtr ufds, uint nfds, int timeout) {
    366             Monitor.Exit (this);
    367             int result = poll (ufds, nfds, timeout);
    368             Monitor.Enter (this);
    369             return result;
    370         }
    371 
    372         private void PollLoop () {
    373             try {
    374                 lock (this) {
    375                     avahi_simple_poll_loop (spoll);
    376                     Monitor.Pulse (this);
    377                 }
    378             } catch (Exception e) {
    379                 Console.Error.WriteLine ("Error in avahi-sharp event loop: " + e);
    380             }
    381         }
    382     }
    383 }
    384