1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 using System.Collections;
21 using System.ComponentModel;
22 using System.Windows.Forms;
24 using System.Net.Sockets;
29 namespace SimpleChat.NET
32 /// Summary description for Form1.
36 public class SimpleChat : System.Windows.Forms.Form
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;
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();
55 delegate void ReadMessageCallback(String data);
57 ReadMessageCallback m_readMessageCallback;
59 /// Required designer variable.
61 private System.ComponentModel.Container components = null;
62 private System.Windows.Forms.RichTextBox richTextBox1;
66 // Called by DNSServices core as a result of Register()
82 // Try to start browsing for other instances of this service
86 m_browser = m_service.Browse(0, 0, "_p2pchat._udp", null, m_eventManager);
90 MessageBox.Show("Browse Failed", "Error");
98 // Called by DNSServices core as a result of a Browse call
111 if (serviceName != m_name)
113 PeerData peer = new PeerData();
115 peer.InterfaceIndex = ifIndex;
116 peer.Name = serviceName;
118 peer.Domain = domain;
121 comboBox1.Items.Add(peer);
123 if (comboBox1.Items.Count == 1)
125 comboBox1.SelectedIndex = 0;
133 // Called by DNSServices core as a result of a Browse call
146 PeerData peer = new PeerData();
148 peer.InterfaceIndex = ifIndex;
149 peer.Name = serviceName;
151 peer.Domain = domain;
154 comboBox1.Items.Remove(peer);
160 // Called by DNSServices core as a result of DNSService.Resolve()
178 PeerData peer = (PeerData)comboBox1.SelectedItem;
183 // Query for the IP address associated with "hostName"
187 m_resolver = m_service.QueryRecord(0, ifIndex, hostName, DNSSDRRType.kDNSSDType_A, DNSSDRRClass.kDNSSDClass_IN, m_eventManager );
191 MessageBox.Show("QueryRecord Failed", "Error");
199 // Called by DNSServices core as a result of DNSService.QueryRecord()
205 DNSSDService service,
210 DNSSDRRClass rrclass,
216 // Stop the resolve to reduce the burden on the network
221 PeerData peer = (PeerData) comboBox1.SelectedItem;
222 uint bits = BitConverter.ToUInt32( (Byte[])rdata, 0);
223 System.Net.IPAddress address = new System.Net.IPAddress(bits);
225 peer.Address = address;
231 DNSSDService service,
235 MessageBox.Show("Operation returned an error code " + error, "Error");
241 // Called when there is data to be read on a socket
243 // This is called (indirectly) from OnReadSocket()
253 for (int i = 0; i < msg.Length && msg[i] != ':'; i++)
255 rgb = rgb ^ ((int)msg[i] << (i % 3 + 2) * 8);
259 Color color = Color.FromArgb(rgb & 0x007F7FFF);
261 richTextBox1.SelectionColor = color;
262 richTextBox1.AppendText(msg + Environment.NewLine);
268 // Called by the .NET core when there is data to be read on a socket
270 // This is called from a worker thread by the .NET core
280 int read = m_socket.EndReceive(ar);
284 String msg = Encoding.UTF8.GetString(m_buffer, 0, read);
285 Invoke(m_readMessageCallback, new Object[]{msg});
288 m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), this);
299 // Required for Windows Form Designer support
301 InitializeComponent();
305 m_service = new DNSSDService();
309 MessageBox.Show("Bonjour Service is not available", "Error");
314 // Associate event handlers with all the Bonjour events that the app is interested in.
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);
325 // Socket read handler
327 m_readMessageCallback = new ReadMessageCallback(OnReadMessage);
329 this.Load += new System.EventHandler(this.Form1_Load);
331 this.AcceptButton = button1;
335 /// Clean up any resources being used.
337 protected override void
338 Dispose( bool disposing )
342 if (components != null)
344 components.Dispose();
347 if (m_registrar != null)
352 if (m_browser != null)
357 if (m_resolver != null)
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);
368 base.Dispose( disposing );
371 #region Windows Form Designer generated code
373 /// Required method for Designer support - do not modify
374 /// the contents of this method with the code editor.
376 private void InitializeComponent()
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();
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);
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);
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);
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:";
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 = "";
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[] {
451 this.Text = "SimpleChat.NET";
452 this.ResumeLayout(false);
457 private void Form1_Load(object sender, EventArgs e)
459 IPEndPoint localEP = new IPEndPoint(System.Net.IPAddress.Any, 0);
462 // create the socket and bind to INADDR_ANY
464 m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
465 m_socket.Bind(localEP);
466 localEP = (IPEndPoint) m_socket.LocalEndPoint;
469 // start asynchronous read
471 m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), this);
476 // start the register and browse operations
478 m_registrar = m_service.Register( 0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, ( ushort ) localEP.Port, null, m_eventManager );
482 MessageBox.Show("Bonjour service is not available", "Error");
488 /// The main entry point for the application.
493 Application.Run(new SimpleChat());
497 // send the message to a peer
499 private void button1_Click(object sender, System.EventArgs e)
501 PeerData peer = (PeerData) comboBox1.SelectedItem;
503 String message = m_name + ": " + textBox2.Text;
505 Byte[] bytes = Encoding.UTF8.GetBytes(message);
507 IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port );
511 m_socket.SendTo(bytes, endPoint);
513 richTextBox1.SelectionColor = Color.Black;
515 richTextBox1.AppendText(textBox2.Text + "\n");
521 // called when typing in message box
523 private void textBox2_TextChanged(object sender, System.EventArgs e)
525 PeerData peer = (PeerData) comboBox1.SelectedItem;
526 button1.Enabled = ((peer.Address != null) && (textBox2.Text.Length > 0));
530 // called when peer target changes
534 /// <param name="sender"></param>
535 /// <param name="e"></param>
536 private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)
538 PeerData peer = (PeerData) comboBox1.SelectedItem;
542 m_resolver = m_service.Resolve(0, peer.InterfaceIndex, peer.Name, peer.Type, peer.Domain, m_eventManager);
546 MessageBox.Show("Unable to Resolve service", "Error");
555 // Holds onto the information associated with a peer on the network
557 public class PeerData
559 public uint InterfaceIndex;
562 public String Domain;
563 public IPAddress Address;
566 public override String
579 if ((object)this == other)
583 else if (other is PeerData)
585 PeerData otherPeerData = (PeerData)other;
587 result = (this.Name == otherPeerData.Name);
598 return Name.GetHashCode();