예제 #1
0
        internal void ReceivePartialMessage(PartialMessage message)
        {
            var queue = this.partials.GetOrAdd(message.OriginalMessageId, id => new ConcurrentQueue <PartialMessage>());

            queue.Enqueue(message);

            if (queue.Count != message.Count)
            {
                return;
            }

            if (!this.partials.TryRemove(message.OriginalMessageId, out queue))
            {
                return;
            }

            byte[] payload = new byte[queue.Sum(p => p.Payload.Length)];

            int offset = 0;

            foreach (PartialMessage msg in queue.OrderBy(p => p.Header.MessageId))
            {
                byte[] partialPayload = msg.Payload;
                Buffer.BlockCopy(partialPayload, 0, payload, offset, partialPayload.Length);
                offset += partialPayload.Length;
            }

            MessageSerializer srlzr = this.serializer;

            if (srlzr == null)
            {
                return;
            }

            List <Message> messages = srlzr.BufferMessages(payload);

            if (messages != null && messages.Count == 1)
            {
                Receive(messages[0], fromPartials: true);
            }
            else
            {
                DisconnectAsync();
            }
        }
예제 #2
0
        protected virtual void HandleConnectionMessage(SocketAsyncEventArgs args, MessageHeader header, ref BufferValueReader reader)
        {
            UdpConnection connection;

            if (!TryGetConnection(header.ConnectionId, out connection))
            {
                return;
            }

            byte[] buffer    = args.Buffer;
            int    offset    = args.Offset;
            int    moffset   = offset;
            int    remaining = args.BytesTransferred;

            MessageSerializer serializer = connection.serializer;

            if (serializer == null)
            {
                return;
            }

            if (header.State == HeaderState.IV)
            {
                serializer.DecryptMessage(header, ref reader);
                header.IsStillEncrypted = false;

                if (!serializer.TryGetHeader(reader, args.BytesTransferred, ref header))
                {
                    return;
                }
            }

            List <Message> messages = serializer.BufferMessages(ref buffer, ref offset, ref moffset, ref remaining, ref header, ref reader);

            if (messages != null)
            {
                foreach (Message message in messages)
                {
                    connection.Receive(message);
                }
            }

            reader.Position = 0;
        }
예제 #3
0
        protected void ReliableReceiveCompleted(object sender, SocketAsyncEventArgs e)
        {
            string callCategory = null;

                        #if TRACE
            int c = GetNextCallId();
            callCategory = String.Format("{2}:{4} {3}:ReliableReceiveCompleted({0},{1})", e.BytesTransferred, e.SocketError, this.typeName, c, this.connectionId);
                        #endif

            Trace.WriteLineIf(NTrace.TraceVerbose, "Entering", callCategory);

            bool receivedAsync;
            do
            {
                int p;
                if (e.BytesTransferred == 0 || e.SocketError != SocketError.Success)
                {
                    Disconnect();                     // This is right, don't mess with it anymore.
                    p = Interlocked.Decrement(ref this.pendingAsync);
                    Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", p), callCategory);
                    Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (error)", callCategory);
                    return;
                }

                                #if !SILVERLIGHT
                this.lastActivity = Stopwatch.GetTimestamp();
                                #else
                this.lastActivity = DateTime.Now.Ticks;
                                #endif

                Interlocked.Add(ref this.bytesReceived, e.BytesTransferred);

                p = Interlocked.Decrement(ref this.pendingAsync);
                Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", p), callCategory);

                this.rmessageLoaded += e.BytesTransferred;

                int bufferOffset = e.Offset;

                MessageSerializer slzr = this.serializer;
                if (slzr == null)
                {
                    p = Interlocked.Decrement(ref this.pendingAsync);
                    Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", p), callCategory);

                    Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (no serializer, probably disconnecting)", callCategory);
                    return;
                }

                List <Message> messages = slzr.BufferMessages(ref this.rmessageBuffer, ref bufferOffset, ref this.rmessageOffset, ref this.rmessageLoaded, ref this.currentHeader, ref this.rreader, CheckMessageId);
                if (messages != null)
                {
                    foreach (Message message in messages)
                    {
                        var args = new MessageEventArgs(this, message);

                        if (message is TempestMessage)
                        {
                            OnTempestMessageReceived(args);
                        }
                        else
                        {
                            OnMessageReceived(args);

                            if (message.Header.IsResponse)
                            {
                                Responses.Receive(message);
                            }
                        }
                    }
                }

                Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Exited BufferMessages with new values: {0},{1},{2},{3},{4}", this.rmessageBuffer.Length, bufferOffset, this.rmessageOffset, this.rmessageLoaded, this.rreader.Position), callCategory);
                e.SetBuffer(this.rmessageBuffer, bufferOffset, this.rmessageBuffer.Length - bufferOffset);

                p = Interlocked.Increment(ref this.pendingAsync);
                Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Increment pending: {0}", p), callCategory);

                lock (this.stateSync)
                {
                    if (!IsConnected)
                    {
                        p = Interlocked.Decrement(ref this.pendingAsync);
                        Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", p), callCategory);

                        Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (not connected)", callCategory);
                        return;
                    }

                    receivedAsync = this.reliableSocket.ReceiveAsync(e);
                }
            } while (!receivedAsync);

            Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting", callCategory);
        }
