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.
17 Change History (most recent first):
19 $Log: SimpleChat.cs,v $
20 Revision 1.7 2009/06/04 20:21:19 herscher
21 <rdar://problem/3948252> Update code to work with DNSSD COM component
23 Revision 1.6 2006/08/14 23:24:21 cheshire
24 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
26 Revision 1.5 2004/09/13 19:37:42 shersche
27 Change code to reflect namespace and type changes to dnssd.NET library
29 Revision 1.4 2004/09/11 05:42:56 shersche
30 don't reset SelectedIndex in OnRemove
32 Revision 1.3 2004/09/11 00:38:58 shersche
33 DNSService APIs now expect port in host format
35 Revision 1.2 2004/07/19 22:08:53 shersche
36 Fixed rdata->int conversion problem in QueryRecordReply
38 Revision 1.1 2004/07/19 07:57:08 shersche
47 using System.Collections;
48 using System.ComponentModel;
49 using System.Windows.Forms;
51 using System.Net.Sockets;
56 namespace SimpleChat.NET
59 /// Summary description for Form1.
63 public class SimpleChat : System.Windows.Forms.Form
65 private System.Windows.Forms.ComboBox comboBox1;
66 private System.Windows.Forms.TextBox textBox2;
67 private System.Windows.Forms.Button button1;
68 private System.Windows.Forms.Label label1;
69 private Bonjour.DNSSDEventManager m_eventManager = null;
70 private Bonjour.DNSSDService m_service = null;
71 private Bonjour.DNSSDService m_registrar = null;
72 private Bonjour.DNSSDService m_browser = null;
73 private Bonjour.DNSSDService m_resolver = null;
74 private String m_name;
75 private Socket m_socket = null;
76 private const int BUFFER_SIZE = 1024;
77 public byte[] m_buffer = new byte[BUFFER_SIZE];
78 public bool m_complete = false;
79 public StringBuilder m_sb = new StringBuilder();
80 delegate void ReadMessageCallback(String data);
81 ReadMessageCallback m_readMessageCallback;
83 /// Required designer variable.
85 private System.ComponentModel.Container components = null;
86 private System.Windows.Forms.RichTextBox richTextBox1;
90 // Called by DNSServices core as a result of Register()
108 m_browser = m_service.Browse(0, 0, "_p2pchat._udp", null, m_eventManager);
112 MessageBox.Show("Browse Failed", "Error");
120 // Called by DNSServices core as a result of a Browse call
134 if (serviceName != m_name)
136 PeerData peer = new PeerData();
138 peer.InterfaceIndex = ifIndex;
139 peer.Name = serviceName;
141 peer.Domain = domain;
144 comboBox1.Items.Add(peer);
146 if (comboBox1.Items.Count == 1)
148 comboBox1.SelectedIndex = 0;
156 // Called by DNSServices core as a result of a Browse call
170 PeerData peer = new PeerData();
172 peer.InterfaceIndex = ifIndex;
173 peer.Name = serviceName;
175 peer.Domain = domain;
178 comboBox1.Items.Remove(peer);
184 // Called by DNSServices core as a result of DNSService.Resolve()
203 PeerData peer = (PeerData)comboBox1.SelectedItem;
209 m_resolver = m_service.QueryRecord(0, ifIndex, hostName, DNSSDRRType.kDNSSDType_A, DNSSDRRClass.kDNSSDClass_IN, m_eventManager );
213 MessageBox.Show("QueryRecord Failed", "Error");
221 // Called by DNSServices core as a result of DNSService.QueryRecord()
228 DNSSDService service,
233 DNSSDRRClass rrclass,
241 PeerData peer = (PeerData) comboBox1.SelectedItem;
243 uint bits = BitConverter.ToUInt32( (Byte[])rdata, 0);
244 System.Net.IPAddress address = new System.Net.IPAddress(bits);
246 peer.Address = address;
252 DNSSDService service,
256 MessageBox.Show("Operation returned an error code " + error, "Error");
262 // Called when there is data to be read on a socket
264 // This is called (indirectly) from OnReadSocket()
274 for (int i = 0; i < msg.Length && msg[i] != ':'; i++)
276 rgb = rgb ^ ((int)msg[i] << (i % 3 + 2) * 8);
279 Color color = Color.FromArgb(rgb & 0x007F7FFF);
280 richTextBox1.SelectionColor = color;
281 richTextBox1.AppendText(msg + Environment.NewLine);
287 // Called by the .NET core when there is data to be read on a socket
289 // This is called from a worker thread by the .NET core
299 int read = m_socket.EndReceive(ar);
303 String msg = Encoding.UTF8.GetString(m_buffer, 0, read);
304 Invoke(m_readMessageCallback, new Object[]{msg});
307 m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), this);
318 // Required for Windows Form Designer support
320 InitializeComponent();
324 m_service = new DNSSDService();
328 MessageBox.Show("Bonjour Service is not available", "Error");
332 m_eventManager = new DNSSDEventManager();
333 m_eventManager.ServiceRegistered += new _IDNSSDEvents_ServiceRegisteredEventHandler(this.ServiceRegistered);
334 m_eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound);
335 m_eventManager.ServiceLost += new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost);
336 m_eventManager.ServiceResolved += new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved);
337 m_eventManager.QueryRecordAnswered += new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered);
338 m_eventManager.OperationFailed += new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed);
340 m_readMessageCallback = new ReadMessageCallback(OnReadMessage);
342 this.Load += new System.EventHandler(this.Form1_Load);
344 this.AcceptButton = button1;
348 /// Clean up any resources being used.
350 protected override void
351 Dispose( bool disposing )
355 if (components != null)
357 components.Dispose();
360 if (m_registrar != null)
365 if (m_browser != null)
370 if (m_resolver != null)
375 m_eventManager.ServiceFound -= new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound);
376 m_eventManager.ServiceLost -= new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost);
377 m_eventManager.ServiceResolved -= new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved);
378 m_eventManager.QueryRecordAnswered -= new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered);
379 m_eventManager.OperationFailed -= new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed);
381 base.Dispose( disposing );
384 #region Windows Form Designer generated code
386 /// Required method for Designer support - do not modify
387 /// the contents of this method with the code editor.
389 private void InitializeComponent()
391 this.comboBox1 = new System.Windows.Forms.ComboBox();
392 this.textBox2 = new System.Windows.Forms.TextBox();
393 this.button1 = new System.Windows.Forms.Button();
394 this.label1 = new System.Windows.Forms.Label();
395 this.richTextBox1 = new System.Windows.Forms.RichTextBox();
396 this.SuspendLayout();
400 this.comboBox1.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
401 | System.Windows.Forms.AnchorStyles.Right);
402 this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
403 this.comboBox1.Location = new System.Drawing.Point(59, 208);
404 this.comboBox1.Name = "comboBox1";
405 this.comboBox1.Size = new System.Drawing.Size(224, 21);
406 this.comboBox1.Sorted = true;
407 this.comboBox1.TabIndex = 5;
408 this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
412 this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
413 | System.Windows.Forms.AnchorStyles.Right);
414 this.textBox2.Location = new System.Drawing.Point(8, 248);
415 this.textBox2.Name = "textBox2";
416 this.textBox2.ScrollBars = System.Windows.Forms.ScrollBars.Horizontal;
417 this.textBox2.Size = new System.Drawing.Size(192, 20);
418 this.textBox2.TabIndex = 2;
419 this.textBox2.Text = "";
420 this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged);
424 this.button1.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right);
425 this.button1.Enabled = false;
426 this.button1.Location = new System.Drawing.Point(208, 248);
427 this.button1.Name = "button1";
428 this.button1.TabIndex = 3;
429 this.button1.Text = "Send";
430 this.button1.Click += new System.EventHandler(this.button1_Click);
434 this.label1.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left);
435 this.label1.Location = new System.Drawing.Point(8, 210);
436 this.label1.Name = "label1";
437 this.label1.Size = new System.Drawing.Size(48, 16);
438 this.label1.TabIndex = 4;
439 this.label1.Text = "Talk To:";
443 this.richTextBox1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
444 | System.Windows.Forms.AnchorStyles.Left)
445 | System.Windows.Forms.AnchorStyles.Right);
446 this.richTextBox1.Location = new System.Drawing.Point(8, 8);
447 this.richTextBox1.Name = "richTextBox1";
448 this.richTextBox1.ReadOnly = true;
449 this.richTextBox1.Size = new System.Drawing.Size(272, 184);
450 this.richTextBox1.TabIndex = 1;
451 this.richTextBox1.Text = "";
455 this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
456 this.ClientSize = new System.Drawing.Size(292, 273);
457 this.Controls.AddRange(new System.Windows.Forms.Control[] {
464 this.Text = "SimpleChat.NET";
465 this.ResumeLayout(false);
470 private void Form1_Load(object sender, EventArgs e)
472 IPEndPoint localEP = new IPEndPoint(System.Net.IPAddress.Any, 0);
475 // create the socket and bind to INADDR_ANY
477 m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
478 m_socket.Bind(localEP);
479 localEP = (IPEndPoint) m_socket.LocalEndPoint;
482 // start asynchronous read
484 m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), this);
489 // start the register and browse operations
491 m_registrar = m_service.Register( 0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, ( ushort ) localEP.Port, null, m_eventManager );
495 MessageBox.Show("Bonjour service is not available", "Error");
501 /// The main entry point for the application.
506 Application.Run(new SimpleChat());
510 // send the message to a peer
512 private void button1_Click(object sender, System.EventArgs e)
514 PeerData peer = (PeerData) comboBox1.SelectedItem;
516 String message = m_name + ": " + textBox2.Text;
518 Byte[] bytes = Encoding.UTF8.GetBytes(message);
520 IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port );
522 m_socket.SendTo(bytes, endPoint);
524 richTextBox1.SelectionColor = Color.Black;
526 richTextBox1.AppendText(textBox2.Text + "\n");
532 // called when typing in message box
534 private void textBox2_TextChanged(object sender, System.EventArgs e)
536 PeerData peer = (PeerData) comboBox1.SelectedItem;
537 button1.Enabled = ((peer.Address != null) && (textBox2.Text.Length > 0));
541 // called when peer target changes
545 /// <param name="sender"></param>
546 /// <param name="e"></param>
547 private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)
549 PeerData peer = (PeerData) comboBox1.SelectedItem;
553 m_resolver = m_service.Resolve(0, peer.InterfaceIndex, peer.Name, peer.Type, peer.Domain, m_eventManager);
557 MessageBox.Show("Unable to Resolve service", "Error");
566 // Holds onto the information associated with a peer on the network
568 public class PeerData
570 public uint InterfaceIndex;
573 public String Domain;
574 public IPAddress Address;
577 public override String
590 if ((object)this == other)
594 else if (other is PeerData)
596 PeerData otherPeerData = (PeerData)other;
598 result = (this.Name == otherPeerData.Name);
608 return Name.GetHashCode();