1/* $Id$ */ 2 3/*** 4 This file is part of avahi. 5 6 avahi is free software; you can redistribute it and/or modify it 7 under the terms of the GNU Lesser General Public License as 8 published by the Free Software Foundation; either version 2.1 of the 9 License, or (at your option) any later version. 10 11 avahi is distributed in the hope that it will be useful, but WITHOUT 12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 14 Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with avahi; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 19 USA. 20***/ 21 22using System; 23using System.Collections; 24using System.Net; 25using System.Runtime.InteropServices; 26using System.Text; 27using Mono.Unix; 28 29namespace Avahi 30{ 31 32 internal delegate void ServiceResolverCallback (IntPtr resolver, int iface, Protocol proto, 33 ResolverEvent revent, IntPtr name, IntPtr type, 34 IntPtr domain, IntPtr host, IntPtr address, 35 UInt16 port, IntPtr txt, LookupResultFlags flags, 36 IntPtr userdata); 37 38 public class ServiceResolver : ResolverBase, IDisposable 39 { 40 private IntPtr handle; 41 private ServiceInfo currentInfo; 42 private Client client; 43 private int iface; 44 private Protocol proto; 45 private string name; 46 private string type; 47 private string domain; 48 private Protocol aproto; 49 private LookupFlags flags; 50 private ServiceResolverCallback cb; 51 52 private ArrayList foundListeners = new ArrayList (); 53 private ArrayList timeoutListeners = new ArrayList (); 54 55 [DllImport ("avahi-client")] 56 private static extern IntPtr avahi_service_resolver_new (IntPtr client, int iface, Protocol proto, 57 byte[] name, byte[] type, byte[] domain, 58 Protocol aproto, LookupFlags flags, 59 ServiceResolverCallback cb, 60 IntPtr userdata); 61 62 [DllImport ("avahi-common")] 63 private static extern IntPtr avahi_string_list_get_next (IntPtr list); 64 65 [DllImport ("avahi-common")] 66 private static extern IntPtr avahi_string_list_get_text (IntPtr list); 67 68 [DllImport ("avahi-common")] 69 private static extern int avahi_string_list_get_size (IntPtr list); 70 71 [DllImport ("avahi-client")] 72 private static extern void avahi_service_resolver_free (IntPtr handle); 73 74 public event ServiceInfoHandler Found 75 { 76 add { 77 foundListeners.Add (value); 78 Start (); 79 } 80 remove { 81 foundListeners.Remove (value); 82 Stop (false); 83 } 84 } 85 86 public event EventHandler Timeout 87 { 88 add { 89 timeoutListeners.Add (value); 90 Start (); 91 } 92 remove { 93 timeoutListeners.Remove (value); 94 Stop (false); 95 } 96 } 97 98 public ServiceInfo Service 99 { 100 get { return currentInfo; } 101 } 102 103 public ServiceResolver (Client client, string name, string type, string domain) : this (client, -1, 104 Protocol.Unspecified, 105 name, type, domain, 106 Protocol.Unspecified, 107 LookupFlags.None) 108 { 109 } 110 111 public ServiceResolver (Client client, ServiceInfo service) : this (client, service.NetworkInterface, 112 service.Protocol, service.Name, 113 service.ServiceType, service.Domain, 114 Protocol.Unspecified, 115 GetLookupFlags (service.Flags)) 116 { 117 } 118 119 public ServiceResolver (Client client, int iface, Protocol proto, string name, 120 string type, string domain, Protocol aproto, LookupFlags flags) 121 { 122 this.client = client; 123 this.iface = iface; 124 this.proto = proto; 125 this.name = name; 126 this.type = type; 127 this.domain = domain; 128 this.aproto = aproto; 129 this.flags = flags; 130 cb = OnServiceResolverCallback; 131 } 132 133 ~ServiceResolver () 134 { 135 Dispose (); 136 } 137 138 public void Dispose () 139 { 140 Stop (true); 141 } 142 143 private void Start () 144 { 145 if (client.Handle == IntPtr.Zero || handle != IntPtr.Zero || 146 (foundListeners.Count == 0 && timeoutListeners.Count == 0)) 147 return; 148 149 lock (client) { 150 handle = avahi_service_resolver_new (client.Handle, iface, proto, 151 Utility.StringToBytes (name), Utility.StringToBytes (type), 152 Utility.StringToBytes (domain), aproto, flags, cb, IntPtr.Zero); 153 154 if (handle == IntPtr.Zero) 155 client.ThrowError (); 156 } 157 } 158 159 private void Stop (bool force) 160 { 161 if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero && 162 (force || (foundListeners.Count == 0 && timeoutListeners.Count == 0))) { 163 164 lock (client) { 165 avahi_service_resolver_free (handle); 166 handle = IntPtr.Zero; 167 } 168 } 169 } 170 171 private void OnServiceResolverCallback (IntPtr resolver, int iface, Protocol proto, 172 ResolverEvent revent, IntPtr name, IntPtr type, 173 IntPtr domain, IntPtr host, IntPtr address, 174 UInt16 port, IntPtr txt, LookupResultFlags flags, 175 IntPtr userdata) 176 { 177 ServiceInfo info; 178 info.NetworkInterface = iface; 179 info.Protocol = proto; 180 info.Domain = Utility.PtrToString (domain); 181 info.ServiceType = Utility.PtrToString (type); 182 info.Name = Utility.PtrToString (name); 183 info.HostName = Utility.PtrToString (host); 184 info.Address = Utility.PtrToAddress (address); 185 info.Port = port; 186 187 if (proto == Protocol.IPv6) 188 info.Address.ScopeId = iface; 189 190 ArrayList txtlist = new ArrayList (); 191 for (IntPtr l = txt; l != IntPtr.Zero; l = avahi_string_list_get_next (l)) { 192 IntPtr buf = avahi_string_list_get_text (l); 193 int len = avahi_string_list_get_size (l); 194 195 byte[] txtbuf = new byte[len]; 196 Marshal.Copy (buf, txtbuf, 0, len); 197 txtlist.Add (txtbuf); 198 } 199 200 info.Text = (byte[][]) txtlist.ToArray (typeof (byte[])); 201 info.Flags = flags; 202 203 switch (revent) { 204 case ResolverEvent.Found: 205 currentInfo = info; 206 207 foreach (ServiceInfoHandler handler in foundListeners) 208 handler (this, new ServiceInfoArgs (info)); 209 break; 210 case ResolverEvent.Failure: 211 EmitFailure (client.LastError); 212 break; 213 } 214 } 215 216 private static LookupFlags GetLookupFlags (LookupResultFlags rflags) { 217 LookupFlags ret = LookupFlags.None; 218 219 if ((rflags & LookupResultFlags.Multicast) > 0) 220 ret |= LookupFlags.UseMulticast; 221 if ((rflags & LookupResultFlags.WideArea) > 0) 222 ret |= LookupFlags.UseWideArea; 223 224 return ret; 225 } 226 } 227} 228