예제 #4
0
        private Task <bool> SendMessage(Message message, bool isResponse, bool requestingResponse, int responseTimeout, out Task <Message> responseTask)
        {
            string callCategory = null;

                        #if TRACE
            int c = GetNextCallId();
            callCategory = String.Format("{1}:{2} {3}:Send({0})", message, this.typeName, this.connectionId, c);
                        #endif
            Trace.WriteLineIf(NTrace.TraceVerbose, "Entering", callCategory);

            responseTask = null;

            TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool> (message);

            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            if (!IsConnected)
            {
                Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (not connected)", callCategory);
                tcs.SetResult(false);

                if (requestingResponse)
                {
                    var responseTcs = new TaskCompletionSource <Message>();
                    responseTcs.SetCanceled();
                    responseTask = responseTcs.Task;
                }

                return(tcs.Task);
            }

            SocketAsyncEventArgs eargs = null;
                        #if NET_4
            if (!writerAsyncArgs.TryPop(out eargs))
            {
                while (eargs == null)
                {
                    int count = bufferCount;
                    if (count == sendBufferLimit)
                    {
                        Trace.WriteLineIf(NTrace.TraceVerbose, "Waiting for writer args", callCategory);

                        SpinWait wait = new SpinWait();
                        while (!writerAsyncArgs.TryPop(out eargs))
                        {
                            wait.SpinOnce();
                        }
                    }
                    else if (count == Interlocked.CompareExchange(ref bufferCount, count + 1, count))
                    {
                        Trace.WriteLineIf(NTrace.TraceVerbose, "Creating new writer args", callCategory);

                        eargs = new SocketAsyncEventArgs();
                        eargs.SetBuffer(new byte[1024], 0, 1024);
                        eargs.Completed += ReliableSendCompleted;
                    }
                }
            }
                        #else
            while (eargs == null)
            {
                lock (writerAsyncArgs)
                {
                    if (writerAsyncArgs.Count != 0)
                    {
                        eargs = writerAsyncArgs.Pop();
                    }
                    else if (bufferCount != sendBufferLimit)
                    {
                        bufferCount++;
                        eargs = new SocketAsyncEventArgs();
                        eargs.SetBuffer(new byte[1024], 0, 1024);
                        eargs.Completed += ReliableSendCompleted;
                    }
                }
            }
                        #endif

                        #if !SILVERLIGHT
            eargs.AcceptSocket = null;
                        #endif

            Trace.WriteLineIf(NTrace.TraceVerbose, "Have writer args", callCategory);

            bool sent;
            lock (this.sendSync) {
                if (message.Header == null)
                {
                    message.Header = new MessageHeader();
                }

                message.Header.MessageId = MessageSerializer.GetNextMessageId(ref this.nextMessageId);

                if (requestingResponse)
                {
                    responseTask = Responses.SendFor(message, tcs.Task, responseTimeout);
                }

                MessageSerializer slzr = this.serializer;
                if (slzr == null)
                {
                    int sp = Interlocked.Decrement(ref this.pendingAsync);
                    Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", sp), callCategory);

                                        #if !NET_4
                    lock (writerAsyncArgs)
                                        #endif
                    writerAsyncArgs.Push(eargs);

                    Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (serializer is null, probably disconnecting)", callCategory);
                    tcs.SetResult(false);
                    return(tcs.Task);
                }

                int    length;
                byte[] buffer = slzr.GetBytes(message, out length, eargs.Buffer);

                eargs.SetBuffer(buffer, 0, length);
                eargs.UserToken = new KeyValuePair <NetworkConnection, TaskCompletionSource <bool> > (this, tcs);

                int p = Interlocked.Increment(ref this.pendingAsync);
                Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Increment pending: {0}", p), callCategory);

                if (!IsConnected)
                {
                    Interlocked.Decrement(ref this.pendingAsync);
                    Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", p), callCategory);

                                        #if !NET_4
                    lock (writerAsyncArgs)
                                        #endif
                    writerAsyncArgs.Push(eargs);

                    tcs.SetResult(false);
                    return(tcs.Task);
                }

                Trace.WriteLineIf(NTrace.TraceVerbose, "Sending", callCategory);
                sent = !this.reliableSocket.SendAsync(eargs);
            }

            if (sent)
            {
                Trace.WriteLineIf(NTrace.TraceVerbose, "Send completed synchronously", callCategory);
                ReliableSendCompleted(this.reliableSocket, eargs);
            }

            Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting", callCategory);
            return(tcs.Task);
        }
