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.Runtime.InteropServices; 23 using System.Text; 24 using Mono.Unix; 25 26 namespace Avahi 27 { 28 29 [Flags] 30 public enum PublishFlags { 31 None = 0, 32 Unique = 1, 33 NoProbe = 2, 34 NoAnnounce = 4, 35 AllowMultiple = 8, 36 NoReverse = 16, 37 NoCookie = 32, 38 Update = 64, 39 UseWideArea = 128, 40 UseMulticast = 256 41 } 42 43 public enum EntryGroupState { 44 Uncommited, 45 Registering, 46 Established, 47 Collision, 48 Failure 49 } 50 51 public class EntryGroupStateArgs : EventArgs 52 { 53 private EntryGroupState state; 54 55 public EntryGroupState State 56 { 57 get { return state; } 58 } 59 EntryGroupStateArgs(EntryGroupState state)60 public EntryGroupStateArgs (EntryGroupState state) 61 { 62 this.state = state; 63 } 64 } 65 EntryGroupCallback(IntPtr group, EntryGroupState state, IntPtr userdata)66 internal delegate void EntryGroupCallback (IntPtr group, EntryGroupState state, IntPtr userdata); EntryGroupStateHandler(object o, EntryGroupStateArgs args)67 public delegate void EntryGroupStateHandler (object o, EntryGroupStateArgs args); 68 69 public class EntryGroup : IDisposable 70 { 71 private Client client; 72 private IntPtr handle; 73 private EntryGroupCallback cb; 74 75 [DllImport ("avahi-client")] avahi_entry_group_new(IntPtr client, EntryGroupCallback cb, IntPtr userdata)76 private static extern IntPtr avahi_entry_group_new (IntPtr client, EntryGroupCallback cb, IntPtr userdata); 77 78 [DllImport ("avahi-client")] avahi_entry_group_commit(IntPtr group)79 private static extern int avahi_entry_group_commit (IntPtr group); 80 81 [DllImport ("avahi-client")] avahi_entry_group_reset(IntPtr group)82 private static extern int avahi_entry_group_reset (IntPtr group); 83 84 [DllImport ("avahi-client")] avahi_entry_group_get_state(IntPtr group)85 private static extern EntryGroupState avahi_entry_group_get_state (IntPtr group); 86 87 [DllImport ("avahi-client")] avahi_entry_group_is_empty(IntPtr group)88 private static extern bool avahi_entry_group_is_empty (IntPtr group); 89 90 [DllImport ("avahi-client")] avahi_entry_group_add_service_strlst(IntPtr group, int iface, Protocol proto, PublishFlags flags, byte[] name, byte[] type, byte[] domain, byte[] host, UInt16 port, IntPtr strlst)91 private static extern int avahi_entry_group_add_service_strlst (IntPtr group, int iface, Protocol proto, 92 PublishFlags flags, byte[] name, byte[] type, 93 byte[] domain, byte[] host, UInt16 port, 94 IntPtr strlst); 95 96 [DllImport ("avahi-client")] avahi_entry_group_update_service_strlst(IntPtr group, int iface, Protocol proto, PublishFlags flags, byte[] name, byte[] type, byte[] domain, IntPtr strlst)97 private static extern int avahi_entry_group_update_service_strlst (IntPtr group, int iface, Protocol proto, 98 PublishFlags flags, byte[] name, 99 byte[] type, byte[] domain, IntPtr strlst); 100 101 [DllImport ("avahi-client")] avahi_entry_group_add_service_subtype(IntPtr group, int iface, Protocol proto, PublishFlags flags, byte[] name, byte[] type, byte[] domain, byte[] subtype)102 private static extern int avahi_entry_group_add_service_subtype (IntPtr group, int iface, Protocol proto, 103 PublishFlags flags, byte[] name, byte[] type, 104 byte[] domain, byte[] subtype); 105 106 [DllImport ("avahi-client")] avahi_entry_group_add_address(IntPtr group, int iface, Protocol proto, PublishFlags flags, byte[] name, IntPtr address)107 private static extern int avahi_entry_group_add_address (IntPtr group, int iface, Protocol proto, 108 PublishFlags flags, byte[] name, IntPtr address); 109 110 111 [DllImport ("avahi-client")] avahi_entry_group_add_record(IntPtr group, int iface, Protocol proto, PublishFlags flags, byte[] name, RecordClass clazz, RecordType type, uint ttl, byte[] rdata, int size)112 private static extern int avahi_entry_group_add_record (IntPtr group, int iface, Protocol proto, 113 PublishFlags flags, byte[] name, RecordClass clazz, 114 RecordType type, uint ttl, byte[] rdata, int size); 115 116 [DllImport ("avahi-client")] avahi_entry_group_free(IntPtr group)117 private static extern void avahi_entry_group_free (IntPtr group); 118 119 [DllImport ("avahi-common")] avahi_string_list_new(IntPtr txt)120 private static extern IntPtr avahi_string_list_new (IntPtr txt); 121 122 [DllImport ("avahi-common")] avahi_string_list_add(IntPtr list, byte[] txt)123 private static extern IntPtr avahi_string_list_add (IntPtr list, byte[] txt); 124 125 [DllImport ("avahi-common")] avahi_string_list_free(IntPtr list)126 private static extern void avahi_string_list_free (IntPtr list); 127 128 [DllImport ("avahi-common")] avahi_alternative_service_name(byte[] name)129 private static extern IntPtr avahi_alternative_service_name (byte[] name); 130 131 public event EntryGroupStateHandler StateChanged; 132 133 public EntryGroupState State 134 { 135 get { 136 lock (client) { 137 return avahi_entry_group_get_state (handle); 138 } 139 } 140 } 141 142 public bool IsEmpty 143 { 144 get { 145 lock (client) { 146 return avahi_entry_group_is_empty (handle); 147 } 148 } 149 } 150 EntryGroup(Client client)151 public EntryGroup (Client client) 152 { 153 this.client = client; 154 cb = OnEntryGroupCallback; 155 156 lock (client) { 157 handle = avahi_entry_group_new (client.Handle, cb, IntPtr.Zero); 158 if (handle == IntPtr.Zero) 159 client.ThrowError (); 160 } 161 } 162 ~EntryGroup()163 ~EntryGroup () 164 { 165 Dispose (); 166 } 167 Dispose()168 public void Dispose () 169 { 170 if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero) { 171 lock (client) { 172 avahi_entry_group_free (handle); 173 handle = IntPtr.Zero; 174 } 175 } 176 } 177 Commit()178 public void Commit () 179 { 180 lock (client) { 181 if (avahi_entry_group_commit (handle) < 0) 182 client.ThrowError (); 183 } 184 } 185 Reset()186 public void Reset () 187 { 188 lock (client) { 189 if (avahi_entry_group_reset (handle) < 0) 190 client.ThrowError (); 191 } 192 } 193 AddService(string name, string type, string domain, UInt16 port, params string[] txt)194 public void AddService (string name, string type, string domain, 195 UInt16 port, params string[] txt) 196 { 197 AddService (PublishFlags.None, name, type, domain, port, txt); 198 } 199 AddService(PublishFlags flags, string name, string type, string domain, UInt16 port, params string[] txt)200 public void AddService (PublishFlags flags, string name, string type, string domain, 201 UInt16 port, params string[] txt) 202 { 203 AddService (-1, Protocol.Unspecified, flags, name, type, domain, null, port, txt); 204 } 205 AddService(int iface, Protocol proto, PublishFlags flags, string name, string type, string domain, string host, UInt16 port, params string[] txt)206 public void AddService (int iface, Protocol proto, PublishFlags flags, string name, string type, string domain, 207 string host, UInt16 port, params string[] txt) 208 { 209 IntPtr list = avahi_string_list_new (IntPtr.Zero); 210 211 if (txt != null) { 212 foreach (string item in txt) { 213 list = avahi_string_list_add (list, Utility.StringToBytes (item)); 214 } 215 } 216 217 AddService (iface, proto, flags, name, type, domain, host, port, list); 218 } 219 AddService(int iface, Protocol proto, PublishFlags flags, string name, string type, string domain, string host, UInt16 port, params byte[][] txt)220 public void AddService (int iface, Protocol proto, PublishFlags flags, string name, string type, string domain, 221 string host, UInt16 port, params byte[][] txt) 222 { 223 IntPtr list = avahi_string_list_new (IntPtr.Zero); 224 225 if (txt != null) { 226 foreach (byte[] item in txt) { 227 list = avahi_string_list_add (list, item); 228 } 229 } 230 231 AddService (iface, proto, flags, name, type, domain, host, port, list); 232 } 233 AddService(int iface, Protocol proto, PublishFlags flags, string name, string type, string domain, string host, UInt16 port, IntPtr list)234 private void AddService (int iface, Protocol proto, PublishFlags flags, string name, string type, 235 string domain, string host, UInt16 port, IntPtr list) 236 { 237 int ret; 238 239 lock (client) { 240 ret = avahi_entry_group_add_service_strlst (handle, iface, proto, flags, 241 Utility.StringToBytes (name), 242 Utility.StringToBytes (type), 243 Utility.StringToBytes (domain), 244 Utility.StringToBytes (host), port, list); 245 } 246 247 avahi_string_list_free (list); 248 249 if (ret < 0) { 250 client.ThrowError (); 251 } 252 } 253 UpdateService(string name, string type, string domain, params string[] txt)254 public void UpdateService (string name, string type, string domain, params string[] txt) 255 { 256 UpdateService (-1, Protocol.Unspecified, PublishFlags.None, name, type, domain, txt); 257 } 258 UpdateService(int iface, Protocol proto, PublishFlags flags, string name, string type, string domain, params string[] txt)259 public void UpdateService (int iface, Protocol proto, PublishFlags flags, string name, string type, 260 string domain, params string[] txt) 261 { 262 IntPtr list = avahi_string_list_new (IntPtr.Zero); 263 264 if (txt != null) { 265 foreach (string item in txt) { 266 list = avahi_string_list_add (list, Utility.StringToBytes (item)); 267 } 268 } 269 270 UpdateService (iface, proto, flags, name, type, domain, list); 271 } 272 UpdateService(int iface, Protocol proto, PublishFlags flags, string name, string type, string domain, params byte[][] txt)273 public void UpdateService (int iface, Protocol proto, PublishFlags flags, string name, string type, 274 string domain, params byte[][] txt) 275 { 276 IntPtr list = avahi_string_list_new (IntPtr.Zero); 277 278 if (txt != null) { 279 foreach (byte[] item in txt) { 280 list = avahi_string_list_add (list, item); 281 } 282 } 283 284 UpdateService (iface, proto, flags, name, type, domain, list); 285 } 286 UpdateService(int iface, Protocol proto, PublishFlags flags, string name, string type, string domain, IntPtr list)287 private void UpdateService (int iface, Protocol proto, PublishFlags flags, string name, string type, 288 string domain, IntPtr list) 289 { 290 lock (client) { 291 int ret = avahi_entry_group_update_service_strlst (handle, iface, proto, flags, 292 Utility.StringToBytes (name), 293 Utility.StringToBytes (type), 294 Utility.StringToBytes (domain), 295 list); 296 297 avahi_string_list_free (list); 298 299 if (ret < 0) { 300 client.ThrowError (); 301 } 302 } 303 } 304 AddServiceSubtype(string name, string type, string domain, string subtype)305 public void AddServiceSubtype (string name, string type, string domain, string subtype) 306 { 307 AddServiceSubtype (-1, Protocol.Unspecified, PublishFlags.None, name, type, domain, subtype); 308 } 309 AddServiceSubtype(int iface, Protocol proto, PublishFlags flags, string name, string type, string domain, string subtype)310 public void AddServiceSubtype (int iface, Protocol proto, PublishFlags flags, string name, 311 string type, string domain, string subtype) 312 { 313 lock (client) { 314 int ret = avahi_entry_group_add_service_subtype (handle, iface, proto, flags, 315 Utility.StringToBytes (name), 316 Utility.StringToBytes (type), 317 Utility.StringToBytes (domain), 318 Utility.StringToBytes (subtype)); 319 320 if (ret < 0) { 321 client.ThrowError (); 322 } 323 } 324 } 325 AddAddress(string name, IPAddress address)326 public void AddAddress (string name, IPAddress address) 327 { 328 AddAddress (-1, Protocol.Unspecified, PublishFlags.None, name, address); 329 } 330 AddAddress(int iface, Protocol proto, PublishFlags flags, string name, IPAddress address)331 public void AddAddress (int iface, Protocol proto, PublishFlags flags, string name, IPAddress address) 332 { 333 IntPtr addressPtr = Utility.AddressToPtr (address); 334 335 lock (client) { 336 int ret = avahi_entry_group_add_address (handle, iface, proto, flags, 337 Utility.StringToBytes (name), addressPtr); 338 339 Utility.Free (addressPtr); 340 341 if (ret < 0) { 342 client.ThrowError (); 343 } 344 } 345 } 346 AddRecord(string name, RecordClass clazz, RecordType type, uint ttl, byte[] rdata, int length)347 public void AddRecord (string name, RecordClass clazz, RecordType type, uint ttl, byte[] rdata, int length) 348 { 349 AddRecord (-1, Protocol.Unspecified, PublishFlags.None, name, clazz, type, ttl, rdata, length); 350 } 351 AddRecord(int iface, Protocol proto, PublishFlags flags, string name, RecordClass clazz, RecordType type, uint ttl, byte[] rdata, int length)352 public void AddRecord (int iface, Protocol proto, PublishFlags flags, string name, 353 RecordClass clazz, RecordType type, uint ttl, byte[] rdata, int length) 354 { 355 lock (client) { 356 int ret = avahi_entry_group_add_record (handle, iface, proto, flags, 357 Utility.StringToBytes (name), 358 clazz, type, ttl, rdata, length); 359 360 if (ret < 0) { 361 client.ThrowError (); 362 } 363 } 364 } 365 GetAlternativeServiceName(string name)366 public static string GetAlternativeServiceName (string name) { 367 return Utility.PtrToStringFree (avahi_alternative_service_name (Utility.StringToBytes (name))); 368 } 369 OnEntryGroupCallback(IntPtr group, EntryGroupState state, IntPtr userdata)370 private void OnEntryGroupCallback (IntPtr group, EntryGroupState state, IntPtr userdata) 371 { 372 if (StateChanged != null) 373 StateChanged (this, new EntryGroupStateArgs (state)); 374 } 375 } 376 } 377