/// <summary>
        /// Creates new ReliableUdpConnectionRecord and starts finite state automaton
        /// </summary>
        /// <param name="reliableUdpMessage"><see cref="ReliableUdpMessage"/> message to send.</param>
        /// <param name="endPoint">Ip endpoint of recipient of the message.</param>
        /// <param name="asyncResult"><see cref="AsyncResultSendMessage"/> object</param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ReliableUdpConfigurationException"></exception>
        /// <returns></returns>
        private void StartTransmission(ReliableUdpMessage reliableUdpMessage, EndPoint endPoint, CancellationToken cToken,
            AsyncResultSendMessage asyncResult)
        {
            try
              {
            if (m_isListenerStarted == 0)
            {
              if (this.LocalEndpoint == null)
              {
            throw new ArgumentNullException( "", "You must use constructor with parameters or start listener before sending message" );
              }
              StartListener(LocalEndpoint);
            }
            //RU: создаем ключ для словаря, на основе EndPoint и ReliableUdpHeader.TransmissionId
            //EN: create key based on EndPoint and ReliableUdpHeader.TransmissionId for dictionary
            byte[] transmissionId = new byte[4];

            //RU: только криптопровайдер! random выдает одинаковые номера для двух одновременно созданных TCB
            //EN: should use only cryptographic random function. System.Random gives the same values for two
            //EN: or more ConnnectionControlBlock created at the same time
            m_randomCrypto.GetBytes(transmissionId);
            Tuple<EndPoint, Int32> key = new Tuple<EndPoint, Int32>(endPoint, BitConverter.ToInt32(transmissionId, 0));
            Debug.WriteLine("Transmission Id is {0}", key.Item2);
            //EN: make two attemps to add key into dictionary
            if (!m_listOfHandlers.TryAdd(key, new ReliableUdpConnectionRecord(key, this, reliableUdpMessage, cToken, asyncResult)))
            {
              m_randomCrypto.GetBytes(transmissionId);
              key = new Tuple<EndPoint, Int32>(endPoint, BitConverter.ToInt32(transmissionId, 0));
              if (!m_listOfHandlers.TryAdd(key, new ReliableUdpConnectionRecord(key, this, reliableUdpMessage,cToken, asyncResult)))
            throw new ArgumentException("Pair TransmissionId & EndPoint is already exists in the dictionary");
            }
            //RU: запустили состояние в обработку.
            //EN: run state handling
            m_listOfHandlers[key].State.SendPacket(m_listOfHandlers[key]);
              }
            //RU: Все исключения в состояниях обрабатываются отдельно
            //RU: здесь ловятся только те, которые могут появиться до запуска конечного автомата
            //EN: All exceptions that raised in states are handled separately
              catch (ArgumentNullException ex)
              {
            if (asyncResult != null)
            {
              asyncResult.SetAsCompleted(ex);
            }
            else
            {
              throw;
            }
              }
              catch (ArgumentOutOfRangeException ex)
              {
            if (asyncResult != null)
            {
              asyncResult.SetAsCompleted(ex);
            }
            else
            {
              throw;
            }
              }
              catch (ArgumentException ex)
              {
            if (asyncResult != null)
            {
              asyncResult.SetAsCompleted(ex);
            }
            else
            {
              throw;
            }
              }
              catch (ReliableUdpConfigurationException ex)
              {
            if (asyncResult != null)
            {
              asyncResult.SetAsCompleted(ex);
            }
            else
            {
              throw;
            }
              }
        }
        /// <summary>
        /// Sends the <paramref name="reliableUdpMessage"/> asynchronously to the specified endpoint.
        /// </summary>
        /// <param name="reliableUdpMessage"><see cref="ReliableUdpMessage"/> message to send.</param>
        /// <param name="remoteEndPoint">Ip endpoint of recipient of the message.</param>
        /// <param name="callback">The <see cref="AsyncCallback"/> delegate.</param>
        /// <param name="state">An object that contains state information for this request.</param>
        /// <returns>An IAsyncResult that references the asynchronous send.</returns>
        public IAsyncResult BeginSend(ReliableUdpMessage reliableUdpMessage,
            IPEndPoint remoteEndPoint, AsyncCallback callback, Object state)
        {
            //RU: упаковали данные в собственный AsyncResult
              //EN: wrapped data in our own AsyncResult
              AsyncResultSendMessage ar = new AsyncResultSendMessage(reliableUdpMessage, remoteEndPoint,CancellationToken.None, callback, state, this);

              ThreadPool.QueueUserWorkItem(StartTransmissionHelper, ar);
              return ar;
        }
 private IAsyncResult BeginSendTask(WrappedBeginSendParameters obj, AsyncCallback callback, Object state)
 {
     //RU: упаковали данные в собственный AsyncResult
       //EN: wrapped data in our own AsyncResult
       AsyncResultSendMessage ar = new AsyncResultSendMessage( obj.ReliableUdpMessage, obj.RemoteEndPoint,obj.Token, callback, state, this );
       ThreadPool.QueueUserWorkItem( StartTransmissionHelper, ar );
       return ar;
 }
 /// <summary>
 /// Initializes a new instance of the ReliableUdpConnectionRecord
 /// to send message 
 /// </summary>
 /// <param name="key">EndPoint and TransmissionId key</param>
 /// <param name="tcb">Connection control block. <see cref="ReliableUdpConnectionControlBlock"/></param>
 /// <param name="reliableUdpMessage"><see cref="ReliableUdpMessage"/> message to send.</param>
 /// <param name="cToken">CancellationToken</param>
 /// <param name="asyncResult"><see cref="AsyncResultSendMessage"/></param>
 /// <exception cref="ArgumentNullException"><paramref name="key"/> or <paramref name="tcb"/> is a null reference</exception>
 public ReliableUdpConnectionRecord(Tuple<EndPoint, Int32> key, ReliableUdpConnectionControlBlock tcb,
                                ReliableUdpMessage reliableUdpMessage, CancellationToken cToken, AsyncResultSendMessage asyncResult)
     : this(key, tcb)
 {
     if (reliableUdpMessage == null)
       {
     throw new ArgumentNullException("reliableUdpMessage");
       }
       if (reliableUdpMessage.Body == null || reliableUdpMessage.Body.Length == 0)
       {
     throw new ArgumentNullException("reliableUdpMessage", "reliableUdpMessage.Body can not be null.");
       }
       CToken = cToken;
       this.AsyncResult = asyncResult;
       this.ReliableUdpMessageType = reliableUdpMessage.Type;
       this.IsNoAnswerNeeded = reliableUdpMessage.NoAsk;
       //RU: добавляем содержимое ReliableUdpMessage в словарь ReliableUdpConnectionControlBlock'a
       //EN: fills the array of outcoming message with message bytes
       this.OutcomingStream = Tcb.OutcomingStreams.GetOrAdd(key, reliableUdpMessage.Body);
       //RU: Расчитываем количество пакетов необходимых для отправки сообщения
       this.NumberOfPackets = (int) Math.Ceiling((double) ((double) OutcomingStream.Length/(double) this.BufferSize));
       //RU: переключаем состояние на отправку первого пакета
       //EN: set initial state
       this.State = Tcb.States.FirstPacketSending;
 }