public SendState(Socket s, SendParameters sendParams)
 {
     this.SendSocket = s;
     this.SendParameters = sendParams;
 }
        /// <summary>
        /// Queue the send to the Socket buffer with no further delay.
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="length"></param>
        /// <param name="s"></param>
        private void SendNow(SendParameters sendItem)
        {
            Synchronizer.AssertLockIsHeld(m_SendQueue);
            AsyncCallback ac = new AsyncCallback(SendCallback);
            Socket s = null;
            while (true) {
                try {
                    s = null;
                    using (Synchronizer.Lock(this.m_SocketMap)) {
                        if (m_SocketMap.ContainsKey(sendItem.Id)) {
                            s = (Socket)m_SocketMap[sendItem.Id];
                        }
                        else {
                            //I believe this should never happen.
                            Debug.Assert(false, "TCPServerSender.SendNow thinks there is a missing socket map entry for client id: " + sendItem.Id.ToString());
                        }
                    }
                    using (Synchronizer.Lock(m_SendingParticipants)) {
                        if (m_SendingParticipants.ContainsKey(sendItem.Id)) {
                            ((ReferenceCounter)m_SendingParticipants[sendItem.Id]).Increment();
                        }
                        else {
                            m_SendingParticipants.Add(sendItem.Id, new ReferenceCounter());
                        }
                        ++m_PendingOutboundMessageCount;
                        s.BeginSend(sendItem.Buffer, 0, sendItem.Length, SocketFlags.None, ac, new SendState(s, sendItem)); //BeginSend won't block.
                    }

                    break;
                }
                catch (Exception e) {
                    using (Synchronizer.Lock(m_SendingParticipants)) {
                        if (m_SendingParticipants.ContainsKey(sendItem.Id)) {
                            ((ReferenceCounter)m_SendingParticipants[sendItem.Id]).Decrement();
                        }
                        --m_PendingOutboundMessageCount;
                        Debug.Assert(m_PendingOutboundMessageCount >= 0, "TCPServerSender.SendNow found negative pending message count");
                    }
                    if (e is SocketException) {
                        SocketException se = (SocketException)e;
                        if (se.ErrorCode == 10055) {
                            //Note that this shouldn't happen since we manually control the queue length.
                            Trace.WriteLine("!!!Server Send queue is full.  Sleeping 50 mS", this.GetType().ToString());
                            Thread.Sleep(50);  //Note that sleeping here could cause various bad performance because other threads may be waiting on us..
                        }
                        else {
                            Trace.WriteLine("Send socket exception: " + se.ToString() + " Error code: " + se.ErrorCode.ToString(), this.GetType().ToString());
                            this.DisableClient(sendItem.Id);
                            break;
                        }
                    }
                    else if (e is ObjectDisposedException) {
                        ObjectDisposedException ode = (ObjectDisposedException)e;
                        this.DisableClient(sendItem.Id);
                        Trace.WriteLine(ode.Message, this.GetType().ToString());
                        break;
                    }
                    else {
                        Trace.WriteLine(e.ToString(), this.GetType().ToString());
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// This has priority over other: return less than zero.
        /// Other has priority over this: return greater than zero.
        /// </summary>
        /// <param name="other"></param>
        /// <param name="currentSlideID"></param>
        /// <returns></returns>
        /// order:
        /// public node GuidEmpty
        /// public node current slide
        /// other node guid empty
        /// other node current slide
        /// lowest sequence number
        public int CompareTo(SendParameters other, Guid currentSlideID)
        {
            //If other is null, this has priority
            if (other == null)
                return -1;

            //Note: Guid.Empty indicates a message of global significance.
            //First priority for public node global or current slide message
            if (this.IsPublicNode != other.IsPublicNode) {
                if (this.IsPublicNode) {
                    if ((this.Tags.SlideID == Guid.Empty) || (this.Tags.SlideID == currentSlideID))
                        return -1;
                }
                else {
                    if ((other.Tags.SlideID == Guid.Empty) || (other.Tags.SlideID == currentSlideID))
                        return 1;
                }
            }

            //Second priority for global message
            if (this.Tags.SlideID == Guid.Empty) {
                if (other.Tags.SlideID == Guid.Empty) {
                        return (this.SequenceNumber < other.SequenceNumber) ? -1 : 1;
                }
                else
                    return -1;
            }
            else if (other.Tags.SlideID==Guid.Empty)
                return 1;

            //Third priority goes to messages for the current slide.
            if (this.Tags.SlideID == currentSlideID) {
                if (other.Tags.SlideID == currentSlideID)
                    return (this.SequenceNumber < other.SequenceNumber) ? -1 : 1;
                else
                    return -1;
            }
            else if (other.Tags.SlideID==currentSlideID)
                return 1;

            //finally just prioritize by sequence number.
            return (this.SequenceNumber < other.SequenceNumber) ? -1 : 1;
        }
            /// <summary>
            /// Undo a dequeue operation.
            /// </summary>
            /// <param name="sp"></param>
            private void Requeue(SendParameters sp)
            {
                lock (this) {
                    LinkedListNode<SendParameters> newNode = new LinkedListNode<SendParameters>(sp);

                    LinkedListNode<SendParameters> n = m_List.First;
                    while (true) {
                        if (n == null) {
                            m_List.AddLast(newNode);
                            break;
                        }
                        if (newNode.Value.SequenceNumber < n.Value.SequenceNumber) {
                            m_List.AddBefore(n, newNode);
                            break;
                        }
                        n = n.Next;
                    }

                    if (!m_SlideQueues.ContainsKey(sp.Tags.SlideID))
                        m_SlideQueues.Add(sp.Tags.SlideID, new SlideQueue());

                    ((SlideQueue)m_SlideQueues[sp.Tags.SlideID]).Requeue(newNode);
                }
            }
            public void Enqueue(SendParameters sp)
            {
                lock (this) {
                    LinkedListNode<SendParameters> node = new LinkedListNode<SendParameters>(sp);
                    m_List.AddLast(node);
                    if (!m_SlideQueues.ContainsKey(sp.Tags.SlideID))
                        m_SlideQueues.Add(sp.Tags.SlideID, new SlideQueue());

                    ((SlideQueue)m_SlideQueues[sp.Tags.SlideID]).Enqueue(node);
                }
            }
        /// <summary>
        /// Set the SequenceNumber property for the specified item, then enqueue it.
        /// </summary>
        /// <param name="sp"></param>
        public void Enqueue(SendParameters sp, ParticipantModel participant)
        {
            lock (this) {
                sp.SequenceNumber = m_NextSequenceNumber;
                m_NextSequenceNumber++;

                if (m_QueueList.ContainsKey(sp.Id)) {
                    ((ClientQueue)m_QueueList[sp.Id]).Enqueue(sp);
                }
                else {
                    ClientQueue cq = new ClientQueue(sp.Id, participant);
                    cq.Enqueue(sp);
                    m_QueueList.Add(sp.Id, cq);
                }
                //Trace.WriteLine("Enqueue guid=" + sp.Tags.SlideID.ToString() + "; seq =" + sp.SequenceNumber.ToString(), this.GetType().ToString());
            }
        }