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 Mono.Unix;
27
28namespace Avahi
29{
30
31    internal delegate void AddressResolverCallback (IntPtr resolver, int iface, Protocol proto,
32                                                    ResolverEvent revent, IntPtr address,
33                                                    IntPtr hostname, LookupResultFlags flags, IntPtr userdata);
34
35    public delegate void HostAddressHandler (object o, HostAddressArgs args);
36
37    public class HostAddressArgs : EventArgs
38    {
39        private string host;
40        private IPAddress address;
41
42        public string Host
43        {
44            get { return host; }
45        }
46
47        public IPAddress Address
48        {
49            get { return address; }
50        }
51
52        public HostAddressArgs (string host, IPAddress address)
53        {
54            this.host = host;
55            this.address = address;
56        }
57    }
58
59    public class AddressResolver : ResolverBase, IDisposable
60    {
61        private IntPtr handle;
62        private Client client;
63        private int iface;
64        private Protocol proto;
65        private IPAddress address;
66        private LookupFlags flags;
67        private AddressResolverCallback cb;
68
69        private IPAddress currentAddress;
70        private string currentHost;
71
72        private ArrayList foundListeners = new ArrayList ();
73        private ArrayList timeoutListeners = new ArrayList ();
74
75        [DllImport ("avahi-client")]
76        private static extern IntPtr avahi_address_resolver_new (IntPtr client, int iface, Protocol proto,
77                                                                 IntPtr address, LookupFlags flags,
78                                                                 AddressResolverCallback cb,
79                                                                 IntPtr userdata);
80
81        [DllImport ("avahi-client")]
82        private static extern void avahi_address_resolver_free (IntPtr handle);
83
84        public event HostAddressHandler Found
85        {
86            add {
87                foundListeners.Add (value);
88                Start ();
89            }
90            remove {
91                foundListeners.Remove (value);
92                Stop (false);
93            }
94        }
95
96        public event EventHandler Timeout
97        {
98            add {
99                timeoutListeners.Add (value);
100                Start ();
101            }
102            remove {
103                timeoutListeners.Remove (value);
104                Stop (false);
105            }
106        }
107
108        public IPAddress Address
109        {
110            get { return currentAddress; }
111        }
112
113        public string HostName
114        {
115            get { return currentHost; }
116        }
117
118        public AddressResolver (Client client, IPAddress address) : this (client, -1, Protocol.Unspecified,
119                                                                          address, LookupFlags.None)
120        {
121        }
122
123        public AddressResolver (Client client, int iface, Protocol proto, IPAddress address, LookupFlags flags)
124        {
125            this.client = client;
126            this.iface = iface;
127            this.proto = proto;
128            this.address = address;
129            this.flags = flags;
130            cb = OnAddressResolverCallback;
131        }
132
133        ~AddressResolver ()
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            IntPtr addrPtr = Utility.AddressToPtr (address);
150
151            lock (client) {
152                handle = avahi_address_resolver_new (client.Handle, iface, proto, addrPtr, flags,
153                                                     cb, IntPtr.Zero);
154
155                if (handle == IntPtr.Zero)
156                    client.ThrowError ();
157            }
158
159            Utility.Free (addrPtr);
160        }
161
162        private void Stop (bool force)
163        {
164            if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero &&
165                (force || (foundListeners.Count == 0 && timeoutListeners.Count == 0))) {
166
167                lock (client) {
168                    avahi_address_resolver_free (handle);
169                    handle = IntPtr.Zero;
170                }
171            }
172        }
173
174        private void OnAddressResolverCallback (IntPtr resolver, int iface, Protocol proto,
175                                                ResolverEvent revent, IntPtr address,
176                                                IntPtr hostname, LookupResultFlags flags, IntPtr userdata)
177        {
178            switch (revent) {
179            case ResolverEvent.Found:
180                currentAddress = Utility.PtrToAddress (address);
181                currentHost = Utility.PtrToString (hostname);
182
183                foreach (HostAddressHandler handler in foundListeners)
184                    handler (this, new HostAddressArgs (currentHost, currentAddress));
185                break;
186            case ResolverEvent.Failure:
187                EmitFailure (client.LastError);
188                break;
189            }
190        }
191    }
192}
193