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