-
Notifications
You must be signed in to change notification settings - Fork 53
/
Copy pathUdpManager.cs
181 lines (153 loc) · 7.11 KB
/
UdpManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// ---------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ---------------------------------------------------------------------------------
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Windows.Networking;
using Windows.Networking.Sockets;
namespace NetworkHelper
{
public class UdpManager : SessionManager
{
/// <summary>
/// The default timing interval (in milliseconds) to send an advertising message.
/// </summary>
private const int ADVERTISING_INTERVAL = 500;
/// <summary>
/// The default message to send when advertising.
/// </summary>
private const string ADVERTISING_MESSAGE = "Advertiser";
/// <summary>
/// The default port to use when advertising for UDP multicast messages.
/// This port was chosen randomly in the ephemeral port range.
/// </summary>
private const string UDP_COMMUNICATION_PORT = "56788";
/// <summary>
/// The default IP to use when advertising UDP multicast messages.
/// This IP was chosen randomly as part of the multicast IP range.
/// </summary>
private const string UDP_MULTICAST_IP = "237.1.3.37";
/// <summary>
/// The timer that will cause the advertiser to send a UDP multicast message every AdvertisingInterval milliseconds.
/// </summary>
private Timer _timer;
/// <summary>
/// The socket of the Advertiser.
/// </summary>
public DatagramSocket AdvertiserSocket { get; set; }
/// <summary>
/// The port that the Advertiser will be sending UDP messages to and accept message from.
/// </summary>
public string AdvertiserPort { get; set; } = UDP_COMMUNICATION_PORT;
/// <summary>
/// The multicast group that the Advertiser will be sending UDP messages to.
/// </summary>
public HostName AdvertiserGroupHost { get; set; } = new HostName(UDP_MULTICAST_IP);
/// <summary>
/// The message that will be sent when advertising.
/// </summary>
public string AdvertiserMessage { get; set; } = ADVERTISING_MESSAGE;
/// <summary>
/// The timing interval (in milliseconds) to send an advertising message.
/// </summary>
public int AdvertiserInterval { get; set; } = ADVERTISING_INTERVAL;
/// <summary>
/// Creates a new UDP socket and starts advertising the AdvertisingMessage to the AdvertiserPort and AdvertiserGroupHost
/// </summary>
public override async Task<bool> StartAdvertisingAsync()
{
if (AdvertiserSocket == null)
{
AdvertiserSocket = new DatagramSocket();
// Attach event handler and start listening on given port.
AdvertiserSocket.MessageReceived += MessageToConnectReceivedFromParticipantAsync;
await AdvertiserSocket.BindServiceNameAsync(AdvertiserPort);
// Start the timer, to send a message every X milliseconds.
_timer = new Timer(async state => await SendMessageAsync(), null, 0, AdvertiserInterval);
return true;
}
return false;
}
public override bool StopAdvertising()
{
if (AdvertiserSocket != null)
{
AdvertiserSocket.MessageReceived -= MessageToConnectReceivedFromParticipantAsync;
AdvertiserSocket.Dispose();
AdvertiserSocket = null;
_timer.Dispose();
return true;
}
return false;
}
/// <summary>
/// Creates a TcpCommunicationChannel object and returns it so that app developers can send custom TCP messages to the manager.
/// Returns a null remote host name in TcpCommunicationChannel object if the manager didn't exist.
/// </summary>
public override ICommunicationChannel CreateCommunicationChannel(Guid participant, int flags = 0)
{
TcpCommunicationChannel channel = new TcpCommunicationChannel();
channel.RemoteHostname = ((UdpParticipantInformation)Participants[participant]).Host;
return channel;
}
/// <summary>
/// The private method that sends an "advertising" message to the multicast group.
/// </summary>
private async Task SendMessageAsync()
{
// Connect to a multicast group IP and send a message to the group.
Stream outStream = (await AdvertiserSocket.GetOutputStreamAsync(AdvertiserGroupHost, AdvertiserPort)).AsStreamForWrite();
using (var writer = new StreamWriter(outStream))
{
await writer.WriteLineAsync(AdvertiserMessage);
await writer.FlushAsync();
}
}
/// <summary>
/// When a new message is received, the participant is added to the list of Participants.
/// </summary>
private async void MessageToConnectReceivedFromParticipantAsync(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
var participant = new UdpParticipantInformation { Host = args.RemoteAddress };
// Read the subscriber's message.
using (var reader = new StreamReader(args.GetDataStream().AsStreamForRead()))
{
string message = await reader.ReadLineAsync();
// Add the participant.
base.AddParticipant(participant, message);
}
}
}
public class UdpParticipantInformation
{
public HostName Host { get; set; }
public override bool Equals(object obj)
{
var objCast = obj as UdpParticipantInformation;
return objCast != null ? Host.IsEqual(objCast.Host) : false;
}
public override int GetHashCode() => Host.GetHashCode();
}
}