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