X-Git-Url: https://git.saurik.com/apple/mdnsresponder.git/blobdiff_plain/7f0064bd55e3fa98568d2c359429ff8a38b23a6c..3af7d322c17d21ac78cb1560cbb8617804a78014:/Clients/SimpleChat.NET/SimpleChat.cs diff --git a/Clients/SimpleChat.NET/SimpleChat.cs b/Clients/SimpleChat.NET/SimpleChat.cs index fb841f2..338bdb7 100755 --- a/Clients/SimpleChat.NET/SimpleChat.cs +++ b/Clients/SimpleChat.NET/SimpleChat.cs @@ -1,46 +1,19 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * 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. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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 + * 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. - * - * @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; @@ -51,7 +24,7 @@ using System.Net; using System.Net.Sockets; using System.Data; using System.Text; -using Apple.DNSSD; +using Bonjour; namespace SimpleChat.NET { @@ -60,426 +33,234 @@ namespace SimpleChat.NET /// /// - // - // 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 class SimpleChat : System.Windows.Forms.Form { - 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; + 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; - - // - // 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; + // ServiceRegistered // - // 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() + // Called by DNSServices core as a result of Register() + // call // - private void - OnResolveAddress - ( - System.Net.IPAddress address - ) - { - resolver.Dispose(); + public void + ServiceRegistered + ( + DNSSDService service, + DNSSDFlags flags, + String name, + String regType, + String domain + ) + { + m_name = name; - 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 - ) + // + // 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 + ) { - 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"); + 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 // - // OnRegisterReply - // - // Called by DNSServices core as a result of DNSService.Register() + // Called by DNSServices core as a result of DNSService.Resolve() // 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) + public void + ServiceResolved + ( + DNSSDService sref, + DNSSDFlags flags, + uint ifIndex, + String fullName, + String hostName, + ushort port, + TXTRecord txtRecord + ) { - if (errorCode == ErrorCode.NoError) - { - Invoke(registerServiceCallback, new Object[]{name}); - } - else - { - MessageBox.Show("OnRegisterReply returned an error code " + errorCode, "Error"); - } - } + m_resolver.Stop(); + m_resolver = null; + PeerData peer = (PeerData)comboBox1.SelectedItem; - // - // 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; + peer.Port = port; - 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"); - } + // + // 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(); + } } // - // OnResolveReply + // QueryAnswered // - // Called by DNSServices core as a result of DNSService.Resolve() + // Called by DNSServices core as a result of DNSService.QueryRecord() // call // - // This is called from a worker thread by DNSService core. - // - private void - OnResolveReply + public void + QueryAnswered ( - ServiceRef sdRef, - ServiceFlags flags, - int interfaceIndex, - ErrorCode errorCode, - String fullName, - String hostName, - int port, - Byte[] txtRecord - ) - { - if (errorCode == ErrorCode.NoError) - { - ResolveData data = new ResolveData(); + 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; - data.InterfaceIndex = interfaceIndex; - data.FullName = fullName; - data.HostName = hostName; - data.Port = port; - data.TxtRecord = txtRecord; + PeerData peer = (PeerData) comboBox1.SelectedItem; + uint bits = BitConverter.ToUInt32( (Byte[])rdata, 0); + System.Net.IPAddress address = new System.Net.IPAddress(bits); - Invoke(resolveServiceCallback, new Object[]{data}); - } - else - { - MessageBox.Show("OnResolveReply returned an error code: " + errorCode, "Error"); - } + peer.Address = address; } - // - // 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"); - } - } + 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 @@ -494,26 +275,17 @@ namespace SimpleChat.NET IAsyncResult ar ) { - SocketStateObject so = (SocketStateObject) ar.AsyncState; - Socket s = so.WorkSocket; - try { - if (s == null) - { - return; - } - - int read = s.EndReceive(ar); + int read = m_socket.EndReceive(ar); if (read > 0) { - String msg = Encoding.UTF8.GetString(so.m_buffer, 0, read); - - Invoke(readMessageCallback, new Object[]{msg}); + String msg = Encoding.UTF8.GetString(m_buffer, 0, read); + Invoke(m_readMessageCallback, new Object[]{msg}); } - s.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), so); + m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), this); } catch { @@ -521,19 +293,38 @@ namespace SimpleChat.NET } - public Form1() + public SimpleChat() { // // 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); + 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); @@ -553,15 +344,26 @@ namespace SimpleChat.NET components.Dispose(); } - if (registrar != null) + if (m_registrar != null) { - registrar.Dispose(); + m_registrar.Stop(); } - if (browser != null) + if (m_browser != null) { - browser.Dispose(); + 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 ); } @@ -659,27 +461,25 @@ namespace SimpleChat.NET // // create the socket and bind to INADDR_ANY // - socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - socket.Bind(localEP); - localEP = (IPEndPoint) socket.LocalEndPoint; + m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + m_socket.Bind(localEP); + localEP = (IPEndPoint) m_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); + m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), this); 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)); + m_registrar = m_service.Register( 0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, ( ushort ) localEP.Port, null, m_eventManager ); } catch { - MessageBox.Show("DNSServices Not Available", "Error"); + MessageBox.Show("Bonjour service is not available", "Error"); Application.Exit(); } } @@ -690,7 +490,7 @@ namespace SimpleChat.NET [STAThread] static void Main() { - Application.Run(new Form1()); + Application.Run(new SimpleChat()); } // @@ -700,13 +500,15 @@ namespace SimpleChat.NET { PeerData peer = (PeerData) comboBox1.SelectedItem; - String message = myName + ": " + textBox2.Text; + String message = m_name + ": " + textBox2.Text; Byte[] bytes = Encoding.UTF8.GetBytes(message); - - UdpClient udpSocket = new UdpClient(peer.Address.ToString(), peer.Port); - udpSocket.Send(bytes, bytes.Length); + IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port ); + + + + m_socket.SendTo(bytes, endPoint); richTextBox1.SelectionColor = Color.Black; @@ -721,15 +523,7 @@ namespace SimpleChat.NET 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; - } + button1.Enabled = ((peer.Address != null) && (textBox2.Text.Length > 0)); } // @@ -745,7 +539,7 @@ namespace SimpleChat.NET try { - resolver = DNSService.Resolve(0, 0, peer.Name, peer.Type, peer.Domain, new DNSService.ResolveReply(OnResolveReply)); + m_resolver = m_service.Resolve(0, peer.InterfaceIndex, peer.Name, peer.Type, peer.Domain, m_eventManager); } catch { @@ -754,4 +548,54 @@ namespace SimpleChat.NET } } } + + // + // 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(); + } + }; }