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