]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - Clients/SimpleChat.NET/SimpleChat.cs
mDNSResponder-87.tar.gz
[apple/mdnsresponder.git] / Clients / SimpleChat.NET / SimpleChat.cs
diff --git a/Clients/SimpleChat.NET/SimpleChat.cs b/Clients/SimpleChat.NET/SimpleChat.cs
new file mode 100755 (executable)
index 0000000..fb841f2
--- /dev/null
@@ -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>
+       /// Summary description for Form1.
+       /// </summary>
+       /// 
+
+       //
+       // 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;
+               /// <summary>
+               /// Required designer variable.
+               /// </summary>
+               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;
+               }
+
+               /// <summary>
+               /// Clean up any resources being used.
+               /// </summary>
+               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
+               /// <summary>
+               /// Required method for Designer support - do not modify
+               /// the contents of this method with the code editor.
+               /// </summary>
+               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();
+                       }
+               }
+
+               /// <summary>
+               /// The main entry point for the application.
+               /// </summary>
+               [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
+               //
+               /// <summary>
+               /// </summary>
+               /// <param name="sender"></param>
+               /// <param name="e"></param>
+               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();
+                       }
+               }
+       }
+}