• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PollCallback(IntPtr ufds, uint nfds, int timeout)45     internal delegate int PollCallback (IntPtr ufds, uint nfds, int timeout);
ClientCallback(IntPtr client, ClientState state, IntPtr userData)46     internal delegate void ClientCallback (IntPtr client, ClientState state, IntPtr userData);
47 
ClientStateHandler(object o, ClientStateArgs state)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 
ClientStateArgs(ClientState state, ErrorCode error)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")]
avahi_client_new(IntPtr poll, ClientFlags flags, ClientCallback handler, IntPtr userData, out int error)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")]
avahi_client_free(IntPtr handle)133         private static extern void avahi_client_free (IntPtr handle);
134 
135         [DllImport ("avahi-client")]
avahi_client_get_version_string(IntPtr handle)136         private static extern IntPtr avahi_client_get_version_string (IntPtr handle);
137 
138         [DllImport ("avahi-client")]
avahi_client_get_host_name(IntPtr handle)139         private static extern IntPtr avahi_client_get_host_name (IntPtr handle);
140 
141         [DllImport ("avahi-client")]
avahi_client_get_domain_name(IntPtr handle)142         private static extern IntPtr avahi_client_get_domain_name (IntPtr handle);
143 
144         [DllImport ("avahi-client")]
avahi_client_get_host_name_fqdn(IntPtr handle)145         private static extern IntPtr avahi_client_get_host_name_fqdn (IntPtr handle);
146 
147         [DllImport ("avahi-client")]
avahi_client_get_state(IntPtr handle)148         private static extern ClientState avahi_client_get_state (IntPtr handle);
149 
150         [DllImport ("avahi-client")]
avahi_client_errno(IntPtr handle)151         private static extern int avahi_client_errno (IntPtr handle);
152 
153         [DllImport ("avahi-common")]
avahi_simple_poll_new()154         private static extern IntPtr avahi_simple_poll_new ();
155 
156         [DllImport ("avahi-common")]
avahi_simple_poll_get(IntPtr spoll)157         private static extern IntPtr avahi_simple_poll_get (IntPtr spoll);
158 
159         [DllImport ("avahi-common")]
avahi_simple_poll_free(IntPtr spoll)160         private static extern void avahi_simple_poll_free (IntPtr spoll);
161 
162         [DllImport ("avahi-common")]
avahi_simple_poll_loop(IntPtr spoll)163         private static extern int avahi_simple_poll_loop (IntPtr spoll);
164 
165         [DllImport ("avahi-common")]
avahi_simple_poll_set_func(IntPtr spoll, PollCallback cb)166         private static extern void avahi_simple_poll_set_func (IntPtr spoll, PollCallback cb);
167 
168         [DllImport ("avahi-common")]
avahi_simple_poll_quit(IntPtr spoll)169         private static extern void avahi_simple_poll_quit (IntPtr spoll);
170 
171         [DllImport ("avahi-client")]
avahi_client_get_local_service_cookie(IntPtr client)172         private static extern uint avahi_client_get_local_service_cookie (IntPtr client);
173 
174         [DllImport ("avahi-common")]
avahi_service_name_join(IntPtr buf, int len, byte[] name, byte[] type, byte[] domain)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")]
avahi_service_name_split(byte[] service, IntPtr name, int name_len, IntPtr type, int type_len, IntPtr domain, int domain_len)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")]
poll(IntPtr ufds, uint nfds, int timeout)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 
Client(ClientFlags flags)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 
Client()276         public Client () : this (ClientFlags.None) {
277         }
278 
~Client()279         ~Client ()
280         {
281             Dispose ();
282         }
283 
Dispose()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 
JoinServiceName(string name, string type, string domain)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 
SplitServiceName(string service, out string name, out string type, out string domain)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 
ThrowError()351         internal void ThrowError ()
352         {
353             ErrorCode error = LastError;
354 
355             if (error != ErrorCode.Ok)
356                 throw new ClientException (error);
357         }
358 
OnClientCallback(IntPtr client, ClientState state, IntPtr userData)359         private void OnClientCallback (IntPtr client, ClientState state, IntPtr userData)
360         {
361             if (StateChanged != null)
362                 StateChanged (this, new ClientStateArgs (state, LastError));
363         }
364 
OnPollCallback(IntPtr ufds, uint nfds, int timeout)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 
PollLoop()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