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 using System;
21 using System.Net;
22 using System.Collections;
23 using System.Runtime.InteropServices;
24 using System.Text;
25 
26 namespace Avahi
27 {
ServiceBrowserCallback(IntPtr browser, int iface, Protocol proto, BrowserEvent bevent, IntPtr name, IntPtr type, IntPtr domain, LookupResultFlags flags, IntPtr userdata)28     internal delegate void ServiceBrowserCallback (IntPtr browser, int iface, Protocol proto, BrowserEvent bevent,
29                                                    IntPtr name, IntPtr type, IntPtr domain, LookupResultFlags flags,
30                                                    IntPtr userdata);
31 
32     public struct ServiceInfo
33     {
34         public int NetworkInterface;
35         public Protocol Protocol;
36         public string Domain;
37         public string ServiceType;
38         public string Name;
39 
40         public string HostName;
41         public IPAddress Address;
42         public UInt16 Port;
43         public byte[][] Text;
44         public LookupResultFlags Flags;
45 
46         public static ServiceInfo Zero = new ServiceInfo ();
47     }
48 
49     public class ServiceInfoArgs : EventArgs
50     {
51         private ServiceInfo service;
52 
53         public ServiceInfo Service {
54             get { return service; }
55         }
56 
ServiceInfoArgs(ServiceInfo service)57         public ServiceInfoArgs (ServiceInfo service)
58         {
59             this.service = service;
60         }
61     }
62 
ServiceInfoHandler(object o, ServiceInfoArgs args)63     public delegate void ServiceInfoHandler (object o, ServiceInfoArgs args);
64 
65     public class ServiceBrowser : BrowserBase, IDisposable
66     {
67         private IntPtr handle;
68         private ArrayList infos = new ArrayList ();
69         private Client client;
70         private int iface;
71         private Protocol proto;
72         private string domain;
73         private string type;
74         private LookupFlags flags;
75         private ServiceBrowserCallback cb;
76 
77         private ArrayList addListeners = new ArrayList ();
78         private ArrayList removeListeners = new ArrayList ();
79 
80         [DllImport ("avahi-client")]
avahi_service_browser_new(IntPtr client, int iface, int proto, byte[] type, byte[] domain, LookupFlags flags, ServiceBrowserCallback cb, IntPtr userdata)81         private static extern IntPtr avahi_service_browser_new (IntPtr client, int iface, int proto, byte[] type,
82                                                                 byte[] domain, LookupFlags flags,
83                                                                 ServiceBrowserCallback cb,
84                                                                 IntPtr userdata);
85 
86         [DllImport ("avahi-client")]
avahi_service_browser_free(IntPtr handle)87         private static extern void avahi_service_browser_free (IntPtr handle);
88 
89         public event ServiceInfoHandler ServiceAdded
90         {
91             add {
92                 addListeners.Add (value);
93                 Start ();
94             }
95             remove {
96                 addListeners.Remove (value);
97                 Stop (false);
98             }
99         }
100 
101         public event ServiceInfoHandler ServiceRemoved
102         {
103             add {
104                 removeListeners.Add (value);
105                 Start ();
106             }
107             remove {
108                 removeListeners.Remove (value);
109                 Stop (false);
110             }
111         }
112 
113         public ServiceInfo[] Services
114         {
115             get { return (ServiceInfo[]) infos.ToArray (typeof (ServiceInfo)); }
116         }
117 
ServiceBrowser(Client client, string type)118         public ServiceBrowser (Client client, string type) : this (client, type, client.DomainName)
119         {
120         }
121 
ServiceBrowser(Client client, string type, string domain)122         public ServiceBrowser (Client client, string type, string domain) : this (client, -1, Protocol.Unspecified,
123                                                                                   type, domain, LookupFlags.None)
124         {
125         }
126 
ServiceBrowser(Client client, int iface, Protocol proto, string type, string domain, LookupFlags flags)127         public ServiceBrowser (Client client, int iface, Protocol proto, string type, string domain, LookupFlags flags)
128         {
129             this.client = client;
130             this.iface = iface;
131             this.proto = proto;
132             this.domain = domain;
133             this.type = type;
134             this.flags = flags;
135             cb = OnServiceBrowserCallback;
136         }
137 
~ServiceBrowser()138         ~ServiceBrowser ()
139         {
140             Dispose ();
141         }
142 
Dispose()143         public void Dispose ()
144         {
145             Stop (true);
146         }
147 
Start()148         private void Start ()
149         {
150             if (client.Handle == IntPtr.Zero || handle != IntPtr.Zero ||
151                 (addListeners.Count == 0 && removeListeners.Count == 0))
152                 return;
153 
154             lock (client) {
155                 handle = avahi_service_browser_new (client.Handle, iface, (int) proto,
156                                                     Utility.StringToBytes (type), Utility.StringToBytes (domain),
157                                                     flags, cb, IntPtr.Zero);
158 
159                 if (handle == IntPtr.Zero)
160                     client.ThrowError ();
161             }
162         }
163 
Stop(bool force)164         private void Stop (bool force)
165         {
166             if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero &&
167                 (force || (addListeners.Count == 0 && removeListeners.Count == 0))) {
168 
169                 lock (client) {
170                     avahi_service_browser_free (handle);
171                     handle = IntPtr.Zero;
172                 }
173             }
174         }
175 
OnServiceBrowserCallback(IntPtr browser, int iface, Protocol proto, BrowserEvent bevent, IntPtr name, IntPtr type, IntPtr domain, LookupResultFlags flags, IntPtr userdata)176         private void OnServiceBrowserCallback (IntPtr browser, int iface, Protocol proto, BrowserEvent bevent,
177                                                IntPtr name, IntPtr type, IntPtr domain, LookupResultFlags flags,
178                                                IntPtr userdata)
179         {
180 
181             ServiceInfo info;
182             info.NetworkInterface = iface;
183             info.Protocol = proto;
184             info.Domain = Utility.PtrToString (domain);
185             info.ServiceType = Utility.PtrToString (type);
186             info.Name = Utility.PtrToString (name);
187             info.HostName = null;
188             info.Address = null;
189             info.Port = 0;
190             info.Text = null;
191             info.Flags = flags;
192 
193             switch (bevent) {
194             case BrowserEvent.Added:
195                 infos.Add (info);
196 
197                 foreach (ServiceInfoHandler handler in addListeners)
198                     handler (this, new ServiceInfoArgs (info));
199 
200                 break;
201             case BrowserEvent.Removed:
202                 infos.Remove (info);
203 
204                 foreach (ServiceInfoHandler handler in removeListeners)
205                     handler (this, new ServiceInfoArgs (info));
206 
207                 break;
208             default:
209                 EmitBrowserEvent (bevent);
210                 break;
211             }
212         }
213     }
214 }
215