internal void Send(byte[] buffer, TimeSpan timeout, string messageType)
        {
            ThrowIfDisposedOrNotOpen();
            TimeoutHelper helper = new TimeoutHelper(timeout);


            //if the client hasn't explicitly begun a conversation, start one here.
            // CONSIDER (dbrowne) automatically ending the conversation in this case.
            if (conversation == null)
            {
                BeginNewConversation();
                this.endConversationOnClose = true;
            }

            try
            {
                string     SQL = string.Format(@"SEND ON CONVERSATION @Conversation MESSAGE TYPE [{0}](@MessageBody)", SsbHelper.ValidateIdentifier(messageType));
                SqlCommand cmd = new SqlCommand(SQL, con);

                cmd.CommandTimeout = helper.RemainingTimeInMillisecondsOrZero();
                SqlParameter pConversation = cmd.Parameters.Add("@Conversation", SqlDbType.UniqueIdentifier);
                pConversation.Value = this.conversation.ConversationHandle;

                SqlParameter pMessageBody = cmd.Parameters.Add("@MessageBody", SqlDbType.VarBinary);
                pMessageBody.Value = buffer;

                try
                {
                    cmd.ExecuteNonQuery();
                }
                catch (SqlException ex)
                {
                    if (ex.Number == 8429)
                    {
                        string errorMessage = SsbHelper.CheckConversationForErrorMessage(con, this.conversation.ConversationHandle);
                        if (errorMessage != null)
                        {
                            throw new Exception(errorMessage);
                        }
                        throw;
                    }
                    throw;
                }
                SsbInstrumentation.MessageSent(buffer.Length);
            }
            catch (Exception e)
            {
                if (!helper.IsTimeRemaining)
                {
                    throw new TimeoutException("Timed out while sending a message. The timeout value passed in was " + timeout.TotalSeconds + " seconds");
                }
                else
                {
                    throw new CommunicationException(String.Format("An exception occurred while sending on conversation {0}.", this.conversation.ConversationHandle), e);
                }
            }
        }
        internal byte[] Receive(TimeSpan timeout, BufferManager  bm, out int messageLength, out SsbConversationContext conversation,WaitHandle cancelEvent)
        {
            ThrowIfDisposedOrNotOpen();

            byte[] message = null;
            conversation = null;
            messageLength = 0;

            if (queuedResult != null)
            {
                ReceivedMessage r = queuedResult;
                queuedResult = null;
                conversation = r.Conversation;
                messageLength = r.MessageLength;
                byte[] buf = bm.TakeBuffer(messageLength);
                Buffer.BlockCopy(r.MessageBody, 0, buf, 0, messageLength);
                return buf;
            }
            try
            {
                lock (rdrlock)
                {
                    

                    //If this is the first time, open the reader, otherwise read the next row
                    if ( rdr == null || !rdr.Read() )
                    {
                        //the last bactch has been processed.  Close the reader.
                        if (rdr != null)
                        {
                            rdr.Close();
                        }

                        rdr = GetMessageBatch(timeout,cancelEvent);

                        //this is a timeout condition
                        //caused by aborting or closing the reciever
                        if ( rdr == null )
                        {
                            return null;
                        }

                        //this is a timeout condition caused by the WAITFOR expiring
                        if( !rdr.Read() )
                        {
                            rdr.Close();

                            //return the Receiver to it's initial state.
                            rdr = null;
                            return null;
                        }
                    }


                    int i = 0;
                    int conversation_handle = i++;
                    int service_name = i++;
                    int message_type_name = i++;
                    int message_body = i++;
                    int message_sequence_number = i++;
                    Guid conversationHandle = rdr.GetGuid(conversation_handle);
                    string ServiceName = rdr.GetString(service_name);
                    string messageTypeName = rdr.GetString(message_type_name);
                    if (messageTypeName != SsbConstants.SsbEndDialogMessage  && messageTypeName != SsbConstants.SsbDialogTimerMessage)
                    {
                                             

                        //this eliminates a one copy because the message_body 
                        //isn't copied into the row buffer.  Instead it's chunked directly
                        //into the message byte[].
                        // CONSIDER (dbrowne) wraping the reader in a custom stream implementation
                        //and pass that back instead to eliminate another copy.
                        messageLength = (int)rdr.GetBytes(message_body, 0, null, 0, 0);
                        if (bm == null)
                        {
                            message = new byte[messageLength];
                        }
                        else
                        {
                            message = bm.TakeBuffer(messageLength);
                        }
                        int br = (int)rdr.GetBytes(message_body, 0, message, 0, messageLength);
                        if (br != messageLength) //should never happen
                        {
                            throw new Exception("Failed to read all the message bytes");
                        }
                    }

                    long sequence = rdr.GetInt64(message_sequence_number);
                    conversation = new SsbConversationContext(conversationHandle, this.cgId, sequence, messageTypeName);

                    if (messageTypeName == SsbConstants.SsbErrorMessage)
                    {
                        System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
                        doc.Load(new System.IO.MemoryStream(message, 0, messageLength));

                        System.Xml.XmlNamespaceManager mgr = new System.Xml.XmlNamespaceManager(doc.NameTable);
                        mgr.AddNamespace("er", SsbConstants.SsbErrorMessage);
                        int code = int.Parse(doc.SelectSingleNode("/er:Error/er:Code", mgr).InnerText);
                        string ermsg = doc.SelectSingleNode("/er:Error/er:Description", mgr).InnerText;

                        throw new ProtocolException(string.Format("Service Broker Error Message {0}: {1}", code, ermsg));
                    }

                    SsbInstrumentation.MessageRecieved(messageLength);
                    return message;

                    //if (messageTypeName == SsbConstants.SsbDialogTimerMessage)
                    //{
                    //    //well now we're running again after a lag, now what?
                        
                    //}
                    
                }
                
            }
            catch (SqlException ex)
            {
                //the timeout will not result in a SqlExecption since the timeout value is passed to WAITFOR RECIEVE
                //if (!helper.IsTimeRemaining)
                //{
                //    throw new TimeoutException(String.Format("Timed out while receiving. Timeout value was {0} seconds", timeout.TotalSeconds), ex);
                //}
                
              throw new CommunicationException(String.Format("An exception occurred while receiving from conversation group {0}.", this.cgId), ex);
            }
        }