private void ListenerLoop()
{
try
{
NetworkStream ns = _tcpClient.GetStream();
while (ns.CanRead)
{
#region Read header and payload from network
Header header;
Payload payload;
try
{
header = new Header(BinaryReader);
payload =
(header.Length == 0)
? new Payload(header.Command, null)
: new Payload(header.Command, BinaryReader.ReadBytes(header.Length));
}
catch (Exception e)
{
string excptionStr = e.ToString();
if ((e is IOException) || (e is SocketException))
excptionStr = "";
Debug.WriteLine("соединение " + NetworkAddress + " потерено " + excptionStr);
Bitmessage.NodeIsDisconnected.Set();
break;
}
#endregion Read header and payload from network
bool checksum = header.Checksum.SequenceEqual(payload.Checksum());
if (checksum && payload.IsValid)
{
debug("Command=" + header.Command);
#region Save payload to Inventory
if ((header.Command == "msg") || (header.Command == "pubkey") || (header.Command == "broadcast") || (header.Command == "getpubkey"))
{
_nodeConnectionInventory.Insert(payload.InventoryVector);
payload.SaveAsync(Bitmessage);
}
#endregion Save to Inventory
#region VERSION
if (header.Command == "version")
{
var v = new Version(payload);
debug("Подключились с " + v.UserAgent);
if ((v.Value != 1) && (v.Value != 2))
Stop("Version = " + v.Value);
else if (v.Nonce == Version.EightBytesOfRandomDataUsedToDetectConnectionsToSelf)
{
Bitmessage.DeleteNode(NetworkAddress);
Stop("DetectConnectionsToSelf");
}
else
Send(new Verack());
}
#endregion VERSION
#region INV
else if (header.Command == "inv")
{
var inputInventory = new Inv(payload.SentData);
var buff4GetData = new MemoryInventory(inputInventory.Count);
debug("прислали inv. Inventory.Count=" + inputInventory.Count);
//lock (Bitmessage.MemoryInventory)
//{
foreach (byte[] inventoryVector in inputInventory)
{
_nodeConnectionInventory.Insert(inventoryVector);
if (!Bitmessage.MemoryInventory.Exists(inventoryVector))
{
Bitmessage.MemoryInventory.AddWait(inventoryVector);
buff4GetData.Insert(inventoryVector);
}
}
//}
if (buff4GetData.Count > 0)
{
debug("SendGetdata count=" + buff4GetData.Count);
Send(new GetData(buff4GetData));
}
else
debug("All know, don't send GetData");
}
#endregion
#region verack
else if (header.Command == "verack")
{
Send(new Inv(Bitmessage.MemoryInventory));
NetworkAddress.TimeLastSeen = DateTime.UtcNow;
NetworkAddress.SaveAsync(Bitmessage.DB);
}
#endregion
#region getpubkey
else if (header.Command == "getpubkey")
{
var getpubkey = new GetPubkey(payload);
PrivateKey pk = Bitmessage.FindPrivateKey(getpubkey);
if ((pk != null) &&
(pk.LastPubkeySendTime.ToUnix() <
(DateTime.UtcNow.ToUnix() - Payload.LengthOfTimeToHoldOnToAllPubkeys)))
{
pk.SendAsync(Bitmessage);
}
}
#endregion getpubkey
#region pubkey
else if (header.Command == "pubkey")
{
int pos = payload.FirstByteAfterTime;
var pubkey = new Pubkey(payload.SentData, ref pos, true);
if (pubkey.Status == Status.Valid)
{
pubkey.SaveAsync(Bitmessage.DB);
Bitmessage.OnReceivePubkey(pubkey);
}
else
Bitmessage.OnReceiveInvalidPubkey(pubkey);
}
#endregion PUBKEY
#region msg
else if (header.Command == "msg")
{
var msg = new Msg(Bitmessage, payload);
msg.SaveAsync(Bitmessage.DB);
if (msg.Status == Status.Valid)
Bitmessage.OnReceiveMsg(msg);
else
Bitmessage.OnReceiveInvalidMsg(msg);
}
#endregion MSG
#region broadcast
else if (header.Command == "broadcast")
{
var broadcast = new Broadcast(Bitmessage, payload);
broadcast.SaveAsync(Bitmessage.DB);
if (broadcast.Status == Status.Valid)
Bitmessage.OnReceiveBroadcast(broadcast);
else
Bitmessage.OnReceiveInvalidBroadcast(broadcast);
}
#endregion BROADCAST
#region addr
else if (header.Command == "addr")
{
int pos = 0;
UInt64 numberOfAddressesIncluded = payload.SentData.ReadVarInt(ref pos);
if ((numberOfAddressesIncluded > 0) && (numberOfAddressesIncluded < 1001))
{
if (payload.Length != (pos + (38*(int) numberOfAddressesIncluded)))
throw new Exception(
"addr message does not contain the correct amount of data. Ignoring.");
while (pos < payload.Length)
{
NetworkAddress networkAddress = NetworkAddress.GetFromAddrList(payload.SentData,
ref pos);
Bitmessage.AddNode(networkAddress);
}
}
}
#endregion addr
#region getdata
else if (header.Command == "getdata")
{
debug("Load getdata");
var getData = new GetData(payload.SentData);
foreach (byte[] hash in getData.Inventory)
Payload.SendAsync(this, hash.ToHex(false));
}
#endregion getdata
#region ping
else if (header.Command == "ping")
{
Send(new Pong());
}
#endregion ping
#region pong
else if (header.Command == "pong")
{
}
#endregion pong
else debug("unknown command");
}
else
debug("checksum error");
}
_tcpClient.Close();
}
// ReSharper disable EmptyGeneralCatchClause
catch(Exception e)
{
debug("Закрываю соединение " + e);
} // ReSharper restore EmptyGeneralCatchClause
Bitmessage.NodeIsDisconnected.Set();
}