]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/SimpleChat.NET/SimpleChat.cs
fb841f2c3192d45f66f0cd5dd7f6eed551f15c11
[apple/mdnsresponder.git] / Clients / SimpleChat.NET / SimpleChat.cs
1 /*
2 * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: SimpleChat.cs,v $
26 Revision 1.5 2004/09/13 19:37:42 shersche
27 Change code to reflect namespace and type changes to dnssd.NET library
28
29 Revision 1.4 2004/09/11 05:42:56 shersche
30 don't reset SelectedIndex in OnRemove
31
32 Revision 1.3 2004/09/11 00:38:58 shersche
33 DNSService APIs now expect port in host format
34
35 Revision 1.2 2004/07/19 22:08:53 shersche
36 Fixed rdata->int conversion problem in QueryRecordReply
37
38 Revision 1.1 2004/07/19 07:57:08 shersche
39 Initial revision
40
41
42
43 */
44
45 using System;
46 using System.Drawing;
47 using System.Collections;
48 using System.ComponentModel;
49 using System.Windows.Forms;
50 using System.Net;
51 using System.Net.Sockets;
52 using System.Data;
53 using System.Text;
54 using Apple.DNSSD;
55
56 namespace SimpleChat.NET
57 {
58 /// <summary>
59 /// Summary description for Form1.
60 /// </summary>
61 ///
62
63 //
64 // PeerData
65 //
66 // Holds onto the information associated with a peer on the network
67 //
68 public class PeerData
69 {
70 public int InterfaceIndex;
71 public String Name;
72 public String Type;
73 public String Domain;
74 public IPAddress Address;
75 public int Port;
76
77 public override String
78 ToString()
79 {
80 return Name;
81 }
82
83 public override bool
84 Equals(object other)
85 {
86 bool result = false;
87
88 if (other != null)
89 {
90 if ((object) this == other)
91 {
92 result = true;
93 }
94 else if (other is PeerData)
95 {
96 PeerData otherPeerData = (PeerData) other;
97
98 result = (this.Name == otherPeerData.Name);
99 }
100 }
101
102 return result;
103 }
104
105 public override int
106 GetHashCode()
107 {
108 return Name.GetHashCode();
109 }
110 };
111
112 //
113 // ResolveData
114 //
115 // Holds onto the information associated with the resolution
116 // of a DNSService
117 //
118 public class ResolveData
119 {
120 public int InterfaceIndex;
121 public String FullName;
122 public String HostName;
123 public int Port;
124 public Byte[] TxtRecord;
125
126 public override String
127 ToString()
128 {
129 return FullName;
130 }
131 };
132
133
134 //
135 // SocketStateObject
136 //
137 // Holds onto the data associated with an asynchronous
138 // socket operation
139 //
140 class SocketStateObject
141 {
142 public const int BUFFER_SIZE = 1024;
143 private Socket m_socket;
144 public byte[] m_buffer;
145 public bool m_complete;
146 public StringBuilder m_sb = new StringBuilder();
147
148 public SocketStateObject(Socket socket)
149 {
150 m_buffer = new byte[BUFFER_SIZE];
151 m_complete = false;
152 m_socket = socket;
153 }
154
155 public Socket
156 WorkSocket
157 {
158 get
159 {
160 return m_socket;
161 }
162 }
163 }
164 public class Form1 : System.Windows.Forms.Form
165 {
166 private System.Windows.Forms.ComboBox comboBox1;
167 private System.Windows.Forms.TextBox textBox2;
168 private System.Windows.Forms.Button button1;
169 private System.Windows.Forms.Label label1;
170 private ServiceRef registrar = null;
171 private ServiceRef browser = null;
172 private ServiceRef resolver = null;
173 private String myName;
174 /// <summary>
175 /// Required designer variable.
176 /// </summary>
177 private System.ComponentModel.Container components = null;
178
179 //
180 // These all of our callbacks. These are invoked in the context
181 // of the main (GUI) thread. The DNSService callbacks Invoke()
182 // them
183 delegate void RegisterServiceCallback(String name);
184 delegate void AddPeerCallback(PeerData data);
185 delegate void RemovePeerCallback(PeerData data);
186 delegate void ResolveServiceCallback(ResolveData data);
187 delegate void ResolveAddressCallback(System.Net.IPAddress address);
188 delegate void ReadMessageCallback(String data);
189
190 RegisterServiceCallback registerServiceCallback;
191 AddPeerCallback addPeerCallback;
192 RemovePeerCallback removePeerCallback;
193 ResolveServiceCallback resolveServiceCallback;
194 ResolveAddressCallback resolveAddressCallback;
195 ReadMessageCallback readMessageCallback;
196 private System.Windows.Forms.RichTextBox richTextBox1;
197
198 //
199 // The socket that we will be reading data from
200 //
201 Socket socket = null;
202
203 //
204 // OnRegisterService
205 //
206 // The name that we are passed might be different than the
207 // name we called Register with. So we hold onto this name
208 // rather than the name we Register with.
209 //
210 // This is called (indirectly) from OnRegisterReply().
211 //
212 private void
213 OnRegisterService
214 (
215 String name
216 )
217 {
218 myName = name;
219 }
220
221 //
222 // OnAddPeer
223 //
224 // Called when DNSServices detects a new P2P Chat peer has
225 // joined.
226 //
227 // This is called (indirectly) from OnBrowseReply()
228 //
229 private void
230 OnAddPeer
231 (
232 PeerData peer
233 )
234 {
235 comboBox1.Items.Add(peer);
236
237 if (comboBox1.Items.Count == 1)
238 {
239 comboBox1.SelectedIndex = 0;
240 }
241 }
242
243 //
244 // OnRemovePeer
245 //
246 // Called when DNSServices detects a P2P peer has left
247 // the network
248 //
249 // This is called (indirectly) from OnBrowseReply()
250 //
251 private void
252 OnRemovePeer
253 (
254 PeerData peer
255 )
256 {
257 comboBox1.Items.Remove(peer);
258 }
259
260 //
261 // OnResolveService
262 //
263 // Called when DNSServices has resolved a service.
264 //
265 // This is called (indirectly) from OnResolveService()
266 //
267 private void
268 OnResolveService
269 (
270 ResolveData data
271 )
272 {
273 resolver.Dispose();
274
275 PeerData peer = (PeerData) comboBox1.SelectedItem;
276
277 peer.Port = data.Port;
278
279 try
280 {
281 resolver = DNSService.QueryRecord(0, 0, data.HostName, /* ns_t_a */ 1, /* ns_t_c */ 1, new DNSService.QueryRecordReply(OnQueryRecordReply));
282 }
283 catch
284 {
285 MessageBox.Show("QueryRecord Failed", "Error");
286 Application.Exit();
287 }
288 }
289
290 //
291 // OnResolveAddress
292 //
293 // Called when DNSServices has finished a query operation
294 //
295 // This is called (indirectly) from OnQueryRecordReply()
296 //
297 private void
298 OnResolveAddress
299 (
300 System.Net.IPAddress address
301 )
302 {
303 resolver.Dispose();
304
305 PeerData peer = (PeerData) comboBox1.SelectedItem;
306
307 peer.Address = address;
308 }
309
310 //
311 // OnReadMessage
312 //
313 // Called when there is data to be read on a socket
314 //
315 // This is called (indirectly) from OnReadSocket()
316 //
317 private void
318 OnReadMessage
319 (
320 String msg
321 )
322 {
323 int rgb = 0;
324
325 for (int i = 0; i < msg.Length && msg[i] != ':'; i++)
326 {
327 rgb = rgb ^ ((int) msg[i] << (i % 3 + 2) * 8);
328 }
329
330 Color color = Color.FromArgb(rgb & 0x007F7FFF);
331
332 richTextBox1.SelectionColor = color;
333
334 richTextBox1.AppendText(msg + "\n");
335 }
336
337 //
338 // OnRegisterReply
339 //
340 // Called by DNSServices core as a result of DNSService.Register()
341 // call
342 //
343 // This is called from a worker thread by DNSService core.
344 //
345 private void
346 OnRegisterReply
347 (
348 ServiceRef sdRef,
349 ServiceFlags flags,
350 ErrorCode errorCode,
351 String name,
352 String regtype,
353 String domain)
354 {
355 if (errorCode == ErrorCode.NoError)
356 {
357 Invoke(registerServiceCallback, new Object[]{name});
358 }
359 else
360 {
361 MessageBox.Show("OnRegisterReply returned an error code " + errorCode, "Error");
362 }
363 }
364
365
366 //
367 // OnBrowseReply
368 //
369 // Called by DNSServices core as a result of DNSService.Browse()
370 // call
371 //
372 // This is called from a worker thread by DNSService core.
373 //
374 private void
375 OnBrowseReply
376 (
377 ServiceRef sdRef,
378 ServiceFlags flags,
379 int interfaceIndex,
380 ErrorCode errorCode,
381 String name,
382 String type,
383 String domain)
384 {
385 if (errorCode == ErrorCode.NoError)
386 {
387 PeerData peer = new PeerData();
388
389 peer.InterfaceIndex = interfaceIndex;
390 peer.Name = name;
391 peer.Type = type;
392 peer.Domain = domain;
393 peer.Address = null;
394
395 if ((flags & ServiceFlags.Add) != 0)
396 {
397 Invoke(addPeerCallback, new Object[]{peer});
398 }
399 else if ((flags == 0) || ((flags & ServiceFlags.MoreComing) != 0))
400 {
401 Invoke(removePeerCallback, new Object[]{peer});
402 }
403 }
404 else
405 {
406 MessageBox.Show("OnBrowseReply returned an error code " + errorCode, "Error");
407 }
408 }
409
410 //
411 // OnResolveReply
412 //
413 // Called by DNSServices core as a result of DNSService.Resolve()
414 // call
415 //
416 // This is called from a worker thread by DNSService core.
417 //
418 private void
419 OnResolveReply
420 (
421 ServiceRef sdRef,
422 ServiceFlags flags,
423 int interfaceIndex,
424 ErrorCode errorCode,
425 String fullName,
426 String hostName,
427 int port,
428 Byte[] txtRecord
429 )
430 {
431 if (errorCode == ErrorCode.NoError)
432 {
433 ResolveData data = new ResolveData();
434
435 data.InterfaceIndex = interfaceIndex;
436 data.FullName = fullName;
437 data.HostName = hostName;
438 data.Port = port;
439 data.TxtRecord = txtRecord;
440
441 Invoke(resolveServiceCallback, new Object[]{data});
442 }
443 else
444 {
445 MessageBox.Show("OnResolveReply returned an error code: " + errorCode, "Error");
446 }
447 }
448
449 //
450 // OnQueryRecordReply
451 //
452 // Called by DNSServices core as a result of DNSService.QueryRecord()
453 // call
454 //
455 // This is called from a worker thread by DNSService core.
456 //
457 private void
458 OnQueryRecordReply
459 (
460 ServiceRef sdRef,
461 ServiceFlags flags,
462 int interfaceIndex,
463 ErrorCode errorCode,
464 String fullName,
465 int rrtype,
466 int rrclass,
467 Byte[] rdata,
468 int ttl
469 )
470 {
471 if (errorCode == ErrorCode.NoError)
472 {
473 uint bits = BitConverter.ToUInt32(rdata, 0);
474 System.Net.IPAddress data = new System.Net.IPAddress(bits);
475
476 Invoke(resolveAddressCallback, new Object[]{data});
477 }
478 else
479 {
480 MessageBox.Show("OnQueryRecordReply returned an error code: " + errorCode, "Error");
481 }
482 }
483
484 //
485 // OnReadSocket
486 //
487 // Called by the .NET core when there is data to be read on a socket
488 //
489 // This is called from a worker thread by the .NET core
490 //
491 private void
492 OnReadSocket
493 (
494 IAsyncResult ar
495 )
496 {
497 SocketStateObject so = (SocketStateObject) ar.AsyncState;
498 Socket s = so.WorkSocket;
499
500 try
501 {
502 if (s == null)
503 {
504 return;
505 }
506
507 int read = s.EndReceive(ar);
508
509 if (read > 0)
510 {
511 String msg = Encoding.UTF8.GetString(so.m_buffer, 0, read);
512
513 Invoke(readMessageCallback, new Object[]{msg});
514 }
515
516 s.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), so);
517 }
518 catch
519 {
520 }
521 }
522
523
524 public Form1()
525 {
526 //
527 // Required for Windows Form Designer support
528 //
529 InitializeComponent();
530
531 registerServiceCallback = new RegisterServiceCallback(OnRegisterService);
532 addPeerCallback = new AddPeerCallback(OnAddPeer);
533 removePeerCallback = new RemovePeerCallback(OnRemovePeer);
534 resolveServiceCallback = new ResolveServiceCallback(OnResolveService);
535 resolveAddressCallback = new ResolveAddressCallback(OnResolveAddress);
536 readMessageCallback = new ReadMessageCallback(OnReadMessage);
537
538 this.Load += new System.EventHandler(this.Form1_Load);
539
540 this.AcceptButton = button1;
541 }
542
543 /// <summary>
544 /// Clean up any resources being used.
545 /// </summary>
546 protected override void
547 Dispose( bool disposing )
548 {
549 if( disposing )
550 {
551 if (components != null)
552 {
553 components.Dispose();
554 }
555
556 if (registrar != null)
557 {
558 registrar.Dispose();
559 }
560
561 if (browser != null)
562 {
563 browser.Dispose();
564 }
565 }
566 base.Dispose( disposing );
567 }
568
569 #region Windows Form Designer generated code
570 /// <summary>
571 /// Required method for Designer support - do not modify
572 /// the contents of this method with the code editor.
573 /// </summary>
574 private void InitializeComponent()
575 {
576 this.comboBox1 = new System.Windows.Forms.ComboBox();
577 this.textBox2 = new System.Windows.Forms.TextBox();
578 this.button1 = new System.Windows.Forms.Button();
579 this.label1 = new System.Windows.Forms.Label();
580 this.richTextBox1 = new System.Windows.Forms.RichTextBox();
581 this.SuspendLayout();
582 //
583 // comboBox1
584 //
585 this.comboBox1.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
586 | System.Windows.Forms.AnchorStyles.Right);
587 this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
588 this.comboBox1.Location = new System.Drawing.Point(59, 208);
589 this.comboBox1.Name = "comboBox1";
590 this.comboBox1.Size = new System.Drawing.Size(224, 21);
591 this.comboBox1.Sorted = true;
592 this.comboBox1.TabIndex = 5;
593 this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
594 //
595 // textBox2
596 //
597 this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
598 | System.Windows.Forms.AnchorStyles.Right);
599 this.textBox2.Location = new System.Drawing.Point(8, 248);
600 this.textBox2.Name = "textBox2";
601 this.textBox2.ScrollBars = System.Windows.Forms.ScrollBars.Horizontal;
602 this.textBox2.Size = new System.Drawing.Size(192, 20);
603 this.textBox2.TabIndex = 2;
604 this.textBox2.Text = "";
605 this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged);
606 //
607 // button1
608 //
609 this.button1.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right);
610 this.button1.Enabled = false;
611 this.button1.Location = new System.Drawing.Point(208, 248);
612 this.button1.Name = "button1";
613 this.button1.TabIndex = 3;
614 this.button1.Text = "Send";
615 this.button1.Click += new System.EventHandler(this.button1_Click);
616 //
617 // label1
618 //
619 this.label1.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left);
620 this.label1.Location = new System.Drawing.Point(8, 210);
621 this.label1.Name = "label1";
622 this.label1.Size = new System.Drawing.Size(48, 16);
623 this.label1.TabIndex = 4;
624 this.label1.Text = "Talk To:";
625 //
626 // richTextBox1
627 //
628 this.richTextBox1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
629 | System.Windows.Forms.AnchorStyles.Left)
630 | System.Windows.Forms.AnchorStyles.Right);
631 this.richTextBox1.Location = new System.Drawing.Point(8, 8);
632 this.richTextBox1.Name = "richTextBox1";
633 this.richTextBox1.ReadOnly = true;
634 this.richTextBox1.Size = new System.Drawing.Size(272, 184);
635 this.richTextBox1.TabIndex = 1;
636 this.richTextBox1.Text = "";
637 //
638 // Form1
639 //
640 this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
641 this.ClientSize = new System.Drawing.Size(292, 273);
642 this.Controls.AddRange(new System.Windows.Forms.Control[] {
643 this.richTextBox1,
644 this.label1,
645 this.button1,
646 this.textBox2,
647 this.comboBox1});
648 this.Name = "Form1";
649 this.Text = "SimpleChat.NET";
650 this.ResumeLayout(false);
651
652 }
653 #endregion
654
655 private void Form1_Load(object sender, EventArgs e)
656 {
657 IPEndPoint localEP = new IPEndPoint(System.Net.IPAddress.Any, 0);
658
659 //
660 // create the socket and bind to INADDR_ANY
661 //
662 socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
663 socket.Bind(localEP);
664 localEP = (IPEndPoint) socket.LocalEndPoint;
665
666 //
667 // start asynchronous read
668 //
669 SocketStateObject so = new SocketStateObject(socket);
670 socket.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), so);
671
672 try
673 {
674 //
675 // start the register and browse operations
676 //
677 registrar = DNSService.Register(0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, localEP.Port, null, new DNSService.RegisterReply(OnRegisterReply));
678 browser = DNSService.Browse(0, 0, "_p2pchat._udp", null, new DNSService.BrowseReply(OnBrowseReply));
679 }
680 catch
681 {
682 MessageBox.Show("DNSServices Not Available", "Error");
683 Application.Exit();
684 }
685 }
686
687 /// <summary>
688 /// The main entry point for the application.
689 /// </summary>
690 [STAThread]
691 static void Main()
692 {
693 Application.Run(new Form1());
694 }
695
696 //
697 // send the message to a peer
698 //
699 private void button1_Click(object sender, System.EventArgs e)
700 {
701 PeerData peer = (PeerData) comboBox1.SelectedItem;
702
703 String message = myName + ": " + textBox2.Text;
704
705 Byte[] bytes = Encoding.UTF8.GetBytes(message);
706
707 UdpClient udpSocket = new UdpClient(peer.Address.ToString(), peer.Port);
708
709 udpSocket.Send(bytes, bytes.Length);
710
711 richTextBox1.SelectionColor = Color.Black;
712
713 richTextBox1.AppendText(textBox2.Text + "\n");
714
715 textBox2.Text = "";
716 }
717
718 //
719 // called when typing in message box
720 //
721 private void textBox2_TextChanged(object sender, System.EventArgs e)
722 {
723 PeerData peer = (PeerData) comboBox1.SelectedItem;
724
725 if ((peer.Address != null) && (textBox2.Text.Length > 0))
726 {
727 button1.Enabled = true;
728 }
729 else
730 {
731 button1.Enabled = false;
732 }
733 }
734
735 //
736 // called when peer target changes
737 //
738 /// <summary>
739 /// </summary>
740 /// <param name="sender"></param>
741 /// <param name="e"></param>
742 private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)
743 {
744 PeerData peer = (PeerData) comboBox1.SelectedItem;
745
746 try
747 {
748 resolver = DNSService.Resolve(0, 0, peer.Name, peer.Type, peer.Domain, new DNSService.ResolveReply(OnResolveReply));
749 }
750 catch
751 {
752 MessageBox.Show("Unable to Resolve service", "Error");
753 Application.Exit();
754 }
755 }
756 }
757 }