383 lines
11 KiB
C#
383 lines
11 KiB
C#
/***
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|