1/* $Id: ServiceBrowser.cs 635 2005-09-26 03:57:30Z snorp $ */
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.Collections;
25using System.Runtime.InteropServices;
26using System.Text;
27
28namespace Avahi
29{
30
31    public delegate void RecordInfoHandler (object o, RecordInfoArgs args);
32
33    internal delegate void RecordBrowserCallback (IntPtr browser, int iface, Protocol proto, BrowserEvent bevent,
34                                                  IntPtr name, ushort clazz, ushort type, IntPtr rdata, int size,
35                                                  LookupResultFlags flags, IntPtr userdata);
36
37    public enum RecordClass {
38        In = 1
39    }
40
41    public enum RecordType {
42        A = 1,
43        Ns = 2,
44        Cname = 5,
45        Soa = 6,
46        Ptr = 12,
47        Hinfo = 13,
48        Mx = 15,
49        Txt = 16,
50        Aaa = 28,
51        Srv = 33
52    }
53
54    public struct RecordInfo
55    {
56        public int NetworkInterface;
57        public Protocol Protocol;
58        public string Name;
59        public RecordClass Class;
60        public RecordType Type;
61        public byte[] Data;
62        public LookupResultFlags Flags;
63    }
64
65    public class RecordInfoArgs : EventArgs
66    {
67        private RecordInfo record;
68
69        public RecordInfo Record {
70            get { return record; }
71        }
72
73        public RecordInfoArgs (RecordInfo record)
74        {
75            this.record = record;
76        }
77    }
78
79    public class RecordBrowser : BrowserBase, IDisposable
80    {
81        private IntPtr handle;
82        private ArrayList infos = new ArrayList ();
83        private Client client;
84        private int iface;
85        private Protocol proto;
86        private string name;
87        private RecordClass clazz;
88        private RecordType type;
89        private LookupFlags flags;
90        private RecordBrowserCallback cb;
91
92        private ArrayList addListeners = new ArrayList ();
93        private ArrayList removeListeners = new ArrayList ();
94
95        [DllImport ("avahi-client")]
96        private static extern IntPtr avahi_record_browser_new (IntPtr client, int iface, Protocol proto,
97                                                               byte[] name, ushort clazz, ushort type,
98                                                               LookupFlags flags, RecordBrowserCallback cb,
99                                                               IntPtr userdata);
100
101
102        [DllImport ("avahi-client")]
103        private static extern void avahi_record_browser_free (IntPtr handle);
104
105        public event RecordInfoHandler RecordAdded
106        {
107            add {
108                addListeners.Add (value);
109                Start ();
110            }
111            remove {
112                addListeners.Remove (value);
113                Stop (false);
114            }
115        }
116
117        public event RecordInfoHandler RecordRemoved
118        {
119            add {
120                removeListeners.Add (value);
121                Start ();
122            }
123            remove {
124                removeListeners.Remove (value);
125                Stop (false);
126            }
127        }
128
129        public RecordInfo[] Records
130        {
131            get { return (RecordInfo[]) infos.ToArray (typeof (RecordInfo)); }
132        }
133
134        public RecordBrowser (Client client, string name, RecordType type) :
135            this (client, -1, Protocol.Unspecified, name, RecordClass.In, type, LookupFlags.None)
136        {
137        }
138
139        public RecordBrowser (Client client, int iface, Protocol proto, string name, RecordClass clazz,
140                              RecordType type, LookupFlags flags)
141        {
142            this.client = client;
143            this.iface = iface;
144            this.proto = proto;
145            this.name = name;
146            this.clazz = clazz;
147            this.type = type;
148            this.flags = flags;
149            cb = OnRecordBrowserCallback;
150        }
151
152        ~RecordBrowser ()
153        {
154            Dispose ();
155        }
156
157        public void Dispose ()
158        {
159            Stop (true);
160        }
161
162        private void Start ()
163        {
164            if (client.Handle == IntPtr.Zero || handle != IntPtr.Zero ||
165                (addListeners.Count == 0 && removeListeners.Count == 0))
166                return;
167
168            lock (client) {
169                handle = avahi_record_browser_new (client.Handle, iface, proto, Utility.StringToBytes (name),
170                                                   (ushort) clazz, (ushort) type, flags, cb, IntPtr.Zero);
171
172                if (handle == IntPtr.Zero)
173                    client.ThrowError ();
174            }
175        }
176
177        private void Stop (bool force)
178        {
179            if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero &&
180                (force || (addListeners.Count == 0 && removeListeners.Count == 0))) {
181
182                lock (client) {
183                    avahi_record_browser_free (handle);
184                    handle = IntPtr.Zero;
185                }
186            }
187        }
188
189        private void OnRecordBrowserCallback (IntPtr browser, int iface, Protocol proto, BrowserEvent bevent,
190                                              IntPtr name, ushort clazz, ushort type, IntPtr rdata, int size,
191                                              LookupResultFlags flags, IntPtr userdata)
192        {
193            RecordInfo info;
194            info.NetworkInterface = iface;
195            info.Protocol = proto;
196            info.Name = Utility.PtrToString (name);
197            info.Class = (RecordClass) clazz;
198            info.Type = (RecordType) type;
199            info.Flags = flags;
200            info.Data = new byte[size];
201
202            if (rdata != IntPtr.Zero) {
203                Marshal.Copy (rdata, info.Data, 0, size);
204            }
205
206            switch (bevent) {
207            case BrowserEvent.Added:
208                infos.Add (info);
209
210                foreach (RecordInfoHandler handler in addListeners)
211                    handler (this, new RecordInfoArgs (info));
212
213                break;
214            case BrowserEvent.Removed:
215                infos.Remove (info);
216
217                foreach (RecordInfoHandler handler in removeListeners)
218                    handler (this, new RecordInfoArgs (info));
219
220                break;
221            default:
222                EmitBrowserEvent (bevent);
223                break;
224            }
225        }
226    }
227}
228