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