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.Net; 23 using System.Runtime.InteropServices; 24 using System.Text; 25 using Mono.Unix; 26 27 namespace Avahi 28 { 29 ServiceResolverCallback(IntPtr resolver, int iface, Protocol proto, ResolverEvent revent, IntPtr name, IntPtr type, IntPtr domain, IntPtr host, IntPtr address, UInt16 port, IntPtr txt, LookupResultFlags flags, IntPtr userdata)30 internal delegate void ServiceResolverCallback (IntPtr resolver, int iface, Protocol proto, 31 ResolverEvent revent, IntPtr name, IntPtr type, 32 IntPtr domain, IntPtr host, IntPtr address, 33 UInt16 port, IntPtr txt, LookupResultFlags flags, 34 IntPtr userdata); 35 36 public class ServiceResolver : ResolverBase, IDisposable 37 { 38 private IntPtr handle; 39 private ServiceInfo currentInfo; 40 private Client client; 41 private int iface; 42 private Protocol proto; 43 private string name; 44 private string type; 45 private string domain; 46 private Protocol aproto; 47 private LookupFlags flags; 48 private ServiceResolverCallback cb; 49 50 private ArrayList foundListeners = new ArrayList (); 51 private ArrayList timeoutListeners = new ArrayList (); 52 53 [DllImport ("avahi-client")] avahi_service_resolver_new(IntPtr client, int iface, Protocol proto, byte[] name, byte[] type, byte[] domain, Protocol aproto, LookupFlags flags, ServiceResolverCallback cb, IntPtr userdata)54 private static extern IntPtr avahi_service_resolver_new (IntPtr client, int iface, Protocol proto, 55 byte[] name, byte[] type, byte[] domain, 56 Protocol aproto, LookupFlags flags, 57 ServiceResolverCallback cb, 58 IntPtr userdata); 59 60 [DllImport ("avahi-common")] avahi_string_list_get_next(IntPtr list)61 private static extern IntPtr avahi_string_list_get_next (IntPtr list); 62 63 [DllImport ("avahi-common")] avahi_string_list_get_text(IntPtr list)64 private static extern IntPtr avahi_string_list_get_text (IntPtr list); 65 66 [DllImport ("avahi-common")] avahi_string_list_get_size(IntPtr list)67 private static extern int avahi_string_list_get_size (IntPtr list); 68 69 [DllImport ("avahi-client")] avahi_service_resolver_free(IntPtr handle)70 private static extern void avahi_service_resolver_free (IntPtr handle); 71 72 public event ServiceInfoHandler Found 73 { 74 add { 75 foundListeners.Add (value); 76 Start (); 77 } 78 remove { 79 foundListeners.Remove (value); 80 Stop (false); 81 } 82 } 83 84 public event EventHandler Timeout 85 { 86 add { 87 timeoutListeners.Add (value); 88 Start (); 89 } 90 remove { 91 timeoutListeners.Remove (value); 92 Stop (false); 93 } 94 } 95 96 public ServiceInfo Service 97 { 98 get { return currentInfo; } 99 } 100 ServiceResolver(Client client, string name, string type, string domain)101 public ServiceResolver (Client client, string name, string type, string domain) : this (client, -1, 102 Protocol.Unspecified, 103 name, type, domain, 104 Protocol.Unspecified, 105 LookupFlags.None) 106 { 107 } 108 ServiceResolver(Client client, ServiceInfo service)109 public ServiceResolver (Client client, ServiceInfo service) : this (client, service.NetworkInterface, 110 service.Protocol, service.Name, 111 service.ServiceType, service.Domain, 112 Protocol.Unspecified, 113 GetLookupFlags (service.Flags)) 114 { 115 } 116 ServiceResolver(Client client, int iface, Protocol proto, string name, string type, string domain, Protocol aproto, LookupFlags flags)117 public ServiceResolver (Client client, int iface, Protocol proto, string name, 118 string type, string domain, Protocol aproto, LookupFlags flags) 119 { 120 this.client = client; 121 this.iface = iface; 122 this.proto = proto; 123 this.name = name; 124 this.type = type; 125 this.domain = domain; 126 this.aproto = aproto; 127 this.flags = flags; 128 cb = OnServiceResolverCallback; 129 } 130 ~ServiceResolver()131 ~ServiceResolver () 132 { 133 Dispose (); 134 } 135 Dispose()136 public void Dispose () 137 { 138 Stop (true); 139 } 140 Start()141 private void Start () 142 { 143 if (client.Handle == IntPtr.Zero || handle != IntPtr.Zero || 144 (foundListeners.Count == 0 && timeoutListeners.Count == 0)) 145 return; 146 147 lock (client) { 148 handle = avahi_service_resolver_new (client.Handle, iface, proto, 149 Utility.StringToBytes (name), Utility.StringToBytes (type), 150 Utility.StringToBytes (domain), aproto, flags, cb, IntPtr.Zero); 151 152 if (handle == IntPtr.Zero) 153 client.ThrowError (); 154 } 155 } 156 Stop(bool force)157 private void Stop (bool force) 158 { 159 if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero && 160 (force || (foundListeners.Count == 0 && timeoutListeners.Count == 0))) { 161 162 lock (client) { 163 avahi_service_resolver_free (handle); 164 handle = IntPtr.Zero; 165 } 166 } 167 } 168 OnServiceResolverCallback(IntPtr resolver, int iface, Protocol proto, ResolverEvent revent, IntPtr name, IntPtr type, IntPtr domain, IntPtr host, IntPtr address, UInt16 port, IntPtr txt, LookupResultFlags flags, IntPtr userdata)169 private void OnServiceResolverCallback (IntPtr resolver, int iface, Protocol proto, 170 ResolverEvent revent, IntPtr name, IntPtr type, 171 IntPtr domain, IntPtr host, IntPtr address, 172 UInt16 port, IntPtr txt, LookupResultFlags flags, 173 IntPtr userdata) 174 { 175 ServiceInfo info; 176 info.NetworkInterface = iface; 177 info.Protocol = proto; 178 info.Domain = Utility.PtrToString (domain); 179 info.ServiceType = Utility.PtrToString (type); 180 info.Name = Utility.PtrToString (name); 181 info.HostName = Utility.PtrToString (host); 182 info.Address = Utility.PtrToAddress (address); 183 info.Port = port; 184 185 if (proto == Protocol.IPv6) 186 info.Address.ScopeId = iface; 187 188 ArrayList txtlist = new ArrayList (); 189 for (IntPtr l = txt; l != IntPtr.Zero; l = avahi_string_list_get_next (l)) { 190 IntPtr buf = avahi_string_list_get_text (l); 191 int len = avahi_string_list_get_size (l); 192 193 byte[] txtbuf = new byte[len]; 194 Marshal.Copy (buf, txtbuf, 0, len); 195 txtlist.Add (txtbuf); 196 } 197 198 info.Text = (byte[][]) txtlist.ToArray (typeof (byte[])); 199 info.Flags = flags; 200 201 switch (revent) { 202 case ResolverEvent.Found: 203 currentInfo = info; 204 205 foreach (ServiceInfoHandler handler in foundListeners) 206 handler (this, new ServiceInfoArgs (info)); 207 break; 208 case ResolverEvent.Failure: 209 EmitFailure (client.LastError); 210 break; 211 } 212 } 213 GetLookupFlags(LookupResultFlags rflags)214 private static LookupFlags GetLookupFlags (LookupResultFlags rflags) { 215 LookupFlags ret = LookupFlags.None; 216 217 if ((rflags & LookupResultFlags.Multicast) > 0) 218 ret |= LookupFlags.UseMulticast; 219 if ((rflags & LookupResultFlags.WideArea) > 0) 220 ret |= LookupFlags.UseWideArea; 221 222 return ret; 223 } 224 } 225 } 226