/* -*- Mode: C; tab-width: 4 -*- * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Net; using System.Net.Sockets; using System.Data; using System.Text; using Bonjour; namespace SimpleChat.NET { /// /// Summary description for Form1. /// /// public class SimpleChat : System.Windows.Forms.Form { private System.Windows.Forms.ComboBox comboBox1; private System.Windows.Forms.TextBox textBox2; private System.Windows.Forms.Button button1; private System.Windows.Forms.Label label1; private Bonjour.DNSSDEventManager m_eventManager = null; private Bonjour.DNSSDService m_service = null; private Bonjour.DNSSDService m_registrar = null; private Bonjour.DNSSDService m_browser = null; private Bonjour.DNSSDService m_resolver = null; private String m_name; private Socket m_socket = null; private const int BUFFER_SIZE = 1024; public byte[] m_buffer = new byte[BUFFER_SIZE]; public bool m_complete = false; public StringBuilder m_sb = new StringBuilder(); delegate void ReadMessageCallback(String data); ReadMessageCallback m_readMessageCallback; /// /// Required designer variable. /// private System.ComponentModel.Container components = null; private System.Windows.Forms.RichTextBox richTextBox1; // ServiceRegistered // // Called by DNSServices core as a result of Register() // call // public void ServiceRegistered ( DNSSDService service, DNSSDFlags flags, String name, String regType, String domain ) { m_name = name; // // Try to start browsing for other instances of this service // try { m_browser = m_service.Browse(0, 0, "_p2pchat._udp", null, m_eventManager); } catch { MessageBox.Show("Browse Failed", "Error"); Application.Exit(); } } // // ServiceFound // // Called by DNSServices core as a result of a Browse call // public void ServiceFound ( DNSSDService sref, DNSSDFlags flags, uint ifIndex, String serviceName, String regType, String domain ) { if (serviceName != m_name) { PeerData peer = new PeerData(); peer.InterfaceIndex = ifIndex; peer.Name = serviceName; peer.Type = regType; peer.Domain = domain; peer.Address = null; comboBox1.Items.Add(peer); if (comboBox1.Items.Count == 1) { comboBox1.SelectedIndex = 0; } } } // // ServiceLost // // Called by DNSServices core as a result of a Browse call // public void ServiceLost ( DNSSDService sref, DNSSDFlags flags, uint ifIndex, String serviceName, String regType, String domain ) { PeerData peer = new PeerData(); peer.InterfaceIndex = ifIndex; peer.Name = serviceName; peer.Type = regType; peer.Domain = domain; peer.Address = null; comboBox1.Items.Remove(peer); } // // ServiceResolved // // Called by DNSServices core as a result of DNSService.Resolve() // call // public void ServiceResolved ( DNSSDService sref, DNSSDFlags flags, uint ifIndex, String fullName, String hostName, ushort port, TXTRecord txtRecord ) { m_resolver.Stop(); m_resolver = null; PeerData peer = (PeerData)comboBox1.SelectedItem; peer.Port = port; // // Query for the IP address associated with "hostName" // try { m_resolver = m_service.QueryRecord(0, ifIndex, hostName, DNSSDRRType.kDNSSDType_A, DNSSDRRClass.kDNSSDClass_IN, m_eventManager ); } catch { MessageBox.Show("QueryRecord Failed", "Error"); Application.Exit(); } } // // QueryAnswered // // Called by DNSServices core as a result of DNSService.QueryRecord() // call // public void QueryAnswered ( DNSSDService service, DNSSDFlags flags, uint ifIndex, String fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, Object rdata, uint ttl ) { // // Stop the resolve to reduce the burden on the network // m_resolver.Stop(); m_resolver = null; PeerData peer = (PeerData) comboBox1.SelectedItem; uint bits = BitConverter.ToUInt32( (Byte[])rdata, 0); System.Net.IPAddress address = new System.Net.IPAddress(bits); peer.Address = address; } public void OperationFailed ( DNSSDService service, DNSSDError error ) { MessageBox.Show("Operation returned an error code " + error, "Error"); } // // OnReadMessage // // Called when there is data to be read on a socket // // This is called (indirectly) from OnReadSocket() // private void OnReadMessage ( String msg ) { int rgb = 0; for (int i = 0; i < msg.Length && msg[i] != ':'; i++) { rgb = rgb ^ ((int)msg[i] << (i % 3 + 2) * 8); } Color color = Color.FromArgb(rgb & 0x007F7FFF); richTextBox1.SelectionColor = color; richTextBox1.AppendText(msg + Environment.NewLine); } // // OnReadSocket // // Called by the .NET core when there is data to be read on a socket // // This is called from a worker thread by the .NET core // private void OnReadSocket ( IAsyncResult ar ) { try { int read = m_socket.EndReceive(ar); if (read > 0) { String msg = Encoding.UTF8.GetString(m_buffer, 0, read); Invoke(m_readMessageCallback, new Object[]{msg}); } m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), this); } catch { } } public SimpleChat() { // // Required for Windows Form Designer support // InitializeComponent(); try { m_service = new DNSSDService(); } catch { MessageBox.Show("Bonjour Service is not available", "Error"); Application.Exit(); } // // Associate event handlers with all the Bonjour events that the app is interested in. // m_eventManager = new DNSSDEventManager(); m_eventManager.ServiceRegistered += new _IDNSSDEvents_ServiceRegisteredEventHandler(this.ServiceRegistered); m_eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound); m_eventManager.ServiceLost += new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost); m_eventManager.ServiceResolved += new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved); m_eventManager.QueryRecordAnswered += new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered); m_eventManager.OperationFailed += new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed); // // Socket read handler // m_readMessageCallback = new ReadMessageCallback(OnReadMessage); this.Load += new System.EventHandler(this.Form1_Load); this.AcceptButton = button1; } /// /// Clean up any resources being used. /// protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } if (m_registrar != null) { m_registrar.Stop(); } if (m_browser != null) { m_browser.Stop(); } if (m_resolver != null) { m_resolver.Stop(); } m_eventManager.ServiceFound -= new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound); m_eventManager.ServiceLost -= new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost); m_eventManager.ServiceResolved -= new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved); m_eventManager.QueryRecordAnswered -= new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered); m_eventManager.OperationFailed -= new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed); } base.Dispose( disposing ); } #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.comboBox1 = new System.Windows.Forms.ComboBox(); this.textBox2 = new System.Windows.Forms.TextBox(); this.button1 = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.richTextBox1 = new System.Windows.Forms.RichTextBox(); this.SuspendLayout(); // // comboBox1 // this.comboBox1.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right); this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBox1.Location = new System.Drawing.Point(59, 208); this.comboBox1.Name = "comboBox1"; this.comboBox1.Size = new System.Drawing.Size(224, 21); this.comboBox1.Sorted = true; this.comboBox1.TabIndex = 5; this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); // // textBox2 // this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right); this.textBox2.Location = new System.Drawing.Point(8, 248); this.textBox2.Name = "textBox2"; this.textBox2.ScrollBars = System.Windows.Forms.ScrollBars.Horizontal; this.textBox2.Size = new System.Drawing.Size(192, 20); this.textBox2.TabIndex = 2; this.textBox2.Text = ""; this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged); // // button1 // this.button1.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right); this.button1.Enabled = false; this.button1.Location = new System.Drawing.Point(208, 248); this.button1.Name = "button1"; this.button1.TabIndex = 3; this.button1.Text = "Send"; this.button1.Click += new System.EventHandler(this.button1_Click); // // label1 // this.label1.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left); this.label1.Location = new System.Drawing.Point(8, 210); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(48, 16); this.label1.TabIndex = 4; this.label1.Text = "Talk To:"; // // richTextBox1 // this.richTextBox1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right); this.richTextBox1.Location = new System.Drawing.Point(8, 8); this.richTextBox1.Name = "richTextBox1"; this.richTextBox1.ReadOnly = true; this.richTextBox1.Size = new System.Drawing.Size(272, 184); this.richTextBox1.TabIndex = 1; this.richTextBox1.Text = ""; // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 273); this.Controls.AddRange(new System.Windows.Forms.Control[] { this.richTextBox1, this.label1, this.button1, this.textBox2, this.comboBox1}); this.Name = "Form1"; this.Text = "SimpleChat.NET"; this.ResumeLayout(false); } #endregion private void Form1_Load(object sender, EventArgs e) { IPEndPoint localEP = new IPEndPoint(System.Net.IPAddress.Any, 0); // // create the socket and bind to INADDR_ANY // m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); m_socket.Bind(localEP); localEP = (IPEndPoint) m_socket.LocalEndPoint; // // start asynchronous read // m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), this); try { // // start the register and browse operations // m_registrar = m_service.Register( 0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, ( ushort ) localEP.Port, null, m_eventManager ); } catch { MessageBox.Show("Bonjour service is not available", "Error"); Application.Exit(); } } /// /// The main entry point for the application. /// [STAThread] static void Main() { Application.Run(new SimpleChat()); } // // send the message to a peer // private void button1_Click(object sender, System.EventArgs e) { PeerData peer = (PeerData) comboBox1.SelectedItem; String message = m_name + ": " + textBox2.Text; Byte[] bytes = Encoding.UTF8.GetBytes(message); IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port ); m_socket.SendTo(bytes, endPoint); richTextBox1.SelectionColor = Color.Black; richTextBox1.AppendText(textBox2.Text + "\n"); textBox2.Text = ""; } // // called when typing in message box // private void textBox2_TextChanged(object sender, System.EventArgs e) { PeerData peer = (PeerData) comboBox1.SelectedItem; button1.Enabled = ((peer.Address != null) && (textBox2.Text.Length > 0)); } // // called when peer target changes // /// /// /// /// private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e) { PeerData peer = (PeerData) comboBox1.SelectedItem; try { m_resolver = m_service.Resolve(0, peer.InterfaceIndex, peer.Name, peer.Type, peer.Domain, m_eventManager); } catch { MessageBox.Show("Unable to Resolve service", "Error"); Application.Exit(); } } } // // PeerData // // Holds onto the information associated with a peer on the network // public class PeerData { public uint InterfaceIndex; public String Name; public String Type; public String Domain; public IPAddress Address; public int Port; public override String ToString() { return Name; } public override bool Equals(object other) { bool result = false; if (other != null) { if ((object)this == other) { result = true; } else if (other is PeerData) { PeerData otherPeerData = (PeerData)other; result = (this.Name == otherPeerData.Name); } } return result; } public override int GetHashCode() { return Name.GetHashCode(); } }; }