X-Git-Url: https://git.saurik.com/apple/mdnsresponder.git/blobdiff_plain/8e92c31c9a45a66732f5bc7afbc9f5596c17e91d..7f0064bd55e3fa98568d2c359429ff8a38b23a6c:/Clients/SimpleChat.NET/SimpleChat.cs diff --git a/Clients/SimpleChat.NET/SimpleChat.cs b/Clients/SimpleChat.NET/SimpleChat.cs new file mode 100755 index 0000000..fb841f2 --- /dev/null +++ b/Clients/SimpleChat.NET/SimpleChat.cs @@ -0,0 +1,757 @@ +/* + * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + + Change History (most recent first): + +$Log: SimpleChat.cs,v $ +Revision 1.5 2004/09/13 19:37:42 shersche +Change code to reflect namespace and type changes to dnssd.NET library + +Revision 1.4 2004/09/11 05:42:56 shersche +don't reset SelectedIndex in OnRemove + +Revision 1.3 2004/09/11 00:38:58 shersche +DNSService APIs now expect port in host format + +Revision 1.2 2004/07/19 22:08:53 shersche +Fixed rdata->int conversion problem in QueryRecordReply + +Revision 1.1 2004/07/19 07:57:08 shersche +Initial revision + + + +*/ + +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 Apple.DNSSD; + +namespace SimpleChat.NET +{ + /// + /// Summary description for Form1. + /// + /// + + // + // PeerData + // + // Holds onto the information associated with a peer on the network + // + public class PeerData + { + public int 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(); + } + }; + + // + // ResolveData + // + // Holds onto the information associated with the resolution + // of a DNSService + // + public class ResolveData + { + public int InterfaceIndex; + public String FullName; + public String HostName; + public int Port; + public Byte[] TxtRecord; + + public override String + ToString() + { + return FullName; + } + }; + + + // + // SocketStateObject + // + // Holds onto the data associated with an asynchronous + // socket operation + // + class SocketStateObject + { + public const int BUFFER_SIZE = 1024; + private Socket m_socket; + public byte[] m_buffer; + public bool m_complete; + public StringBuilder m_sb = new StringBuilder(); + + public SocketStateObject(Socket socket) + { + m_buffer = new byte[BUFFER_SIZE]; + m_complete = false; + m_socket = socket; + } + + public Socket + WorkSocket + { + get + { + return m_socket; + } + } + } + public class Form1 : 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 ServiceRef registrar = null; + private ServiceRef browser = null; + private ServiceRef resolver = null; + private String myName; + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + + // + // These all of our callbacks. These are invoked in the context + // of the main (GUI) thread. The DNSService callbacks Invoke() + // them + delegate void RegisterServiceCallback(String name); + delegate void AddPeerCallback(PeerData data); + delegate void RemovePeerCallback(PeerData data); + delegate void ResolveServiceCallback(ResolveData data); + delegate void ResolveAddressCallback(System.Net.IPAddress address); + delegate void ReadMessageCallback(String data); + + RegisterServiceCallback registerServiceCallback; + AddPeerCallback addPeerCallback; + RemovePeerCallback removePeerCallback; + ResolveServiceCallback resolveServiceCallback; + ResolveAddressCallback resolveAddressCallback; + ReadMessageCallback readMessageCallback; + private System.Windows.Forms.RichTextBox richTextBox1; + + // + // The socket that we will be reading data from + // + Socket socket = null; + + // + // OnRegisterService + // + // The name that we are passed might be different than the + // name we called Register with. So we hold onto this name + // rather than the name we Register with. + // + // This is called (indirectly) from OnRegisterReply(). + // + private void + OnRegisterService + ( + String name + ) + { + myName = name; + } + + // + // OnAddPeer + // + // Called when DNSServices detects a new P2P Chat peer has + // joined. + // + // This is called (indirectly) from OnBrowseReply() + // + private void + OnAddPeer + ( + PeerData peer + ) + { + comboBox1.Items.Add(peer); + + if (comboBox1.Items.Count == 1) + { + comboBox1.SelectedIndex = 0; + } + } + + // + // OnRemovePeer + // + // Called when DNSServices detects a P2P peer has left + // the network + // + // This is called (indirectly) from OnBrowseReply() + // + private void + OnRemovePeer + ( + PeerData peer + ) + { + comboBox1.Items.Remove(peer); + } + + // + // OnResolveService + // + // Called when DNSServices has resolved a service. + // + // This is called (indirectly) from OnResolveService() + // + private void + OnResolveService + ( + ResolveData data + ) + { + resolver.Dispose(); + + PeerData peer = (PeerData) comboBox1.SelectedItem; + + peer.Port = data.Port; + + try + { + resolver = DNSService.QueryRecord(0, 0, data.HostName, /* ns_t_a */ 1, /* ns_t_c */ 1, new DNSService.QueryRecordReply(OnQueryRecordReply)); + } + catch + { + MessageBox.Show("QueryRecord Failed", "Error"); + Application.Exit(); + } + } + + // + // OnResolveAddress + // + // Called when DNSServices has finished a query operation + // + // This is called (indirectly) from OnQueryRecordReply() + // + private void + OnResolveAddress + ( + System.Net.IPAddress address + ) + { + resolver.Dispose(); + + PeerData peer = (PeerData) comboBox1.SelectedItem; + + peer.Address = address; + } + + // + // 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 + "\n"); + } + + // + // OnRegisterReply + // + // Called by DNSServices core as a result of DNSService.Register() + // call + // + // This is called from a worker thread by DNSService core. + // + private void + OnRegisterReply + ( + ServiceRef sdRef, + ServiceFlags flags, + ErrorCode errorCode, + String name, + String regtype, + String domain) + { + if (errorCode == ErrorCode.NoError) + { + Invoke(registerServiceCallback, new Object[]{name}); + } + else + { + MessageBox.Show("OnRegisterReply returned an error code " + errorCode, "Error"); + } + } + + + // + // OnBrowseReply + // + // Called by DNSServices core as a result of DNSService.Browse() + // call + // + // This is called from a worker thread by DNSService core. + // + private void + OnBrowseReply + ( + ServiceRef sdRef, + ServiceFlags flags, + int interfaceIndex, + ErrorCode errorCode, + String name, + String type, + String domain) + { + if (errorCode == ErrorCode.NoError) + { + PeerData peer = new PeerData(); + + peer.InterfaceIndex = interfaceIndex; + peer.Name = name; + peer.Type = type; + peer.Domain = domain; + peer.Address = null; + + if ((flags & ServiceFlags.Add) != 0) + { + Invoke(addPeerCallback, new Object[]{peer}); + } + else if ((flags == 0) || ((flags & ServiceFlags.MoreComing) != 0)) + { + Invoke(removePeerCallback, new Object[]{peer}); + } + } + else + { + MessageBox.Show("OnBrowseReply returned an error code " + errorCode, "Error"); + } + } + + // + // OnResolveReply + // + // Called by DNSServices core as a result of DNSService.Resolve() + // call + // + // This is called from a worker thread by DNSService core. + // + private void + OnResolveReply + ( + ServiceRef sdRef, + ServiceFlags flags, + int interfaceIndex, + ErrorCode errorCode, + String fullName, + String hostName, + int port, + Byte[] txtRecord + ) + { + if (errorCode == ErrorCode.NoError) + { + ResolveData data = new ResolveData(); + + data.InterfaceIndex = interfaceIndex; + data.FullName = fullName; + data.HostName = hostName; + data.Port = port; + data.TxtRecord = txtRecord; + + Invoke(resolveServiceCallback, new Object[]{data}); + } + else + { + MessageBox.Show("OnResolveReply returned an error code: " + errorCode, "Error"); + } + } + + // + // OnQueryRecordReply + // + // Called by DNSServices core as a result of DNSService.QueryRecord() + // call + // + // This is called from a worker thread by DNSService core. + // + private void + OnQueryRecordReply + ( + ServiceRef sdRef, + ServiceFlags flags, + int interfaceIndex, + ErrorCode errorCode, + String fullName, + int rrtype, + int rrclass, + Byte[] rdata, + int ttl + ) + { + if (errorCode == ErrorCode.NoError) + { + uint bits = BitConverter.ToUInt32(rdata, 0); + System.Net.IPAddress data = new System.Net.IPAddress(bits); + + Invoke(resolveAddressCallback, new Object[]{data}); + } + else + { + MessageBox.Show("OnQueryRecordReply returned an error code: " + errorCode, "Error"); + } + } + + // + // 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 + ) + { + SocketStateObject so = (SocketStateObject) ar.AsyncState; + Socket s = so.WorkSocket; + + try + { + if (s == null) + { + return; + } + + int read = s.EndReceive(ar); + + if (read > 0) + { + String msg = Encoding.UTF8.GetString(so.m_buffer, 0, read); + + Invoke(readMessageCallback, new Object[]{msg}); + } + + s.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), so); + } + catch + { + } + } + + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + registerServiceCallback = new RegisterServiceCallback(OnRegisterService); + addPeerCallback = new AddPeerCallback(OnAddPeer); + removePeerCallback = new RemovePeerCallback(OnRemovePeer); + resolveServiceCallback = new ResolveServiceCallback(OnResolveService); + resolveAddressCallback = new ResolveAddressCallback(OnResolveAddress); + 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 (registrar != null) + { + registrar.Dispose(); + } + + if (browser != null) + { + browser.Dispose(); + } + } + 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 + // + socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + socket.Bind(localEP); + localEP = (IPEndPoint) socket.LocalEndPoint; + + // + // start asynchronous read + // + SocketStateObject so = new SocketStateObject(socket); + socket.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), so); + + try + { + // + // start the register and browse operations + // + registrar = DNSService.Register(0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, localEP.Port, null, new DNSService.RegisterReply(OnRegisterReply)); + browser = DNSService.Browse(0, 0, "_p2pchat._udp", null, new DNSService.BrowseReply(OnBrowseReply)); + } + catch + { + MessageBox.Show("DNSServices Not Available", "Error"); + Application.Exit(); + } + } + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.Run(new Form1()); + } + + // + // send the message to a peer + // + private void button1_Click(object sender, System.EventArgs e) + { + PeerData peer = (PeerData) comboBox1.SelectedItem; + + String message = myName + ": " + textBox2.Text; + + Byte[] bytes = Encoding.UTF8.GetBytes(message); + + UdpClient udpSocket = new UdpClient(peer.Address.ToString(), peer.Port); + + udpSocket.Send(bytes, bytes.Length); + + 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; + + if ((peer.Address != null) && (textBox2.Text.Length > 0)) + { + button1.Enabled = true; + } + else + { + button1.Enabled = false; + } + } + + // + // called when peer target changes + // + /// + /// + /// + /// + private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e) + { + PeerData peer = (PeerData) comboBox1.SelectedItem; + + try + { + resolver = DNSService.Resolve(0, 0, peer.Name, peer.Type, peer.Domain, new DNSService.ResolveReply(OnResolveReply)); + } + catch + { + MessageBox.Show("Unable to Resolve service", "Error"); + Application.Exit(); + } + } + } +}