예제 #5
0
        protected Task <bool> SendCore(Message message, bool dontSetId, bool responseRequested, int timeout, out Task <Message> responseTask)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

            responseTask = null;

            Socket            sock        = this.socket;
            MessageSerializer mserialzier = this.serializer;

            TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool> (message);

            if (sock == null || mserialzier == null || (!IsConnected && !IsConnecting))
            {
                tcs.TrySetResult(false);

                if (responseRequested)
                {
                    var responseTcs = new TaskCompletionSource <Message>();
                    responseTcs.SetCanceled();
                    responseTask = responseTcs.Task;
                }

                return(tcs.Task);
            }

            if (message.Header == null)
            {
                message.Header = new MessageHeader();
            }

            if (!dontSetId)
            {
                SetMessageId(message);

                if (responseRequested)
                {
                    responseTask = Responses.SendFor(message, tcs.Task, timeout);
                }
            }

            IPEndPoint endPoint = IPEndPoint;

            if (endPoint == null)
            {
                tcs.SetResult(false);
                return(tcs.Task);
            }

            SocketAsyncEventArgs e;

            BufferPool.TryGetBuffer(out e);

            int length;

            byte[] buffer = mserialzier.GetBytes(message, out length, e.Buffer);
            if (!(message is PartialMessage) && length > 490)
            {
                byte count = (byte)Math.Ceiling((length / 490f));

                int i = 0;

                int remaining = length;
                do
                {
                    int payloadLen = Math.Min(490, remaining);

                    var partial = new PartialMessage
                    {
                        OriginalMessageId = (ushort)message.Header.MessageId,
                        Count             = count,
                        Header            = new MessageHeader()
                    };

                    partial.SetPayload(buffer, i, payloadLen);
                    if (i == 0)                     // We have to fill the gap the original id uses for reliability
                    {
                        partial.Header.MessageId = message.Header.MessageId;
                    }
                    else
                    {
                        SetMessageId(partial);
                    }

                    lock (this.pendingAck)
                        this.pendingAck.Add(partial.Header.MessageId, new Tuple <DateTime, Message> (DateTime.UtcNow, partial));

                    mserialzier.GetBytes(partial, out length, e.Buffer);

                    e.SetBuffer(0, length);
                    e.RemoteEndPoint = endPoint;

                    remaining -= payloadLen;
                    i         += payloadLen;

                    if (remaining == 0)
                    {
                        e.Completed += OnSendCompleted;
                        e.UserToken  = tcs;
                    }
                    else
                    {
                        e.Completed += OnPartialSendCompleted;
                    }

                    try {
                        this.lastReliableSendActivity = Stopwatch.GetTimestamp();
                        if (!sock.SendToAsync(e))
                        {
                            if (remaining == 0)
                            {
                                OnSendCompleted(this, e);
                            }
                            else
                            {
                                OnPartialSendCompleted(this, e);
                            }
                        }
                    } catch (ObjectDisposedException) {
                        BufferPool.PushBuffer(e);

                        if (remaining == 0)
                        {
                            CleanupSend(e);
                        }
                        else
                        {
                            CleanupPartialSend(e);
                        }

                        tcs.TrySetResult(false);
                    }

                    if (remaining > 0)
                    {
                        BufferPool.TryGetBuffer(out e);
                    }
                } while (remaining > 0);
            }
            else
            {
                e.SetBuffer(0, length);
                e.RemoteEndPoint = endPoint;
                e.Completed     += OnSendCompleted;
                e.UserToken      = tcs;

                if (message.PreferReliable || message.MustBeReliable)
                {
                    this.lastReliableSendActivity = Stopwatch.GetTimestamp();

                    lock (this.pendingAck)
                        this.pendingAck.Add(message.Header.MessageId, new Tuple <DateTime, Message> (DateTime.UtcNow, message));
                }

                try {
                    if (!sock.SendToAsync(e))
                    {
                        OnSendCompleted(this, e);
                    }
                } catch (ObjectDisposedException) {
                    CleanupSend(e);
                    tcs.TrySetResult(false);
                }
            }

            return(tcs.Task);
        }
