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.Net; 24using System.Net.Sockets; 25using System.Data; 26using System.Text; 27using Bonjour; 28 29namespace SimpleChat.NET 30{ 31 /// <summary> 32 /// Summary description for Form1. 33 /// </summary> 34 /// 35 36 public class SimpleChat : System.Windows.Forms.Form 37 { 38 private System.Windows.Forms.ComboBox comboBox1; 39 private System.Windows.Forms.TextBox textBox2; 40 private System.Windows.Forms.Button button1; 41 private System.Windows.Forms.Label label1; 42 43 private Bonjour.DNSSDEventManager m_eventManager = null; 44 private Bonjour.DNSSDService m_service = null; 45 private Bonjour.DNSSDService m_registrar = null; 46 private Bonjour.DNSSDService m_browser = null; 47 private Bonjour.DNSSDService m_resolver = null; 48 private String m_name; 49 private Socket m_socket = null; 50 private const int BUFFER_SIZE = 1024; 51 public byte[] m_buffer = new byte[BUFFER_SIZE]; 52 public bool m_complete = false; 53 public StringBuilder m_sb = new StringBuilder(); 54 55 delegate void ReadMessageCallback(String data); 56 57 ReadMessageCallback m_readMessageCallback; 58 /// <summary> 59 /// Required designer variable. 60 /// </summary> 61 private System.ComponentModel.Container components = null; 62 private System.Windows.Forms.RichTextBox richTextBox1; 63 64 // ServiceRegistered 65 // 66 // Called by DNSServices core as a result of Register() 67 // call 68 // 69 public void 70 ServiceRegistered 71 ( 72 DNSSDService service, 73 DNSSDFlags flags, 74 String name, 75 String regType, 76 String domain 77 ) 78 { 79 m_name = name; 80 81 // 82 // Try to start browsing for other instances of this service 83 // 84 try 85 { 86 m_browser = m_service.Browse(0, 0, "_p2pchat._udp", null, m_eventManager); 87 } 88 catch 89 { 90 MessageBox.Show("Browse Failed", "Error"); 91 Application.Exit(); 92 } 93 } 94 95 // 96 // ServiceFound 97 // 98 // Called by DNSServices core as a result of a Browse call 99 // 100 public void 101 ServiceFound 102 ( 103 DNSSDService sref, 104 DNSSDFlags flags, 105 uint ifIndex, 106 String serviceName, 107 String regType, 108 String domain 109 ) 110 { 111 if (serviceName != m_name) 112 { 113 PeerData peer = new PeerData(); 114 115 peer.InterfaceIndex = ifIndex; 116 peer.Name = serviceName; 117 peer.Type = regType; 118 peer.Domain = domain; 119 peer.Address = null; 120 121 comboBox1.Items.Add(peer); 122 123 if (comboBox1.Items.Count == 1) 124 { 125 comboBox1.SelectedIndex = 0; 126 } 127 } 128 } 129 130 // 131 // ServiceLost 132 // 133 // Called by DNSServices core as a result of a Browse call 134 // 135 public void 136 ServiceLost 137 ( 138 DNSSDService sref, 139 DNSSDFlags flags, 140 uint ifIndex, 141 String serviceName, 142 String regType, 143 String domain 144 ) 145 { 146 PeerData peer = new PeerData(); 147 148 peer.InterfaceIndex = ifIndex; 149 peer.Name = serviceName; 150 peer.Type = regType; 151 peer.Domain = domain; 152 peer.Address = null; 153 154 comboBox1.Items.Remove(peer); 155 } 156 157 // 158 // ServiceResolved 159 // 160 // Called by DNSServices core as a result of DNSService.Resolve() 161 // call 162 // 163 public void 164 ServiceResolved 165 ( 166 DNSSDService sref, 167 DNSSDFlags flags, 168 uint ifIndex, 169 String fullName, 170 String hostName, 171 ushort port, 172 TXTRecord txtRecord 173 ) 174 { 175 m_resolver.Stop(); 176 m_resolver = null; 177 178 PeerData peer = (PeerData)comboBox1.SelectedItem; 179 180 peer.Port = port; 181 182 // 183 // Query for the IP address associated with "hostName" 184 // 185 try 186 { 187 m_resolver = m_service.QueryRecord(0, ifIndex, hostName, DNSSDRRType.kDNSSDType_A, DNSSDRRClass.kDNSSDClass_IN, m_eventManager ); 188 } 189 catch 190 { 191 MessageBox.Show("QueryRecord Failed", "Error"); 192 Application.Exit(); 193 } 194 } 195 196 // 197 // QueryAnswered 198 // 199 // Called by DNSServices core as a result of DNSService.QueryRecord() 200 // call 201 // 202 public void 203 QueryAnswered 204 ( 205 DNSSDService service, 206 DNSSDFlags flags, 207 uint ifIndex, 208 String fullName, 209 DNSSDRRType rrtype, 210 DNSSDRRClass rrclass, 211 Object rdata, 212 uint ttl 213 ) 214 { 215 // 216 // Stop the resolve to reduce the burden on the network 217 // 218 m_resolver.Stop(); 219 m_resolver = null; 220 221 PeerData peer = (PeerData) comboBox1.SelectedItem; 222 uint bits = BitConverter.ToUInt32( (Byte[])rdata, 0); 223 System.Net.IPAddress address = new System.Net.IPAddress(bits); 224 225 peer.Address = address; 226 } 227 228 public void 229 OperationFailed 230 ( 231 DNSSDService service, 232 DNSSDError error 233 ) 234 { 235 MessageBox.Show("Operation returned an error code " + error, "Error"); 236 } 237 238 // 239 // OnReadMessage 240 // 241 // Called when there is data to be read on a socket 242 // 243 // This is called (indirectly) from OnReadSocket() 244 // 245 private void 246 OnReadMessage 247 ( 248 String msg 249 ) 250 { 251 int rgb = 0; 252 253 for (int i = 0; i < msg.Length && msg[i] != ':'; i++) 254 { 255 rgb = rgb ^ ((int)msg[i] << (i % 3 + 2) * 8); 256 257 } 258 259 Color color = Color.FromArgb(rgb & 0x007F7FFF); 260 261 richTextBox1.SelectionColor = color; 262 richTextBox1.AppendText(msg + Environment.NewLine); 263 } 264 265 // 266 // OnReadSocket 267 // 268 // Called by the .NET core when there is data to be read on a socket 269 // 270 // This is called from a worker thread by the .NET core 271 // 272 private void 273 OnReadSocket 274 ( 275 IAsyncResult ar 276 ) 277 { 278 try 279 { 280 int read = m_socket.EndReceive(ar); 281 282 if (read > 0) 283 { 284 String msg = Encoding.UTF8.GetString(m_buffer, 0, read); 285 Invoke(m_readMessageCallback, new Object[]{msg}); 286 } 287 288 m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), this); 289 } 290 catch 291 { 292 } 293 } 294 295 296 public SimpleChat() 297 { 298 // 299 // Required for Windows Form Designer support 300 // 301 InitializeComponent(); 302 303 try 304 { 305 m_service = new DNSSDService(); 306 } 307 catch 308 { 309 MessageBox.Show("Bonjour Service is not available", "Error"); 310 Application.Exit(); 311 } 312 313 // 314 // Associate event handlers with all the Bonjour events that the app is interested in. 315 // 316 m_eventManager = new DNSSDEventManager(); 317 m_eventManager.ServiceRegistered += new _IDNSSDEvents_ServiceRegisteredEventHandler(this.ServiceRegistered); 318 m_eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound); 319 m_eventManager.ServiceLost += new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost); 320 m_eventManager.ServiceResolved += new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved); 321 m_eventManager.QueryRecordAnswered += new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered); 322 m_eventManager.OperationFailed += new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed); 323 324 // 325 // Socket read handler 326 // 327 m_readMessageCallback = new ReadMessageCallback(OnReadMessage); 328 329 this.Load += new System.EventHandler(this.Form1_Load); 330 331 this.AcceptButton = button1; 332 } 333 334 /// <summary> 335 /// Clean up any resources being used. 336 /// </summary> 337 protected override void 338 Dispose( bool disposing ) 339 { 340 if( disposing ) 341 { 342 if (components != null) 343 { 344 components.Dispose(); 345 } 346 347 if (m_registrar != null) 348 { 349 m_registrar.Stop(); 350 } 351 352 if (m_browser != null) 353 { 354 m_browser.Stop(); 355 } 356 357 if (m_resolver != null) 358 { 359 m_resolver.Stop(); 360 } 361 362 m_eventManager.ServiceFound -= new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound); 363 m_eventManager.ServiceLost -= new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost); 364 m_eventManager.ServiceResolved -= new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved); 365 m_eventManager.QueryRecordAnswered -= new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered); 366 m_eventManager.OperationFailed -= new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed); 367 } 368 base.Dispose( disposing ); 369 } 370 371 #region Windows Form Designer generated code 372 /// <summary> 373 /// Required method for Designer support - do not modify 374 /// the contents of this method with the code editor. 375 /// </summary> 376 private void InitializeComponent() 377 { 378 this.comboBox1 = new System.Windows.Forms.ComboBox(); 379 this.textBox2 = new System.Windows.Forms.TextBox(); 380 this.button1 = new System.Windows.Forms.Button(); 381 this.label1 = new System.Windows.Forms.Label(); 382 this.richTextBox1 = new System.Windows.Forms.RichTextBox(); 383 this.SuspendLayout(); 384 // 385 // comboBox1 386 // 387 this.comboBox1.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 388 | System.Windows.Forms.AnchorStyles.Right); 389 this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 390 this.comboBox1.Location = new System.Drawing.Point(59, 208); 391 this.comboBox1.Name = "comboBox1"; 392 this.comboBox1.Size = new System.Drawing.Size(224, 21); 393 this.comboBox1.Sorted = true; 394 this.comboBox1.TabIndex = 5; 395 this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); 396 // 397 // textBox2 398 // 399 this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 400 | System.Windows.Forms.AnchorStyles.Right); 401 this.textBox2.Location = new System.Drawing.Point(8, 248); 402 this.textBox2.Name = "textBox2"; 403 this.textBox2.ScrollBars = System.Windows.Forms.ScrollBars.Horizontal; 404 this.textBox2.Size = new System.Drawing.Size(192, 20); 405 this.textBox2.TabIndex = 2; 406 this.textBox2.Text = ""; 407 this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged); 408 // 409 // button1 410 // 411 this.button1.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right); 412 this.button1.Enabled = false; 413 this.button1.Location = new System.Drawing.Point(208, 248); 414 this.button1.Name = "button1"; 415 this.button1.TabIndex = 3; 416 this.button1.Text = "Send"; 417 this.button1.Click += new System.EventHandler(this.button1_Click); 418 // 419 // label1 420 // 421 this.label1.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left); 422 this.label1.Location = new System.Drawing.Point(8, 210); 423 this.label1.Name = "label1"; 424 this.label1.Size = new System.Drawing.Size(48, 16); 425 this.label1.TabIndex = 4; 426 this.label1.Text = "Talk To:"; 427 // 428 // richTextBox1 429 // 430 this.richTextBox1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 431 | System.Windows.Forms.AnchorStyles.Left) 432 | System.Windows.Forms.AnchorStyles.Right); 433 this.richTextBox1.Location = new System.Drawing.Point(8, 8); 434 this.richTextBox1.Name = "richTextBox1"; 435 this.richTextBox1.ReadOnly = true; 436 this.richTextBox1.Size = new System.Drawing.Size(272, 184); 437 this.richTextBox1.TabIndex = 1; 438 this.richTextBox1.Text = ""; 439 // 440 // Form1 441 // 442 this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); 443 this.ClientSize = new System.Drawing.Size(292, 273); 444 this.Controls.AddRange(new System.Windows.Forms.Control[] { 445 this.richTextBox1, 446 this.label1, 447 this.button1, 448 this.textBox2, 449 this.comboBox1}); 450 this.Name = "Form1"; 451 this.Text = "SimpleChat.NET"; 452 this.ResumeLayout(false); 453 454 } 455 #endregion 456 457 private void Form1_Load(object sender, EventArgs e) 458 { 459 IPEndPoint localEP = new IPEndPoint(System.Net.IPAddress.Any, 0); 460 461 // 462 // create the socket and bind to INADDR_ANY 463 // 464 m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 465 m_socket.Bind(localEP); 466 localEP = (IPEndPoint) m_socket.LocalEndPoint; 467 468 // 469 // start asynchronous read 470 // 471 m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), this); 472 473 try 474 { 475 // 476 // start the register and browse operations 477 // 478 m_registrar = m_service.Register( 0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, ( ushort ) localEP.Port, null, m_eventManager ); 479 } 480 catch 481 { 482 MessageBox.Show("Bonjour service is not available", "Error"); 483 Application.Exit(); 484 } 485 } 486 487 /// <summary> 488 /// The main entry point for the application. 489 /// </summary> 490 [STAThread] 491 static void Main() 492 { 493 Application.Run(new SimpleChat()); 494 } 495 496 // 497 // send the message to a peer 498 // 499 private void button1_Click(object sender, System.EventArgs e) 500 { 501 PeerData peer = (PeerData) comboBox1.SelectedItem; 502 503 String message = m_name + ": " + textBox2.Text; 504 505 Byte[] bytes = Encoding.UTF8.GetBytes(message); 506 507 IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port ); 508 509 510 511 m_socket.SendTo(bytes, endPoint); 512 513 richTextBox1.SelectionColor = Color.Black; 514 515 richTextBox1.AppendText(textBox2.Text + "\n"); 516 517 textBox2.Text = ""; 518 } 519 520 // 521 // called when typing in message box 522 // 523 private void textBox2_TextChanged(object sender, System.EventArgs e) 524 { 525 PeerData peer = (PeerData) comboBox1.SelectedItem; 526 button1.Enabled = ((peer.Address != null) && (textBox2.Text.Length > 0)); 527 } 528 529 // 530 // called when peer target changes 531 // 532 /// <summary> 533 /// </summary> 534 /// <param name="sender"></param> 535 /// <param name="e"></param> 536 private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e) 537 { 538 PeerData peer = (PeerData) comboBox1.SelectedItem; 539 540 try 541 { 542 m_resolver = m_service.Resolve(0, peer.InterfaceIndex, peer.Name, peer.Type, peer.Domain, m_eventManager); 543 } 544 catch 545 { 546 MessageBox.Show("Unable to Resolve service", "Error"); 547 Application.Exit(); 548 } 549 } 550 } 551 552 // 553 // PeerData 554 // 555 // Holds onto the information associated with a peer on the network 556 // 557 public class PeerData 558 { 559 public uint InterfaceIndex; 560 public String Name; 561 public String Type; 562 public String Domain; 563 public IPAddress Address; 564 public int Port; 565 566 public override String 567 ToString() 568 { 569 return Name; 570 } 571 572 public override bool 573 Equals(object other) 574 { 575 bool result = false; 576 577 if (other != null) 578 { 579 if ((object)this == other) 580 { 581 result = true; 582 } 583 else if (other is PeerData) 584 { 585 PeerData otherPeerData = (PeerData)other; 586 587 result = (this.Name == otherPeerData.Name); 588 } 589 } 590 591 return result; 592 } 593 594 595 public override int 596 GetHashCode() 597 { 598 return Name.GetHashCode(); 599 } 600 }; 601} 602