예제 #1
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);
        }
예제 #2
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);
        }