예제 #6
0
        protected override void OnTempestMessageReceived(MessageEventArgs e)
        {
            switch (e.Message.MessageType)
            {
            case (ushort)TempestMessageType.Connect:
                var msg = (ConnectMessage)e.Message;

                if (!IsConnected)
                {
                    return;
                }

                if (!msg.Protocols.Any())
                {
                    DisconnectAsync(ConnectionResult.FailedHandshake);
                    return;
                }

                if (this.requiresHandshake)
                {
                    bool foundHashAlg = false;
                    foreach (string hashAlg in this.signatureHashAlgs)
                    {
                        if (msg.SignatureHashAlgorithms.Contains(hashAlg))
                        {
                            this.serializer.SigningHashAlgorithm = hashAlg;
                            foundHashAlg = true;
                            break;
                        }
                    }

                    if (!foundHashAlg)
                    {
                        DisconnectAsync(ConnectionResult.FailedHandshake);
                        return;
                    }
                }

                ConnectionId = this.provider.GetConnectionId();

                foreach (Protocol ip in msg.Protocols)
                {
                    Protocol lp;
                    if (!this.protocols.TryGetValue(ip.id, out lp) || !lp.CompatibleWith(ip))
                    {
                        DisconnectAsync(ConnectionResult.IncompatibleVersion);
                        return;
                    }
                }

                this.protocols         = this.protocols.Values.Intersect(msg.Protocols).ToDictionary(p => p.id);
                this.receivedProtocols = true;

                if (!this.requiresHandshake)
                {
                    this.formallyConnected = true;
                    this.provider.Connect(this);
                    e.Connection.SendAsync(new ConnectedMessage());
                }
                else
                {
                    while (!this.authReady)
                    {
                        Thread.Sleep(0);
                    }

                    MessageSerializer s = this.serializer;
                    if (s == null)
                    {
                        return;
                    }

                    e.Connection.SendAsync(new AcknowledgeConnectMessage
                    {
                        SignatureHashAlgorithm  = s.SigningHashAlgorithm,
                        EnabledProtocols        = this.protocols.Values,
                        ConnectionId            = ConnectionId,
                        PublicAuthenticationKey = this.provider.PublicAuthenticationKey,
                        PublicEncryptionKey     = this.provider.PublicEncryptionKey
                    });
                }
                break;

            case (ushort)TempestMessageType.FinalConnect:
                if (!this.receivedProtocols)
                {
                    DisconnectAsync(ConnectionResult.FailedHandshake);
                    return;
                }

                var finalConnect = (FinalConnectMessage)e.Message;

                if (finalConnect.AESKey == null || finalConnect.AESKey.Length == 0 || finalConnect.PublicAuthenticationKey == null)
                {
                    DisconnectAsync(ConnectionResult.FailedHandshake);
                    return;
                }

                try
                {
                    byte[] aeskey = this.provider.pkEncryption.Decrypt(finalConnect.AESKey);

                    this.serializer.HMAC = new HMACSHA256(aeskey);
                    this.serializer.AES  = new AesManaged {
                        KeySize = 256, Key = aeskey
                    };
                }
                catch
                {
                    DisconnectAsync(ConnectionResult.FailedHandshake);
                    return;
                }

                this.formallyConnected = true;
                this.provider.Connect(this);

                SendAsync(new ConnectedMessage {
                    ConnectionId = ConnectionId
                });

                break;
            }

            base.OnTempestMessageReceived(e);
        }