/ThirdParty/Lidgren.Network/NetUtility.cs
C# | 378 lines | 268 code | 40 blank | 70 comment | 64 complexity | ecbeab32fe0ce9f51d3a8f273045e4c1 MD5 | raw file
1/* Copyright (c) 2010 Michael Lidgren
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4and associated documentation files (the "Software"), to deal in the Software without
5restriction, including without limitation the rights to use, copy, modify, merge, publish,
6distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
7the Software is furnished to do so, subject to the following conditions:
8
9The above copyright notice and this permission notice shall be included in all copies or
10substantial portions of the Software.
11
12THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
15LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
16TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
17USE OR OTHER DEALINGS IN THE SOFTWARE.
18*/
19#if !ANDROID && !IOS
20#define IS_FULL_NET_AVAILABLE
21#endif
22
23using System;
24using System.Net;
25using System.Net.NetworkInformation;
26using System.Net.Sockets;
27using System.Text;
28using System.Text.RegularExpressions;
29
30namespace Lidgren.Network
31{
32 /// <summary>
33 /// Utility methods
34 /// </summary>
35 public static class NetUtility
36 {
37 /// <summary>
38 /// Get IPv4 endpoint from notation (xxx.xxx.xxx.xxx) or hostname and port number
39 /// </summary>
40 public static IPEndPoint Resolve(string ipOrHost, int port)
41 {
42 IPAddress adr = Resolve(ipOrHost);
43 return new IPEndPoint(adr, port);
44 }
45
46 /// <summary>
47 /// Get IPv4 address from notation (xxx.xxx.xxx.xxx) or hostname
48 /// </summary>
49 public static IPAddress Resolve(string ipOrHost)
50 {
51 if (string.IsNullOrEmpty(ipOrHost))
52 throw new ArgumentException("Supplied string must not be empty", "ipOrHost");
53
54 ipOrHost = ipOrHost.Trim();
55
56 IPAddress ipAddress = null;
57 if (IPAddress.TryParse(ipOrHost, out ipAddress))
58 {
59 if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
60 return ipAddress;
61 throw new ArgumentException("This method will not currently resolve other than ipv4 addresses");
62 }
63
64 // ok must be a host name
65 IPHostEntry entry;
66 try
67 {
68 entry = Dns.GetHostEntry(ipOrHost);
69 if (entry == null)
70 return null;
71
72 // check each entry for a valid IP address
73 foreach (IPAddress ipCurrent in entry.AddressList)
74 {
75 if (ipCurrent.AddressFamily == AddressFamily.InterNetwork)
76 return ipCurrent;
77 }
78
79 return null;
80 }
81 catch (SocketException ex)
82 {
83 if (ex.SocketErrorCode == SocketError.HostNotFound)
84 {
85 //LogWrite(string.Format(CultureInfo.InvariantCulture, "Failed to resolve host '{0}'.", ipOrHost));
86 return null;
87 }
88 else
89 {
90 throw;
91 }
92 }
93 }
94
95#if IS_FULL_NET_AVAILABLE
96
97 private static NetworkInterface GetNetworkInterface()
98 {
99 //IPGlobalProperties computerProperties = IPGlobalProperties.GetIPGlobalProperties();
100 //if (computerProperties == null)
101 // return null;
102
103 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
104 if (nics == null || nics.Length < 1)
105 return null;
106
107 NetworkInterface best = null;
108 foreach (NetworkInterface adapter in nics)
109 {
110 if (adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback || adapter.NetworkInterfaceType == NetworkInterfaceType.Unknown)
111 continue;
112 if (!adapter.Supports(NetworkInterfaceComponent.IPv4))
113 continue;
114 if (best == null)
115 best = adapter;
116 if (adapter.OperationalStatus != OperationalStatus.Up)
117 continue;
118
119 // A computer could have several adapters (more than one network card)
120 // here but just return the first one for now...
121 return adapter;
122 }
123 return best;
124 }
125
126 /// <summary>
127 /// Returns the physical (MAC) address for the first usable network interface
128 /// </summary>
129 public static PhysicalAddress GetMacAddress()
130 {
131 NetworkInterface ni = GetNetworkInterface();
132 if (ni == null)
133 return null;
134 return ni.GetPhysicalAddress();
135 }
136#endif
137
138 /// <summary>
139 /// Create a hex string from an Int64 value
140 /// </summary>
141 public static string ToHexString(long data)
142 {
143 return ToHexString(BitConverter.GetBytes(data));
144 }
145
146 /// <summary>
147 /// Create a hex string from an array of bytes
148 /// </summary>
149 public static string ToHexString(byte[] data)
150 {
151 char[] c = new char[data.Length * 2];
152 byte b;
153 for (int i = 0; i < data.Length; ++i)
154 {
155 b = ((byte)(data[i] >> 4));
156 c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
157 b = ((byte)(data[i] & 0xF));
158 c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
159 }
160 return new string(c);
161 }
162
163 /// <summary>
164 /// Gets my local IP address (not necessarily external) and subnet mask
165 /// </summary>
166 public static IPAddress GetMyAddress(out IPAddress mask)
167 {
168#if IS_FULL_NET_AVAILABLE
169 NetworkInterface ni = GetNetworkInterface();
170 if (ni == null)
171 {
172 mask = null;
173 return null;
174 }
175
176 IPInterfaceProperties properties = ni.GetIPProperties();
177 foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses)
178 {
179 if (unicastAddress != null && unicastAddress.Address != null && unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork)
180 {
181 mask = unicastAddress.IPv4Mask;
182 return unicastAddress.Address;
183 }
184 }
185#endif
186 mask = null;
187 return null;
188 }
189
190 /// <summary>
191 /// Returns true if the IPEndPoint supplied is on the same subnet as this host
192 /// </summary>
193 public static bool IsLocal(IPEndPoint endpoint)
194 {
195 if (endpoint == null)
196 return false;
197 return IsLocal(endpoint.Address);
198 }
199
200 /// <summary>
201 /// Returns true if the IPAddress supplied is on the same subnet as this host
202 /// </summary>
203 public static bool IsLocal(IPAddress remote)
204 {
205 IPAddress mask;
206 IPAddress local = GetMyAddress(out mask);
207
208 if (mask == null)
209 return false;
210
211 uint maskBits = BitConverter.ToUInt32(mask.GetAddressBytes(), 0);
212 uint remoteBits = BitConverter.ToUInt32(remote.GetAddressBytes(), 0);
213 uint localBits = BitConverter.ToUInt32(local.GetAddressBytes(), 0);
214
215 // compare network portions
216 return ((remoteBits & maskBits) == (localBits & maskBits));
217 }
218
219 /// <summary>
220 /// Returns how many bits are necessary to hold a certain number
221 /// </summary>
222 [CLSCompliant(false)]
223 public static int BitsToHoldUInt(uint value)
224 {
225 int bits = 1;
226 while ((value >>= 1) != 0)
227 bits++;
228 return bits;
229 }
230
231 /// <summary>
232 /// Returns how many bytes are required to hold a certain number of bits
233 /// </summary>
234 public static int BytesToHoldBits(int numBits)
235 {
236 return (numBits + 7) / 8;
237 }
238
239 internal static UInt32 SwapByteOrder(UInt32 value)
240 {
241 return
242 ((value & 0xff000000) >> 24) |
243 ((value & 0x00ff0000) >> 8) |
244 ((value & 0x0000ff00) << 8) |
245 ((value & 0x000000ff) << 24);
246 }
247
248 internal static UInt64 SwapByteOrder(UInt64 value)
249 {
250 return
251 ((value & 0xff00000000000000L) >> 56) |
252 ((value & 0x00ff000000000000L) >> 40) |
253 ((value & 0x0000ff0000000000L) >> 24) |
254 ((value & 0x000000ff00000000L) >> 8) |
255 ((value & 0x00000000ff000000L) << 8) |
256 ((value & 0x0000000000ff0000L) << 24) |
257 ((value & 0x000000000000ff00L) << 40) |
258 ((value & 0x00000000000000ffL) << 56);
259 }
260
261 internal static bool CompareElements(byte[] one, byte[] two)
262 {
263 if (one.Length != two.Length)
264 return false;
265 for (int i = 0; i < one.Length; i++)
266 if (one[i] != two[i])
267 return false;
268 return true;
269 }
270
271 /// <summary>
272 /// Convert a hexadecimal string to a byte array
273 /// </summary>
274 public static byte[] ToByteArray(String hexString)
275 {
276 byte[] retval = new byte[hexString.Length / 2];
277 for (int i = 0; i < hexString.Length; i += 2)
278 retval[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
279 return retval;
280 }
281
282 /// <summary>
283 /// Converts a number of bytes to a shorter, more readable string representation
284 /// </summary>
285 public static string ToHumanReadable(long bytes)
286 {
287 if (bytes < 4000) // 1-4 kb is printed in bytes
288 return bytes + " bytes";
289 if (bytes < 1000 * 1000) // 4-999 kb is printed in kb
290 return Math.Round(((double)bytes / 1000.0), 2) + " kilobytes";
291 return Math.Round(((double)bytes / (1000.0 * 1000.0)), 2) + " megabytes"; // else megabytes
292 }
293
294 internal static int RelativeSequenceNumber(int nr, int expected)
295 {
296 int retval = ((nr + NetConstants.NumSequenceNumbers) - expected) % NetConstants.NumSequenceNumbers;
297 if (retval > (NetConstants.NumSequenceNumbers / 2))
298 retval -= NetConstants.NumSequenceNumbers;
299 return retval;
300 }
301
302 /// <summary>
303 /// Gets the window size used internally in the library for a certain delivery method
304 /// </summary>
305 public static int GetWindowSize(NetDeliveryMethod method)
306 {
307 switch (method)
308 {
309 case NetDeliveryMethod.Unknown:
310 return 0;
311
312 case NetDeliveryMethod.Unreliable:
313 case NetDeliveryMethod.UnreliableSequenced:
314 return NetConstants.UnreliableWindowSize;
315
316 case NetDeliveryMethod.ReliableOrdered:
317 return NetConstants.ReliableOrderedWindowSize;
318
319 case NetDeliveryMethod.ReliableSequenced:
320 case NetDeliveryMethod.ReliableUnordered:
321 default:
322 return NetConstants.DefaultWindowSize;
323 }
324 }
325
326 // shell sort
327 internal static void SortMembersList(System.Reflection.MemberInfo[] list)
328 {
329 int h;
330 int j;
331 System.Reflection.MemberInfo tmp;
332
333 h = 1;
334 while (h * 3 + 1 <= list.Length)
335 h = 3 * h + 1;
336
337 while (h > 0)
338 {
339 for (int i = h - 1; i < list.Length; i++)
340 {
341 tmp = list[i];
342 j = i;
343 while (true)
344 {
345 if (j >= h)
346 {
347 if (string.Compare(list[j - h].Name, tmp.Name, StringComparison.InvariantCulture) > 0)
348 {
349 list[j] = list[j - h];
350 j -= h;
351 }
352 else
353 break;
354 }
355 else
356 break;
357 }
358
359 list[j] = tmp;
360 }
361 h /= 3;
362 }
363 }
364
365 internal static NetDeliveryMethod GetDeliveryMethod(NetMessageType mtp)
366 {
367 if (mtp >= NetMessageType.UserReliableOrdered1)
368 return NetDeliveryMethod.ReliableOrdered;
369 else if (mtp >= NetMessageType.UserReliableSequenced1)
370 return NetDeliveryMethod.ReliableSequenced;
371 else if (mtp >= NetMessageType.UserReliableUnordered)
372 return NetDeliveryMethod.ReliableUnordered;
373 else if (mtp >= NetMessageType.UserSequenced1)
374 return NetDeliveryMethod.UnreliableSequenced;
375 return NetDeliveryMethod.Unreliable;
376 }
377 }
378}