1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18using System;
19using System.Drawing;
20using System.Collections;
21using System.ComponentModel;
22using System.Windows.Forms;
23using System.Data;
24using System.Text;
25using Bonjour;
26
27namespace DNSServiceBrowser_NET
28{
29	/// <summary>
30	/// Summary description for Form1.
31	/// </summary>
32	public class Form1 : System.Windows.Forms.Form
33	{
34		private System.Windows.Forms.ComboBox typeBox;
35		private System.Windows.Forms.ListBox browseList;
36        private Bonjour.DNSSDEventManager   eventManager = null;
37        private Bonjour.DNSSDService        service = null;
38		private Bonjour.DNSSDService        browser = null;
39		private Bonjour.DNSSDService        resolver = null;
40		/// <summary>
41		/// Required designer variable.
42		/// </summary>
43		private System.ComponentModel.Container components = null;
44
45		private System.Windows.Forms.Label label1;
46		private System.Windows.Forms.Label label2;
47		private System.Windows.Forms.Label label3;
48		private System.Windows.Forms.Label label4;
49		private System.Windows.Forms.TextBox nameField;
50		private System.Windows.Forms.TextBox typeField;
51		private System.Windows.Forms.TextBox domainField;
52		private System.Windows.Forms.TextBox hostField;
53		private System.Windows.Forms.TextBox portField;
54		private System.Windows.Forms.Label label5;
55		private System.Windows.Forms.ListBox serviceTextField;
56
57		public Form1()
58		{
59			//
60			// Required for Windows Form Designer support
61			//
62			InitializeComponent();
63
64			this.Load += new System.EventHandler(this.Form1_Load);
65
66			//
67			// Create the DNSSDEventManager. You can then associate event handlers
68			// with the instance that will be invoked when the event occurs
69			//
70			// In this example, we're associating ServiceFound, ServiceLost,
71			// ServiceResolved, and OperationFailed event handlers with the
72			// event manager instance.
73			//
74            eventManager                    =  new DNSSDEventManager();
75            eventManager.ServiceFound       += new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound);
76            eventManager.ServiceLost        += new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost);
77            eventManager.ServiceResolved    += new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved);
78            eventManager.OperationFailed    += new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed);
79
80            service = new DNSSDService();
81		}
82
83		private void Form1_Load(object sender, EventArgs e)
84		{
85			typeBox.SelectedItem = "_http._tcp";
86		}
87
88
89		/// <summary>
90		/// Clean up any resources being used.
91		/// </summary>
92		protected override void Dispose( bool disposing )
93		{
94			if( disposing )
95			{
96                if (components != null)
97                {
98                    components.Dispose();
99                }
100
101				//
102				// Clean up
103				//
104                if (resolver != null)
105                {
106                    resolver.Stop();
107                }
108
109                if (browser != null)
110                {
111                    browser.Stop();
112                }
113
114                if (service != null)
115                {
116                    service.Stop();
117                }
118
119                eventManager.ServiceFound    -= new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound);
120                eventManager.ServiceLost     -= new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost);
121                eventManager.ServiceResolved -= new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved);
122                eventManager.OperationFailed -= new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed);
123			}
124			base.Dispose( disposing );
125		}
126
127		#region Windows Form Designer generated code
128		/// <summary>
129		/// Required method for Designer support - do not modify
130		/// the contents of this method with the code editor.
131		/// </summary>
132		private void InitializeComponent()
133		{
134			this.browseList = new System.Windows.Forms.ListBox();
135			this.typeBox = new System.Windows.Forms.ComboBox();
136			this.label1 = new System.Windows.Forms.Label();
137			this.label2 = new System.Windows.Forms.Label();
138			this.label3 = new System.Windows.Forms.Label();
139			this.label4 = new System.Windows.Forms.Label();
140			this.nameField = new System.Windows.Forms.TextBox();
141			this.typeField = new System.Windows.Forms.TextBox();
142			this.domainField = new System.Windows.Forms.TextBox();
143			this.hostField = new System.Windows.Forms.TextBox();
144			this.portField = new System.Windows.Forms.TextBox();
145			this.label5 = new System.Windows.Forms.Label();
146			this.serviceTextField = new System.Windows.Forms.ListBox();
147			this.SuspendLayout();
148			//
149			// browseList
150			//
151			this.browseList.Location = new System.Drawing.Point(8, 48);
152			this.browseList.Name = "browseList";
153			this.browseList.Size = new System.Drawing.Size(488, 147);
154			this.browseList.TabIndex = 0;
155			this.browseList.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
156			//
157			// typeBox
158			//
159			this.typeBox.Items.AddRange(new object[]
160			{
161				"_accessone._tcp",
162				"_accountedge._tcp",
163				"_actionitems._tcp",
164				"_addressbook._tcp",
165				"_aecoretech._tcp",
166				"_afpovertcp._tcp",
167				"_airport._tcp",
168				"_animolmd._tcp",
169				"_animobserver._tcp",
170				"_apple-sasl._tcp",
171				"_aquamon._tcp",
172				"_async._tcp",
173				"_auth._tcp",
174				"_beep._tcp",
175				"_bfagent._tcp",
176				"_bootps._udp",
177				"_bousg._tcp",
178				"_bsqdea._tcp",
179				"_cheat._tcp",
180				"_chess._tcp",
181				"_clipboard._tcp",
182				"_collection._tcp",
183				"_contactserver._tcp",
184				"_cvspserver._tcp",
185				"_cytv._tcp",
186				"_daap._tcp",
187				"_difi._tcp",
188				"_distcc._tcp",
189				"_dossier._tcp",
190				"_dpap._tcp",
191				"_earphoria._tcp",
192				"_ebms._tcp",
193				"_ebreg._tcp",
194				"_ecbyesfsgksc._tcp",
195				"_eheap._tcp",
196				"_embrace._tcp",
197				"_eppc._tcp",
198				"_eventserver._tcp",
199				"_exec._tcp",
200				"_facespan._tcp",
201				"_faxstfx._tcp",
202				"_fish._tcp",
203				"_fjork._tcp",
204				"_fmpro-internal._tcp",
205				"_ftp._tcp",
206				"_ftpcroco._tcp",
207				"_gbs-smp._tcp",
208				"_gbs-stp._tcp",
209				"_grillezvous._tcp",
210				"_h323._tcp",
211				"_http._tcp",
212				"_hotwayd._tcp",
213				"_hydra._tcp",
214				"_ica-networking._tcp",
215				"_ichalkboard._tcp",
216				"_ichat._tcp",
217				"_iconquer._tcp",
218				"_ifolder._tcp",
219				"_ilynx._tcp",
220				"_imap._tcp",
221				"_imidi._tcp",
222				"_ipbroadcaster._tcp",
223				"_ipp._tcp",
224				"_isparx._tcp",
225				"_ispq-vc._tcp",
226				"_ishare._tcp",
227				"_isticky._tcp",
228				"_istorm._tcp",
229				"_iwork._tcp",
230				"_lan2p._tcp",
231				"_ldap._tcp",
232				"_liaison._tcp",
233				"_login._tcp",
234				"_lontalk._tcp",
235				"_lonworks._tcp",
236				"_macfoh-remote._tcp",
237				"_macminder._tcp",
238				"_moneyworks._tcp",
239				"_mp3sushi._tcp",
240				"_mttp._tcp",
241				"_ncbroadcast._tcp",
242				"_ncdirect._tcp",
243				"_ncsyncserver._tcp",
244				"_net-assistant._tcp",
245				"_newton-dock._tcp",
246				"_nfs._udp",
247				"_nssocketport._tcp",
248				"_odabsharing._tcp",
249				"_omni-bookmark._tcp",
250				"_openbase._tcp",
251				"_p2pchat._udp",
252				"_pdl-datastream._tcp",
253				"_poch._tcp",
254				"_pop3._tcp",
255				"_postgresql._tcp",
256				"_presence._tcp",
257				"_printer._tcp",
258				"_ptp._tcp",
259				"_quinn._tcp",
260				"_raop._tcp",
261				"_rce._tcp",
262				"_realplayfavs._tcp",
263				"_riousbprint._tcp",
264				"_rfb._tcp",
265				"_rtsp._tcp",
266				"_safarimenu._tcp",
267				"_sallingclicker._tcp",
268				"_scone._tcp",
269				"_sdsharing._tcp",
270				"_see._tcp",
271				"_seeCard._tcp",
272				"_serendipd._tcp",
273				"_servermgr._tcp",
274				"_shell._tcp",
275				"_shout._tcp",
276				"_shoutcast._tcp",
277				"_soap._tcp",
278				"_spike._tcp",
279				"_spincrisis._tcp",
280				"_spl-itunes._tcp",
281				"_spr-itunes._tcp",
282				"_ssh._tcp",
283				"_ssscreenshare._tcp",
284				"_strateges._tcp",
285				"_sge-exec._tcp",
286				"_sge-qmaster._tcp",
287				"_stickynotes._tcp",
288				"_sxqdea._tcp",
289				"_sybase-tds._tcp",
290				"_teamlist._tcp",
291				"_teleport._udp",
292				"_telnet._tcp",
293				"_tftp._udp",
294				"_ticonnectmgr._tcp",
295				"_tinavigator._tcp",
296				"_tryst._tcp",
297				"_upnp._tcp",
298				"_utest._tcp",
299				"_vue4rendercow._tcp",
300				"_webdav._tcp",
301				"_whamb._tcp",
302				"_wired._tcp",
303				"_workstation._tcp",
304				"_wormhole._tcp",
305				"_workgroup._tcp",
306				"_ws._tcp",
307				"_xserveraid._tcp",
308				"_xsync._tcp",
309				"_xtshapro._tcp"
310			});
311
312			this.typeBox.Location = new System.Drawing.Point(8, 16);
313			this.typeBox.Name = "typeBox";
314			this.typeBox.Size = new System.Drawing.Size(192, 21);
315			this.typeBox.Sorted = true;
316			this.typeBox.TabIndex = 3;
317			this.typeBox.SelectedIndexChanged += new System.EventHandler(this.typeBox_SelectedIndexChanged);
318			//
319			// label1
320			//
321			this.label1.Location = new System.Drawing.Point(8, 208);
322			this.label1.Name = "label1";
323			this.label1.Size = new System.Drawing.Size(48, 16);
324			this.label1.TabIndex = 4;
325			this.label1.Text = "Name:";
326			this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
327			//
328			// label2
329			//
330			this.label2.Location = new System.Drawing.Point(8, 240);
331			this.label2.Name = "label2";
332			this.label2.Size = new System.Drawing.Size(48, 16);
333			this.label2.TabIndex = 5;
334			this.label2.Text = "Type:";
335			this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
336			//
337			// label3
338			//
339			this.label3.Location = new System.Drawing.Point(8, 272);
340			this.label3.Name = "label3";
341			this.label3.Size = new System.Drawing.Size(48, 16);
342			this.label3.TabIndex = 6;
343			this.label3.Text = "Domain:";
344			this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
345			//
346			// label4
347			//
348			this.label4.Location = new System.Drawing.Point(8, 304);
349			this.label4.Name = "label4";
350			this.label4.Size = new System.Drawing.Size(48, 16);
351			this.label4.TabIndex = 7;
352			this.label4.Text = "Host:";
353			this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
354			//
355			// nameField
356			//
357			this.nameField.Location = new System.Drawing.Point(56, 208);
358			this.nameField.Name = "nameField";
359			this.nameField.ReadOnly = true;
360			this.nameField.Size = new System.Drawing.Size(168, 20);
361			this.nameField.TabIndex = 8;
362			this.nameField.Text = "";
363			//
364			// typeField
365			//
366			this.typeField.Location = new System.Drawing.Point(56, 240);
367			this.typeField.Name = "typeField";
368			this.typeField.ReadOnly = true;
369			this.typeField.Size = new System.Drawing.Size(168, 20);
370			this.typeField.TabIndex = 9;
371			this.typeField.Text = "";
372			//
373			// domainField
374			//
375			this.domainField.Location = new System.Drawing.Point(56, 272);
376			this.domainField.Name = "domainField";
377			this.domainField.ReadOnly = true;
378			this.domainField.Size = new System.Drawing.Size(168, 20);
379			this.domainField.TabIndex = 10;
380			this.domainField.Text = "";
381			//
382			// hostField
383			//
384			this.hostField.Location = new System.Drawing.Point(56, 304);
385			this.hostField.Name = "hostField";
386			this.hostField.ReadOnly = true;
387			this.hostField.Size = new System.Drawing.Size(168, 20);
388			this.hostField.TabIndex = 11;
389			this.hostField.Text = "";
390
391			//
392			// portField
393			//
394			this.portField.Location = new System.Drawing.Point(56, 336);
395			this.portField.Name = "portField";
396			this.portField.ReadOnly = true;
397			this.portField.Size = new System.Drawing.Size(168, 20);
398			this.portField.TabIndex = 12;
399			this.portField.Text = "";
400			//
401			// label5
402			//
403			this.label5.Location = new System.Drawing.Point(8, 336);
404			this.label5.Name = "label5";
405			this.label5.Size = new System.Drawing.Size(48, 16);
406			this.label5.TabIndex = 14;
407			this.label5.Text = "Port:";
408			this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
409			//
410			// serviceTextField
411			//
412			this.serviceTextField.HorizontalScrollbar = true;
413			this.serviceTextField.Location = new System.Drawing.Point(264, 208);
414			this.serviceTextField.Name = "serviceTextField";
415			this.serviceTextField.Size = new System.Drawing.Size(232, 147);
416			this.serviceTextField.TabIndex = 16;
417			//
418			// Form1
419			//
420			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
421			this.ClientSize = new System.Drawing.Size(512, 365);
422			this.Controls.AddRange(new System.Windows.Forms.Control[] {
423																		  this.serviceTextField,
424																		  this.label5,
425																		  this.portField,
426																		  this.hostField,
427																		  this.domainField,
428																		  this.typeField,
429																		  this.nameField,
430																		  this.label4,
431																		  this.label3,
432																		  this.label2,
433																		  this.label1,
434																		  this.typeBox,
435																		  this.browseList});
436			this.Name = "Form1";
437			this.Text = "DNSServices Browser";
438			this.ResumeLayout(false);
439
440		}
441		#endregion
442
443		/// <summary>
444		/// The main entry point for the application.
445		/// </summary>
446		[STAThread]
447		static void Main()
448		{
449			Application.Run(new Form1());
450		}
451		//
452		// BrowseData
453		//
454		// This class is used to store data associated
455		// with a DNSService.Browse() operation
456		//
457		public class BrowseData
458		{
459			public uint		InterfaceIndex;
460			public String	Name;
461			public String	Type;
462			public String	Domain;
463            public int      Refs;
464
465			public override String
466			ToString()
467			{
468				return Name;
469			}
470
471			public override bool
472			Equals(object other)
473			{
474				bool result = false;
475
476				if (other != null)
477				{
478					result = (this.Name == other.ToString());
479				}
480
481				return result;
482			}
483
484			public override int
485			GetHashCode()
486			{
487				return Name.GetHashCode();
488			}
489		};
490
491
492		//
493		// ResolveData
494		//
495		// This class is used to store data associated
496		// with a DNSService.Resolve() operation
497		//
498		public class ResolveData
499		{
500			public uint		    InterfaceIndex;
501			public String	    FullName;
502			public String	    HostName;
503			public int		    Port;
504			public TXTRecord	TxtRecord;
505
506			public override String
507				ToString()
508			{
509				return FullName;
510			}
511		};
512
513		//
514		// Populate()
515		//
516		// Populate this form with data associated with a
517		// DNSService.Resolve() call
518		//
519		public void
520		Populate(BrowseData browseData, ResolveData resolveData)
521		{
522			nameField.Text	= browseData.Name;
523			typeField.Text	= browseData.Type;
524			domainField.Text	= browseData.Domain;
525			hostField.Text	= resolveData.HostName;
526			portField.Text	= resolveData.Port.ToString();
527
528			serviceTextField.Items.Clear();
529
530			//
531			// When we print the text record, we're going to assume that every value
532			// is a string.
533			//
534            if (resolveData.TxtRecord != null)
535            {
536                for (uint idx = 0; idx < resolveData.TxtRecord.GetCount(); idx++)
537                {
538                    String key;
539                    Byte[] bytes;
540
541                    key = resolveData.TxtRecord.GetKeyAtIndex(idx);
542                    bytes = (Byte[])resolveData.TxtRecord.GetValueAtIndex(idx);
543
544                    if (key.Length > 0)
545                    {
546                        String val = "";
547
548                        if (bytes != null)
549                        {
550                            val = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
551                        }
552
553                        serviceTextField.Items.Add(key + "=" + val);
554                    }
555                }
556            }
557		}
558
559		//
560		// called when the type field changes
561		//
562		private void typeBox_SelectedIndexChanged(object sender, System.EventArgs e)
563		{
564			browseList.Items.Clear();
565
566			//
567			// Stop the current browse operation
568			//
569			if (browser != null)
570			{
571				browser.Stop();
572			}
573
574			nameField.Text = "";
575			typeField.Text = "";
576			domainField.Text = "";
577			hostField.Text = "";
578			portField.Text = "";
579			serviceTextField.Items.Clear();
580
581			try
582			{
583				//
584				// Selecting a service type will start a new browse operation.
585				//
586				browser = service.Browse( 0, 0, typeBox.SelectedItem.ToString(), null, eventManager );
587			}
588			catch
589			{
590				MessageBox.Show("Browse Failed", "Error");
591				Application.Exit();
592			}
593		}
594
595		private void listBox1_SelectedIndexChanged(object sender, System.EventArgs e)
596		{
597			if (resolver != null)
598			{
599				resolver.Stop();
600                resolver = null;
601			}
602
603            if (browseList.SelectedItem != null)
604            {
605                try
606                {
607                    BrowseData data = (BrowseData) browseList.SelectedItem;
608
609					//
610					// Clicking on a service instance results in starting a resolve operation
611					// that will call us back with information about the service
612					//
613                    resolver = service.Resolve(0, data.InterfaceIndex, data.Name, data.Type, data.Domain, eventManager);
614                }
615                catch
616                {
617                    MessageBox.Show("Resolve Failed", "Error");
618                    Application.Exit();
619                }
620            }
621		}
622
623		//
624		// ServiceFound
625		//
626		// This call is invoked by the DNSService core.  We create
627        // a BrowseData object and invoked the appropriate method
628        // in the GUI thread so we can update the UI
629		//
630        public void ServiceFound
631                        (
632                        DNSSDService sref,
633                        DNSSDFlags flags,
634                        uint ifIndex,
635                        String serviceName,
636                        String regType,
637                        String domain
638                        )
639        {
640            int index = browseList.Items.IndexOf(serviceName);
641
642			//
643			// Check to see if we've seen this service before. If the machine has multiple
644			// interfaces, we could potentially get called back multiple times for the
645			// same service. Implementing a simple reference counting scheme will address
646			// the problem of the same service showing up more than once in the browse list.
647			//
648            if (index == -1)
649            {
650                BrowseData data = new BrowseData();
651
652                data.InterfaceIndex = ifIndex;
653                data.Name = serviceName;
654                data.Type = regType;
655                data.Domain = domain;
656                data.Refs = 1;
657
658                browseList.Items.Add(data);
659                browseList.Invalidate();
660            }
661            else
662            {
663                BrowseData data = (BrowseData) browseList.Items[index];
664                data.Refs++;
665            }
666        }
667
668        public void ServiceLost
669                        (
670                        DNSSDService sref,
671                        DNSSDFlags flags,
672                        uint ifIndex,
673                        String serviceName,
674                        String regType,
675                        String domain
676                        )
677        {
678            int index = browseList.Items.IndexOf(serviceName);
679
680			//
681			// See above comment in ServiceFound about reference counting
682			//
683            if (index != -1)
684            {
685                BrowseData data = (BrowseData) browseList.Items[index];
686
687                data.Refs--;
688
689                if (data.Refs == 0)
690                {
691                    browseList.Items.Remove(data);
692                    browseList.Invalidate();
693                }
694            }
695        }
696
697		public void ServiceResolved
698						(
699						DNSSDService    sref,
700						DNSSDFlags      flags,
701						uint			ifIndex,
702                        String          fullName,
703                        String          hostName,
704                        ushort           port,
705                        TXTRecord       txtRecord
706						)
707		{
708			ResolveData data = new ResolveData();
709
710			data.InterfaceIndex = ifIndex;
711			data.FullName		= fullName;
712			data.HostName		= hostName;
713			data.Port			= port;
714			data.TxtRecord		= txtRecord;
715
716			//
717			// Don't forget to stop the resolver. This eases the burden on the network
718			//
719            resolver.Stop();
720			resolver = null;
721
722			Populate((BrowseData) browseList.SelectedItem, data);
723		}
724
725        public void OperationFailed
726                        (
727                        DNSSDService sref,
728                        DNSSDError error
729                        )
730        {
731            MessageBox.Show("Operation failed: error code: " + error, "Error");
732        }
733    }
734}
735