/// <summary> /// Выполняет одноразовую операцию получения и отправки пакетов. /// </summary> public override void Process() { // Flush send buffer OSCARQueueEntity toSend; while (!m_sendBuffer.IsEmpty) if (m_sendBuffer.TryDequeue(out toSend)) sendPacket(toSend.Host, ref toSend.FLAP, toSend.Data); else break; // Receive packets byte[] data; EndPoint from; while (this.readPacket(ref m_svcFlap, out data, out from)) HandlePacket(ref m_svcFlap, data, (IPEndPoint)from); // Check connect attempt if (m_connReq != null) // IsConnecting { // Did connection attempt failed (No response?) if ((Environment.TickCount - m_connReq.LastSent) >= ConnReq.Timeout) { // Did we reached fail limit? if (m_connReq.AttemptsTaken >= ConnReq.AttemptsLimit) { var host = m_connReq.Host; var error = new TimeoutException("OSCARUdp connection attempt timed out, response was not received."); m_connReq = null; m_events.ConnectFailed(this, new HostErrorEventArgs(host, error)); } else { // Re-send m_connReq.Send(this, ref m_svcFlap); } } } }
private void HandlePacket(ref FLAPHeader flap, byte[] data, IPEndPoint from) { var tlvs = (TLVChain)data; var type = tlvs[SvcLayer.TLV_TYPE].Value[0]; switch(type) { case SvcLayer.TYPE_USER_DATA: if (Connections.Contains(from)) m_events.TriggerPacketReceived(this, new PacketEventArgs(from, ref flap, tlvs[SvcLayer.TLV_USER_DATA].Value)); break; case SvcLayer.TYPE_CONNECT_ACCEPT: if (IsConnecting && m_connReq.Host.Equals(from) && Misc.CompareByteArrays(m_connReq.Hash, tlvs[SvcLayer.TLV_CONNECT_HASH].Value)) { m_connReq = null; Connections.Add(from); m_events.Connected(this, new HostConnectEventArgs(from, true)); } break; case SvcLayer.TYPE_CONNECT_REQST: if (m_acceptsIncomingConnections && (!this.IsConnecting || m_connReq.Host != from) && m_events.AuthorizeIncomingConnection(this, new HostEventArgs(from)) && !this.Connections.Contains(from)) { var tosend = new TLVChain(2) { new TLV { TypeID = SvcLayer.TLV_TYPE, Value = new byte[1] { SvcLayer.TYPE_CONNECT_ACCEPT } }, new TLV { TypeID = SvcLayer.TLV_CONNECT_HASH, Value = tlvs[SvcLayer.TLV_CONNECT_HASH].Value } }; sendPacket(from, ref flap, (byte[])tosend); Connections.Add(from); m_events.Connected(this, new HostConnectEventArgs(from, false)); } break; } }
/// <summary> /// Запускает попытку исходящего подключения к удаленному хосту. /// </summary> /// <param name="to">Удаленный узел для подключения</param> /// <param name="async">Значение False заблокирует исполнение программы до окончания исходящего подключения</param> public override void Connect(EndPoint to, bool async = true) { if (this.IsConnecting) throw new InvalidOperationException("There is already active outgoing connect attempt in progress."); else if(this.Connections.Contains(to)) throw new ArgumentException("This address is already connected to current peer!"); m_connReq = new ConnReq(to); m_connReq.Send(this, ref m_svcFlap); m_events.ConnectStarted(this, new HostEventArgs(to)); if (!async) while (this.IsConnecting) Thread.Sleep(50); }