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