protected async UniTask HandshakeAsync(int bits) { // in the very first message we must mine a hashcash token // and send that as a hello // the server won't accept connections otherwise #if NETSTANDARD string applicationName = Application.productName; HashCash token = await UniTask.RunOnThreadPool(() => HashCash.Mine(applicationName, bits)); #else // TODO - HashCash token implement a better way for both unity and .net to work. string applicationName = "Application.productName"; HashCash token = await UniTask.Run(() => HashCash.Mine(applicationName, bits)); #endif byte[] hello = new byte[1000]; int length = HashCashEncoding.Encode(hello, 0, token); var data = new ArraySegment <byte>(hello, 0, length); // send a greeting and see if the server replies await SendAsync(data); var stream = new MemoryStream(); try { await ReceiveAsync(stream); } catch (Exception e) { throw new InvalidDataException("Unable to establish connection, no Handshake message received.", e); } }
private bool Validate(byte[] data, int msgLength) { // do we have enough data in the buffer for a HashCash token? if (msgLength < Kcp.OVERHEAD + KcpConnection.RESERVED + HashCashEncoding.SIZE) { return(false); } // read the token HashCash token = HashCashEncoding.Decode(data, Kcp.OVERHEAD + KcpConnection.RESERVED); RemoveExpiredTokens(); // have this token been used? if (used.Contains(token)) { return(false); } // does the token validate? #if NETSTANDARD if (!token.Validate(Application.productName, HashCashBits)) #else // TODO - HashCash token implement a better way for both unity and .net to work. if (!token.Validate("Application.productName", HashCashBits)) #endif { return(false); } used.Add(token); expireQueue.Enqueue(token); // brand new token, and it is for this app, go on return(true); }
/// <summary> /// Encode a hashcash token into a buffer /// </summary> /// <param name="buffer">the buffer where to store the hashcash</param> /// <param name="index">the index in the buffer where to put it</param> /// <param name="hashCash">the token to be encoded</param> /// <returns>the length of the written data</returns> public static int Encode(byte[] buffer, int index, HashCash hashCash) { var encoder = new Encoder(buffer, index); encoder.Encode64U((ulong)hashCash.dt.Ticks); encoder.Encode32U((uint)hashCash.resource); encoder.Encode64U(hashCash.salt); encoder.Encode64U(hashCash.counter); return(encoder.Position - index); }
// remove all the tokens that expired private void RemoveExpiredTokens() { DateTime threshold = DateTime.UtcNow.AddMinutes(-10); while (expireQueue.Count > 0) { HashCash token = expireQueue.Peek(); if (token.dt > threshold) { return; } expireQueue.Dequeue(); used.Remove(token); } }
/// <summary> /// Encode a hashcash token into a buffer /// </summary> /// <param name="buffer">the buffer where to store the hashcash</param> /// <param name="index">the index in the buffer where to put it</param> /// <param name="hashCash">the token to be encoded</param> /// <returns>the length of the written data</returns> public static HashCash Decode(byte[] buffer, int index) { var decoder = new Decoder(buffer, index); long ticks = (long)decoder.Decode64U(); int resource = (int)decoder.Decode32U(); ulong salt = decoder.Decode64U(); ulong counter = decoder.Decode64U(); var token = new HashCash( new DateTime(ticks), resource, salt, counter ); return(token); }