00001
00002
00003
00004
00005
00006 namespace NewGamePhysics.Networking
00007 {
00008 using System;
00009 using System.Net;
00010 using System.Collections.Generic;
00011 using System.Linq;
00012 using System.Text;
00013 using System.IO;
00014
00018 public class PlayTrulyRandom
00019 {
00023 private const string baseUrl =
00024 "http://www.playtrulyrandom.com/";
00025
00029 private string submitUrl;
00030
00034 private string retrieveUrl;
00035
00039 private string usageUrl;
00040
00046 private string agentName;
00047
00052 private string userName;
00053
00057 private int retrievePoolSize;
00058
00062 private string retrievePoolCache;
00063
00067 private int retrievePoolPos;
00068
00072 private string lastMessage = string.Empty;
00073
00077 private bool error = false;
00078
00085 public PlayTrulyRandom(string agentName)
00086 : this(agentName, Guid.NewGuid().ToString(), 256)
00087 {
00088 }
00089
00099 public PlayTrulyRandom(string agentName, int retrievePoolSize)
00100 : this(agentName, Guid.NewGuid().ToString(), retrievePoolSize)
00101 {
00102 }
00103
00110 public PlayTrulyRandom(string agentName, string userName)
00111 : this(agentName, userName, 256)
00112 {
00113 }
00114
00124 public PlayTrulyRandom(string agentName, string userName, int retrievePoolSize)
00125 {
00126
00127 if (string.IsNullOrEmpty(agentName))
00128 {
00129 throw new ArgumentNullException(
00130 "agentName",
00131 "Parameter cannot be null or empty.");
00132 }
00133
00134 if (null == userName)
00135 {
00136 throw new ArgumentNullException("userName");
00137 }
00138
00139 if ((retrievePoolSize < 2) || (retrievePoolSize > 1024))
00140 {
00141 throw new ArgumentOutOfRangeException(
00142 "retrievePoolSize",
00143 "Must be in the range [8,1024]");
00144 }
00145
00146 this.agentName = Uri.EscapeDataString(agentName);
00147 this.userName = Uri.EscapeDataString(userName);
00148 this.retrievePoolSize = retrievePoolSize;
00149
00150 string commonPart = "?source=" + agentName + "&user=" + userName + "&";
00151
00152
00153
00154 this.submitUrl = baseUrl + "submit.php" + commonPart + "bits=";
00155
00156
00157
00158 this.retrieveUrl = baseUrl + "retrieve.php" + commonPart + "n=";
00159
00160
00161
00162 this.usageUrl = baseUrl + "usage.php" + commonPart + "duration=";
00163
00164
00165 this.retrievePoolCache = string.Empty;
00166 this.retrievePoolPos = -1;
00167 }
00168
00172 public string LastMessage
00173 {
00174 get { return this.lastMessage; }
00175 }
00176
00180 public bool Error
00181 {
00182 get { return this.error; }
00183 }
00184
00193 public void OnlineSubmit(object param)
00194 {
00195
00196 string bitsToSumit = (string)param;
00197
00198
00199 this.lastMessage = string.Empty;
00200 this.error = false;
00201
00202
00203 if (!String.IsNullOrEmpty(bitsToSumit))
00204 {
00205
00206 Uri url = new Uri(this.submitUrl + Uri.EscapeDataString(bitsToSumit));
00207
00208
00209 string result = UrlGet(url);
00210 }
00211 }
00212
00220 public void OnlineUsage(object param)
00221 {
00222
00223 int usageSeconds = (int)param;
00224
00225
00226 this.lastMessage = string.Empty;
00227 this.error = false;
00228
00229
00230 if (usageSeconds > 0)
00231 {
00232
00233 Uri url = new Uri(this.usageUrl + usageSeconds.ToString());
00234
00235
00236 string result = UrlGet(url);
00237 }
00238 }
00239
00244 public void RegisterAgent()
00245 {
00246
00247 this.lastMessage = string.Empty;
00248 this.error = false;
00249
00250
00251 Uri url = new Uri(this.usageUrl + "1&hrngmode=1");
00252
00253
00254 string result = UrlGet(url);
00255 }
00256
00265 public string OnlineRetrieve(int numberOfBits)
00266 {
00267
00268 if ((numberOfBits < 1) || (numberOfBits > 1024))
00269 {
00270 throw new ArgumentOutOfRangeException(
00271 "numberBits",
00272 "Requested number must be between 1 and 1024");
00273 }
00274
00275
00276 this.lastMessage = string.Empty;
00277 this.error = false;
00278
00279
00280 Uri url = new Uri(this.retrieveUrl + Uri.EscapeDataString(numberOfBits.ToString()));
00281
00282
00283 string result = UrlGet(url);
00284
00285
00286 return result;
00287 }
00288
00298 public string PoolRetrieve(int numberOfBits)
00299 {
00300
00301 string retrievedBits = string.Empty;
00302
00303
00304 int bitsToCopy = numberOfBits;
00305 while (bitsToCopy > 0)
00306 {
00307
00308 if ((this.retrievePoolPos < 0) || (this.retrievePoolPos == this.retrievePoolSize))
00309 {
00310
00311 this.retrievePoolCache = this.OnlineRetrieve(this.retrievePoolSize);
00312 this.retrievePoolPos = 0;
00313
00314 if (this.Error)
00315 {
00316 throw new Exception(
00317 "Could not retrieve random data. " +
00318 this.LastMessage);
00319 }
00320
00321 if (this.retrievePoolCache.Length != this.retrievePoolSize)
00322 {
00323 throw new Exception(
00324 "Could not retrieve the required number of bits. " +
00325 "Expecting: " + this.retrievePoolSize + " bits, " +
00326 "Got: " + this.retrievePoolCache.Length + " bits.");
00327 }
00328 }
00329
00330
00331 int bitsLeftInPool = this.retrievePoolSize - this.retrievePoolPos;
00332 if (bitsLeftInPool >= bitsToCopy)
00333 {
00334
00335 retrievedBits += this.retrievePoolCache.Substring(this.retrievePoolPos, bitsToCopy);
00336 this.retrievePoolPos += bitsToCopy;
00337 bitsToCopy = 0;
00338 }
00339 else
00340 {
00341
00342 retrievedBits += this.retrievePoolCache.Substring(this.retrievePoolPos, bitsLeftInPool);
00343 bitsToCopy -= bitsLeftInPool;
00344
00345
00346 this.retrievePoolPos = -1;
00347 }
00348 }
00349
00350 return retrievedBits;
00351 }
00352
00369 public int Next(int minValue, int maxValue, out int retrievedBits)
00370 {
00371 if (maxValue < minValue)
00372 {
00373 throw new ArgumentException(
00374 "maxValue must be greater or equals than minValue",
00375 "maxValue");
00376 }
00377
00378 int result;
00379 retrievedBits = 0;
00380
00381
00382 result = minValue;
00383
00384
00385 long delta = (long)maxValue - (long)minValue;
00386 if (delta < 1)
00387 {
00388 return result;
00389 }
00390
00391
00392 int numberOfBits = 1;
00393 long currentValue = 2;
00394 long deltaPlus = delta + 1;
00395 while (deltaPlus > currentValue)
00396 {
00397 numberOfBits++;
00398 currentValue *= 2;
00399 }
00400
00401
00402
00403
00404
00405 long randomNumber = 0;
00406 do
00407 {
00408
00409 string randomBits = this.PoolRetrieve(numberOfBits);
00410 retrievedBits += numberOfBits;
00411 if (randomBits.Length != numberOfBits)
00412 {
00413 this.lastMessage = String.Format(
00414 "Could not retrieve the required number of bits. " +
00415 "Expecting: {0} bits, " +
00416 "Got: {1} bits.",
00417 numberOfBits,
00418 randomBits.Length);
00419 this.error = true;
00420 throw new ApplicationException(this.lastMessage);
00421 }
00422
00423
00424 randomNumber = Convert.ToInt64(randomBits, 2);
00425 } while (randomNumber > delta);
00426
00427
00428 result = (int)((long)minValue + randomNumber);
00429
00430 return result;
00431 }
00432
00440 private string UrlGet(Uri url)
00441 {
00442 string retrievedText = string.Empty;
00443 HttpWebRequest request;
00444 HttpWebResponse response = null;
00445 try
00446 {
00447
00448 request = WebRequest.Create(url) as HttpWebRequest;
00449
00450
00451 request.UserAgent = this.agentName;
00452 request.KeepAlive = false;
00453
00454
00455 request.Timeout = 15 * 1000;
00456
00457
00458 response = request.GetResponse() as HttpWebResponse;
00459 if (request.HaveResponse == true && response != null)
00460 {
00461
00462 StreamReader reader = new StreamReader(response.GetResponseStream());
00463
00464
00465 retrievedText = reader.ReadToEnd();
00466 }
00467 }
00468 catch (WebException wex)
00469 {
00470
00471
00472 if (wex.Response != null)
00473 {
00474 using (HttpWebResponse errorResponse = (HttpWebResponse)wex.Response)
00475 {
00476 this.lastMessage = String.Format("Network error '{0}' {1} ({2:d}).",
00477 errorResponse.StatusDescription,
00478 errorResponse.StatusCode,
00479 errorResponse.StatusCode);
00480 }
00481
00482 this.error = true;
00483 }
00484 }
00485 catch (Exception e)
00486 {
00487 this.lastMessage = e.Message;
00488
00489 this.error = true;
00490 }
00491 finally
00492 {
00493 if (response != null)
00494 {
00495 response.Close();
00496 }
00497 }
00498
00499 return retrievedText;
00500 }
00501 }
00502 }