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.Collections;
25using System.Runtime.InteropServices;
26using System.Text;
27
28namespace Avahi
29{
30    internal delegate void ServiceBrowserCallback (IntPtr browser, int iface, Protocol proto, BrowserEvent bevent,
31                                                   IntPtr name, IntPtr type, IntPtr domain, LookupResultFlags flags,
32                                                   IntPtr userdata);
33
34    public struct ServiceInfo
35    {
36        public int NetworkInterface;
37        public Protocol Protocol;
38        public string Domain;
39        public string ServiceType;
40        public string Name;
41
42        public string HostName;
43        public IPAddress Address;
44        public UInt16 Port;
45        public byte[][] Text;
46        public LookupResultFlags Flags;
47
48        public static ServiceInfo Zero = new ServiceInfo ();
49    }
50
51    public class ServiceInfoArgs : EventArgs
52    {
53        private ServiceInfo service;
54
55        public ServiceInfo Service {
56            get { return service; }
57        }
58
59        public ServiceInfoArgs (ServiceInfo service)
60        {
61            this.service = service;
62        }
63    }
64
65    public delegate void ServiceInfoHandler (object o, ServiceInfoArgs args);
66
67    public class ServiceBrowser : BrowserBase, IDisposable
68    {
69        private IntPtr handle;
70        private ArrayList infos = new ArrayList ();
71        private Client client;
72        private int iface;
73        private Protocol proto;
74        private string domain;
75        private string type;
76        private LookupFlags flags;
77        private ServiceBrowserCallback cb;
78
79        private ArrayList addListeners = new ArrayList ();
80        private ArrayList removeListeners = new ArrayList ();
81
82        [DllImport ("avahi-client")]
83        private static extern IntPtr avahi_service_browser_new (IntPtr client, int iface, int proto, byte[] type,
84                                                                byte[] domain, LookupFlags flags,
85                                                                ServiceBrowserCallback cb,
86                                                                IntPtr userdata);
87
88        [DllImport ("avahi-client")]
89        private static extern void avahi_service_browser_free (IntPtr handle);
90
91        public event ServiceInfoHandler ServiceAdded
92        {
93            add {
94                addListeners.Add (value);
95                Start ();
96            }
97            remove {
98                addListeners.Remove (value);
99                Stop (false);
100            }
101        }
102
103        public event ServiceInfoHandler ServiceRemoved
104        {
105            add {
106                removeListeners.Add (value);
107                Start ();
108            }
109            remove {
110                removeListeners.Remove (value);
111                Stop (false);
112            }
113        }
114
115        public ServiceInfo[] Services
116        {
117            get { return (ServiceInfo[]) infos.ToArray (typeof (ServiceInfo)); }
118        }
119
120        public ServiceBrowser (Client client, string type) : this (client, type, client.DomainName)
121        {
122        }
123
124        public ServiceBrowser (Client client, string type, string domain) : this (client, -1, Protocol.Unspecified,
125                                                                                  type, domain, LookupFlags.None)
126        {
127        }
128
129        public ServiceBrowser (Client client, int iface, Protocol proto, string type, string domain, LookupFlags flags)
130        {
131            this.client = client;
132            this.iface = iface;
133            this.proto = proto;
134            this.domain = domain;
135            this.type = type;
136            this.flags = flags;
137            cb = OnServiceBrowserCallback;
138        }
139
140        ~ServiceBrowser ()
141        {
142            Dispose ();
143        }
144
145        public void Dispose ()
146        {
147            Stop (true);
148        }
149
150        private void Start ()
151        {
152            if (client.Handle == IntPtr.Zero || handle != IntPtr.Zero ||
153                (addListeners.Count == 0 && removeListeners.Count == 0))
154                return;
155
156            lock (client) {
157                handle = avahi_service_browser_new (client.Handle, iface, (int) proto,
158                                                    Utility.StringToBytes (type), Utility.StringToBytes (domain),
159                                                    flags, cb, IntPtr.Zero);
160
161                if (handle == IntPtr.Zero)
162                    client.ThrowError ();
163            }
164        }
165
166        private void Stop (bool force)
167        {
168            if (client.Handle != IntPtr.Zero && handle != IntPtr.Zero &&
169                (force || (addListeners.Count == 0 && removeListeners.Count == 0))) {
170
171                lock (client) {
172                    avahi_service_browser_free (handle);
173                    handle = IntPtr.Zero;
174                }
175            }
176        }
177
178        private void OnServiceBrowserCallback (IntPtr browser, int iface, Protocol proto, BrowserEvent bevent,
179                                               IntPtr name, IntPtr type, IntPtr domain, LookupResultFlags flags,
180                                               IntPtr userdata)
181        {
182
183            ServiceInfo info;
184            info.NetworkInterface = iface;
185            info.Protocol = proto;
186            info.Domain = Utility.PtrToString (domain);
187            info.ServiceType = Utility.PtrToString (type);
188            info.Name = Utility.PtrToString (name);
189            info.HostName = null;
190            info.Address = null;
191            info.Port = 0;
192            info.Text = null;
193            info.Flags = flags;
194
195            switch (bevent) {
196            case BrowserEvent.Added:
197                infos.Add (info);
198
199                foreach (ServiceInfoHandler handler in addListeners)
200                    handler (this, new ServiceInfoArgs (info));
201
202                break;
203            case BrowserEvent.Removed:
204                infos.Remove (info);
205
206                foreach (ServiceInfoHandler handler in removeListeners)
207                    handler (this, new ServiceInfoArgs (info));
208
209                break;
210            default:
211                EmitBrowserEvent (bevent);
212                break;
213            }
214        }
215    }
216}
217