summaryrefslogtreecommitdiffstats
path: root/trunk/avahi-sharp/Client.cs
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/avahi-sharp/Client.cs')
-rw-r--r--trunk/avahi-sharp/Client.cs385
1 files changed, 385 insertions, 0 deletions
diff --git a/trunk/avahi-sharp/Client.cs b/trunk/avahi-sharp/Client.cs
new file mode 100644
index 0000000..02763d4
--- /dev/null
+++ b/trunk/avahi-sharp/Client.cs
@@ -0,0 +1,385 @@
+/* $Id$ */
+
+/***
+ This file is part of avahi.
+
+ avahi is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ avahi is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+ Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with avahi; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+
+using System;
+using System.Threading;
+using System.Collections;
+using System.Runtime.InteropServices;
+using Mono.Unix;
+using Mono.Unix.Native;
+
+using Stdlib = Mono.Unix.Native.Stdlib;
+
+namespace Avahi
+{
+ internal enum ResolverEvent {
+ Found,
+ Failure
+ }
+
+ internal enum BrowserEvent {
+ Added,
+ Removed,
+ CacheExhausted,
+ AllForNow,
+ Failure
+ }
+
+ internal delegate int PollCallback (IntPtr ufds, uint nfds, int timeout);
+ internal delegate void ClientCallback (IntPtr client, ClientState state, IntPtr userData);
+
+ public delegate void ClientStateHandler (object o, ClientStateArgs state);
+
+ public class ClientStateArgs : EventArgs
+ {
+ private ClientState state;
+ private ErrorCode error;
+
+ public ClientState State
+ {
+ get { return state; }
+ }
+
+ public ErrorCode Error
+ {
+ get { return error; }
+ }
+
+ public ClientStateArgs (ClientState state, ErrorCode error)
+ {
+ this.state = state;
+ this.error = error;
+ }
+ }
+
+ public enum Protocol {
+ Unspecified = -1,
+ IPv4 = 0,
+ IPv6 = 1
+ }
+
+ internal enum ServerState {
+ Invalid,
+ Registering,
+ Running,
+ Collision
+ }
+
+ public enum ClientState {
+ Registering = ServerState.Registering,
+ Running = ServerState.Running,
+ Collision = ServerState.Collision,
+ Failure = 100,
+ Connecting = 101
+ }
+
+ [Flags]
+ public enum LookupFlags {
+ None = 0,
+ UseWideArea = 1,
+ UseMulticast = 2,
+ NoTxt = 4,
+ NoAddress = 8
+ }
+
+ [Flags]
+ public enum LookupResultFlags {
+ None = 0,
+ Cached = 1,
+ WideArea = 2,
+ Multicast = 4,
+ Local = 8,
+ OurOwn = 16,
+ }
+
+ [Flags]
+ public enum ClientFlags {
+ None = 0,
+ IgnoreUserConfig = 1,
+ NoFail = 2
+ }
+
+ public class Client : IDisposable
+ {
+ private IntPtr handle;
+ private ClientCallback cb;
+ private PollCallback pollcb;
+ private IntPtr spoll;
+
+ private Thread thread;
+
+ [DllImport ("avahi-client")]
+ private static extern IntPtr avahi_client_new (IntPtr poll, ClientFlags flags, ClientCallback handler,
+ IntPtr userData, out int error);
+
+ [DllImport ("avahi-client")]
+ private static extern void avahi_client_free (IntPtr handle);
+
+ [DllImport ("avahi-client")]
+ private static extern IntPtr avahi_client_get_version_string (IntPtr handle);
+
+ [DllImport ("avahi-client")]
+ private static extern IntPtr avahi_client_get_host_name (IntPtr handle);
+
+ [DllImport ("avahi-client")]
+ private static extern IntPtr avahi_client_get_domain_name (IntPtr handle);
+
+ [DllImport ("avahi-client")]
+ private static extern IntPtr avahi_client_get_host_name_fqdn (IntPtr handle);
+
+ [DllImport ("avahi-client")]
+ private static extern ClientState avahi_client_get_state (IntPtr handle);
+
+ [DllImport ("avahi-client")]
+ private static extern int avahi_client_errno (IntPtr handle);
+
+ [DllImport ("avahi-common")]
+ private static extern IntPtr avahi_simple_poll_new ();
+
+ [DllImport ("avahi-common")]
+ private static extern IntPtr avahi_simple_poll_get (IntPtr spoll);
+
+ [DllImport ("avahi-common")]
+ private static extern void avahi_simple_poll_free (IntPtr spoll);
+
+ [DllImport ("avahi-common")]
+ private static extern int avahi_simple_poll_loop (IntPtr spoll);
+
+ [DllImport ("avahi-common")]
+ private static extern void avahi_simple_poll_set_func (IntPtr spoll, PollCallback cb);
+
+ [DllImport ("avahi-common")]
+ private static extern void avahi_simple_poll_quit (IntPtr spoll);
+
+ [DllImport ("avahi-client")]
+ private static extern uint avahi_client_get_local_service_cookie (IntPtr client);
+
+ [DllImport ("avahi-common")]
+ private static extern int avahi_service_name_join (IntPtr buf, int len, byte[] name, byte[] type,
+ byte[] domain);
+
+ [DllImport ("avahi-common")]
+ private static extern int avahi_service_name_split (byte[] service, IntPtr name, int name_len,
+ IntPtr type, int type_len,
+ IntPtr domain, int domain_len);
+
+
+ [DllImport ("libc")]
+ private static extern int poll(IntPtr ufds, uint nfds, int timeout);
+
+ public event ClientStateHandler StateChanged;
+
+ internal IntPtr Handle
+ {
+ get { return handle; }
+ }
+
+ public string Version
+ {
+ get {
+ lock (this) {
+ return Utility.PtrToString (avahi_client_get_version_string (handle));
+ }
+ }
+ }
+
+ public string HostName
+ {
+ get {
+ lock (this) {
+ return Utility.PtrToString (avahi_client_get_host_name (handle));
+ }
+ }
+ }
+
+ public string DomainName
+ {
+ get {
+ lock (this) {
+ return Utility.PtrToString (avahi_client_get_domain_name (handle));
+ }
+ }
+ }
+
+ public string HostNameFqdn
+ {
+ get {
+ lock (this) {
+ return Utility.PtrToString (avahi_client_get_host_name_fqdn (handle));
+ }
+ }
+ }
+
+ public ClientState State
+ {
+ get {
+ lock (this) {
+ return (ClientState) avahi_client_get_state (handle);
+ }
+ }
+ }
+
+ public uint LocalServiceCookie
+ {
+ get {
+ lock (this) {
+ return avahi_client_get_local_service_cookie (handle);
+ }
+ }
+ }
+
+ internal ErrorCode LastError
+ {
+ get {
+ lock (this) {
+ return (ErrorCode) avahi_client_errno (handle);
+ }
+ }
+ }
+
+ public Client (ClientFlags flags)
+ {
+ spoll = avahi_simple_poll_new ();
+
+ pollcb = OnPollCallback;
+ avahi_simple_poll_set_func (spoll, pollcb);
+ IntPtr poll = avahi_simple_poll_get (spoll);
+ cb = OnClientCallback;
+
+ int error;
+ handle = avahi_client_new (poll, flags, cb, IntPtr.Zero, out error);
+ if (error != 0)
+ throw new ClientException (error);
+
+ thread = new Thread (PollLoop);
+ thread.IsBackground = true;
+ thread.Start ();
+ }
+
+ public Client () : this (ClientFlags.None) {
+ }
+
+ ~Client ()
+ {
+ Dispose ();
+ }
+
+ public void Dispose ()
+ {
+ if (handle != IntPtr.Zero) {
+ lock (this) {
+ avahi_client_free (handle);
+ handle = IntPtr.Zero;
+
+ avahi_simple_poll_quit (spoll);
+ Monitor.Wait (this);
+
+ avahi_simple_poll_free (spoll);
+ }
+ }
+ }
+
+ public static string JoinServiceName (string name, string type, string domain)
+ {
+ int len = 4 * (name.Length + type.Length + domain.Length) + 4;
+ IntPtr buf = Stdlib.malloc ((ulong) len);
+
+ int ret = avahi_service_name_join (buf, len,
+ Utility.StringToBytes (name),
+ Utility.StringToBytes (type),
+ Utility.StringToBytes (domain));
+
+ if (ret < 0) {
+ Utility.Free (buf);
+ return null; // FIXME, should throw exception
+ }
+
+ string service = Utility.PtrToString (buf);
+ Utility.Free (buf);
+
+ return service;
+ }
+
+ public static void SplitServiceName (string service, out string name, out string type, out string domain)
+ {
+ int len = 1024;
+
+ IntPtr namePtr = Stdlib.malloc ((ulong) len);
+ IntPtr typePtr = Stdlib.malloc ((ulong) len);
+ IntPtr domainPtr = Stdlib.malloc ((ulong) len);
+
+ int ret = avahi_service_name_split (Utility.StringToBytes (service), namePtr, len, typePtr, len,
+ domainPtr, len);
+
+ if (ret < 0) {
+ Utility.Free (namePtr);
+ Utility.Free (typePtr);
+ Utility.Free (domainPtr);
+
+ name = null;
+ type = null;
+ domain = null;
+ return;
+ }
+
+ name = Utility.PtrToString (namePtr);
+ type = Utility.PtrToString (typePtr);
+ domain = Utility.PtrToString (domainPtr);
+
+ Utility.Free (namePtr);
+ Utility.Free (typePtr);
+ Utility.Free (domainPtr);
+ }
+
+ internal void ThrowError ()
+ {
+ ErrorCode error = LastError;
+
+ if (error != ErrorCode.Ok)
+ throw new ClientException (error);
+ }
+
+ private void OnClientCallback (IntPtr client, ClientState state, IntPtr userData)
+ {
+ if (StateChanged != null)
+ StateChanged (this, new ClientStateArgs (state, LastError));
+ }
+
+ private int OnPollCallback (IntPtr ufds, uint nfds, int timeout) {
+ Monitor.Exit (this);
+ int result = poll (ufds, nfds, timeout);
+ Monitor.Enter (this);
+ return result;
+ }
+
+ private void PollLoop () {
+ try {
+ lock (this) {
+ avahi_simple_poll_loop (spoll);
+ Monitor.Pulse (this);
+ }
+ } catch (Exception e) {
+ Console.Error.WriteLine ("Error in avahi-sharp event loop: " + e);
+ }
+ }
+ }
+}