/* * @project: TERA * @version: Development (beta) * @license: MIT (not for evil) * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] * Web: https://terafoundation.org * Twitter: https://twitter.com/terafoundation * Telegram: https://t.me/terafoundation */ "use strict"; import "./library" import * as net from "net" import { secp256k1, RBTree } from '../core/library' var ConnectIDCount = 1; export class TeraSocket extends net.Socket { ConnectToServer: boolean; Node: CNode; ConnectID: string; WasClose: number; SocketStatus: number; Buf: Buffer; SocketNum: number; SocketPrioritet: number; } export default class CNode { addrStr ip port StartFindList WhiteConnect GrayConnect POW FirstTime FirstTimeStr LastTime LastTimeError LastTimeTransfer FromIP FromPort Active Hot CanHot CountChildConnect BlockProcessCount VersionOK VersionNum Delete DeltaBan Name Info PrevInfo StartTimeHot NextHotDelta LastTimeGetNode DeltaGlobTime CountDeltaTime DeltaTime SumDeltaTime TransferCount StopGetBlock LevelCount LevelEnum TimeMap bInit INFO DoubleConnectCount StartTimeConnect NextConnectDelta StartTimeGetNodes NextGetNodesDelta PingStart NextPing SendBlockArr LoadBlockArr SendBlockCount LoadBlockCount SendBlockCountAll LoadBlockCountAll WantHardTrafficArr WantHardTraffic CanHardTraffic BufWriteLength BufWrite SendPacket: RBTree ConnectCount TrafficArr SendTrafficCurrent SendTrafficLimit ErrCount ErrCountAll SendPacketNum Socket: TeraSocket Socket2: TeraSocket ReconnectFromServer SecretForReconnect Self: boolean addrStrTemp DoubleConnection PubKey addrArr SocketStart WaitConnectFromServer WaitConnectIP constructor(addrStr, ip, port) { this.addrStr = addrStr this.ip = ip.trim() this.port = port this.StartFindList = 0 this.WhiteConnect = 0 this.GrayConnect = 0 this.POW = 0 this.FirstTime = 0 this.FirstTimeStr = "" this.LastTime = 0 this.LastTimeError = 0 this.LastTimeTransfer = 0 this.FromIP = undefined this.FromPort = undefined this.Active = false this.Hot = false this.CanHot = false this.CountChildConnect = 0 this.BlockProcessCount = 0 this.VersionOK = false this.VersionNum = 0 this.Delete = 0 this.DeltaBan = 300 this.Name = "" this.Info = "" this.PrevInfo = "" this.StartTimeHot = 0 this.NextHotDelta = 1000 this.ResetNode() } ResetNode() { this.LastTimeGetNode = 0 this.DeltaGlobTime = 0 this.CountDeltaTime = 0 this.DeltaTime = 1000 this.SumDeltaTime = 0 this.TransferCount = 0 this.StopGetBlock = 0 this.LevelCount = 0 this.LevelEnum = 100 this.TimeMap = {} this.bInit = 1 this.INFO = {} this.DoubleConnectCount = 0 this.StartTimeConnect = 0 this.NextConnectDelta = 1000 this.StartTimeGetNodes = 0 this.NextGetNodesDelta = 1000 this.PingStart = 0 this.NextPing = global.MIN_PERIOD_PING this.SendBlockArr = [] this.LoadBlockArr = [] this.SendBlockCount = 0 this.LoadBlockCount = 0 this.SendBlockCountAll = 0 this.LoadBlockCountAll = 0 this.WantHardTrafficArr = [] this.WantHardTraffic = 0 this.CanHardTraffic = 0 this.BufWriteLength = 0 this.BufWrite = Buffer.alloc(0) this.SendPacket = new RBTree(function(a, b) { return b.PacketNum - a.PacketNum; } as any) this.ConnectCount = 0 this.TrafficArr = [] this.SendTrafficCurrent = 0 this.SendTrafficLimit = 0 this.ErrCount = 0 this.ErrCountAll = 0 var Prioritet = this.BlockProcessCount; global.SERVER.SetNodePrioritet(this, Prioritet) this.SendPacketNum = 0 } ConnectStatus() { if (this.Socket) return GetSocketStatus(this.Socket); else return 0; } CreateConnect() { delete global.SERVER.BAN_IP[this.ip] let NODE = this; if (NODE.ConnectStatus()) { if (NODE.ConnectStatus() === 100) global.SERVER.AddNodeToActive(NODE) return; } global.AddNodeInfo(NODE, "===CreateConnect===") global.CloseSocket(NODE.Socket, "CreateConnect") NODE.SocketStart = Date.now() NODE.Socket = net.createConnection(NODE.port, NODE.ip, function() { if (NODE.Socket) { global.socketInit(NODE.Socket, "s") global.AddNodeInfo(NODE, "OK connected *" + NODE.Socket.ConnectID) NODE.Socket.ConnectToServer = true SetSocketStatus(NODE.Socket, 2) } }) as TeraSocket SetSocketStatus(NODE.Socket, 1) NODE.Socket.Node = NODE NODE.Socket.ConnectID = "~C" + ConnectIDCount ConnectIDCount++ this.SetEventsProcessing(NODE.Socket, 0) } CreateReconnection() { let NODE = this; global.AddNodeInfo(NODE, "===CreateReconnection===") global.CloseSocket(NODE.Socket2, "CreateReconnection") NODE.SocketStart = Date.now() NODE.Socket2 = net.createConnection(NODE.port, NODE.ip, function() { if (NODE.Socket2) { global.socketInit(NODE.Socket2, "s") global.AddNodeInfo(NODE, "OK Reconnected *" + NODE.Socket2.ConnectID) NODE.Socket2.ConnectToServer = true SetSocketStatus(NODE.Socket2, 2) } }) as TeraSocket SetSocketStatus(NODE.Socket2, 1) NODE.Socket2.Node = NODE NODE.Socket2.ConnectID = "~R" + ConnectIDCount ConnectIDCount++ this.SetEventsProcessing(NODE.Socket2, 1) } SwapSockets() { if (!this.Socket2) return; var SocketOld = this.Socket; this.Socket = this.Socket2 this.Socket2 = undefined this.Socket.Node = this SetSocketStatus(this.Socket, 100) this.Socket.Buf = SocketOld.Buf global.SERVER.LoadBufSocketList.remove(SocketOld) global.SERVER.LoadBufSocketList.insert(this.Socket) SocketOld.Buf = undefined SocketOld.WasClose = 1 SocketOld.Node = undefined this.ErrCount = 0 } SetEventsProcessing(Socket, Reconnection) { let SOCKET = Socket; let NODE = this; let RECONNECTION = Reconnection; SOCKET.on('data', function(data) { if (Socket.WasClose) return; if (GetSocketStatus(SOCKET) === 2) { SetSocketStatus(SOCKET, 3) var Buf = global.SERVER.GetDataFromBuf(data); if (Buf) { var Res = NODE.SendPOWFromClientToServer(SOCKET, Buf.Data); if (Res) { return; } } global.CloseSocket(SOCKET, Buf ? "Method=" + Buf.Method : "=CLIENT ON DATA=") } else if (GetSocketStatus(SOCKET) === 3) { var Buf = global.SERVER.GetDataFromBuf(data); if (Buf) { var Str = Buf.Data; if (Str && Str.substr(0, 24) === "WAIT_CONNECT_FROM_SERVER") { global.AddNodeInfo(NODE, "2. CLIENT OK POW") global.CloseSocket(SOCKET, "WAIT_CONNECT_FROM_SERVER") NODE.WaitConnectFromServer = 1 NODE.WaitConnectIP = NODE.ip try { NODE.SecretForReconnect = global.GetArrFromHex(Str.substr(25)) } catch (e) { NODE.SecretForReconnect = [] global.ToLog(e) } } else if (Str === "OK") { NODE.NextConnectDelta = 1000 SetSocketStatus(SOCKET, 100) global.AddNodeInfo(NODE, "4. CLIENT OK CONNECT") if (RECONNECTION) { if (NODE.Socket) SetSocketStatus(NODE.Socket, 200) } else { if (!NODE.Active) global.SERVER.AddNodeToActive(NODE) } return; } else if (Str === "SELF") { NODE.Self = true } else if (Str === "DOUBLE") { } else { global.AddNodeInfo(NODE, "ERROR:" + Str) } } global.CloseSocket(SOCKET, Buf ? "Method=" + Buf.Method + ":" + Str : "=CLIENT ON DATA=") } else { global.socketRead(Socket, data) global.SERVER.OnGetFromTCP(NODE, Socket, data) } }) SOCKET.on('end', function() { if (GetSocketStatus(SOCKET)) global.AddNodeInfo(NODE, "Get socket end *" + SOCKET.ConnectID + " Stat: " + SocketStatistic(SOCKET)) if (GetSocketStatus(SOCKET) === 200) { NODE.SwapSockets() SOCKET.WasClose = 1 } }) SOCKET.on('close', function(err) { if (SOCKET.ConnectID && GetSocketStatus(SOCKET)) global.AddNodeInfo(NODE, "Get socket close *" + SOCKET.ConnectID + " Stat: " + SocketStatistic(SOCKET)) if (!SOCKET.WasClose) { if (GetSocketStatus(SOCKET) >= 2) { global.CloseSocket(SOCKET, "GET CLOSE") } } SetSocketStatus(SOCKET, 0) }) SOCKET.on('error', function(err) { if (GetSocketStatus(SOCKET) >= 2) { global.SERVER.AddCheckErrCount(NODE, 1, "ERR##1 : socket") global.ADD_TO_STAT("ERRORS") } }) } SendPOWFromClientToServer(Socket, data) { var Node = this; if (Node.ReconnectFromServer) { Node.ReconnectFromServer = 0 var Info = this.GetPOWClientData(0); Info.Reconnect = 1 Info.SecretForReconnect = Node.SecretForReconnect var BufWrite = global.BufLib.GetBufferFromObject(Info, global.FORMAT_POW_TO_SERVER, 1200, {}); var BufAll = global.SERVER.GetBufFromData("POW_CONNECT7", BufWrite, 1); Socket.write(BufAll) return 1; } try { var Buf = global.BufLib.GetObjectFromBuffer(data, global.FORMAT_POW_TO_CLIENT, {}); } catch (e) { global.SERVER.SendCloseSocket(Socket, "FORMAT_POW_TO_CLIENT") return 0; } if (global.CompareArr(Buf.addrArr, global.SERVER.addrArr) === 0) { Node.Self = true global.AddNodeInfo(Node, "END: SELF") global.SERVER.SendCloseSocket(Socket, "SELF") return; } var addrStr = global.GetHexFromAddres(Buf.addrArr); if (!Node.StartFindList && addrStr !== Node.addrStr) { global.AddNodeInfo(Node, "END: CHANGED ADDR: " + Node.addrStr.substr(0, 16) + "->" + addrStr.substr(0, 16)) global.SERVER.SendCloseSocket(Socket, "ADDRESS_HAS_BEEN_CHANGED") return; } if (Node.addrStrTemp) { global.AddNodeInfo(Node, "Set Addr = " + addrStr) Node.addrStr = addrStr global.SERVER.CheckNodeMap(Node) } var Result = false; if (Buf.PubKeyType === 2 || Buf.PubKeyType === 3) { Result = secp256k1.verify(Buffer.from(global.shaarr(addrStr)), Buffer.from(Buf.Sign), Buffer.from([Buf.PubKeyType].concat(Buf.addrArr))) if (!Result) { Result = secp256k1.verify(Buffer.from(global.sha3(addrStr)), Buffer.from(Buf.Sign), Buffer.from([Buf.PubKeyType].concat(Buf.addrArr))) } } if (!Result) { global.ToLog("END: ERROR_SIGN_SERVER ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress) global.AddNodeInfo(Node, "END: ERROR_SIGN_SERVER ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress) global.SERVER.SendCloseSocket(Socket, "ERROR_SIGN_SERVER") return; } if (Buf.MIN_POWER_POW_HANDSHAKE > 1 + global.MIN_POWER_POW_HANDSHAKE) { global.ToLog("END: BIG_MIN_POWER_POW_HANDSHAKE ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress) return 0; } var TestNode = global.SERVER.NodesMap[addrStr]; if (TestNode && TestNode !== Node) { if (GetSocketStatus(TestNode.Socket)) { global.AddNodeInfo(Node, "DoubleConnection find") Node.DoubleConnection = true return 0; } else { global.AddNodeInfo(Node, "DoubleConnection find") TestNode.DoubleConnection = true } } Node.PubKey = Buffer.from([Buf.PubKeyType].concat(Buf.addrArr)) Node.addrArr = Buf.addrArr Node.addrStr = addrStr if (global.CompareArr(global.SERVER.addrArr, Node.addrArr) === 0) { Node.Self = true return 0; } var Hash = global.shaarr2(Buf.addrArr, Buf.HashRND); var nonce = global.CreateNoncePOWExternMinPower(Hash, 0, Buf.MIN_POWER_POW_HANDSHAKE); var Info; if (global.WALLET.WalletOpen && global.IsDeveloperAccount(global.WALLET.PubKeyArr)) { Info = this.GetPOWClientData(0) Info.Reconnect = 255 Info.Sign = secp256k1.sign(global.SHA3BUF(Hash), global.WALLET.KeyPair.getPrivateKey('')).signature Result = global.CheckDevelopSign(Hash, Info.Sign) if (!Result) { throw "ERROR DEVELOPSIGN!"; } } else { Info = this.GetPOWClientData(nonce) Info.PubKeyType = global.SERVER.PubKeyType Info.Sign = secp256k1.sign(Buffer.from(Hash), global.SERVER.KeyPair.getPrivateKey('')).signature } var BufWrite = global.BufLib.GetBufferFromObject(Info, global.FORMAT_POW_TO_SERVER, 1200, {}); var BufAll = global.SERVER.GetBufFromData("POW_CONNECT6", BufWrite, 1); Socket.write(BufAll) return 1; } GetPOWClientData(nonce) { var Node = this; var Info: any = {}; Info.DEF_NETWORK = global.GetNetworkName() Info.DEF_VERSION = global.DEF_VERSION Info.DEF_CLIENT = global.DEF_CLIENT Info.addrArr = global.SERVER.addrArr Info.ToIP = Node.ip Info.ToPort = Node.port Info.FromIP = global.SERVER.ip Info.FromPort = global.SERVER.port Info.nonce = nonce Info.Reconnect = 0 Info.SendBytes = 0 Info.SecretForReconnect = [] Info.Reserv = [] if (global.GrayConnect()) Info.GrayConnect = 1 return Info; } write(BufWrite) { if (!this.Socket) return; global.socketWrite(this.Socket, BufWrite) try { this.Socket.write(BufWrite) } catch (e) { global.ToError(e) this.Socket.WasClose = 1 this.Socket.SocketStatus = 0 this.Socket.Node = undefined } } }; global.socketInit = function(Socket, Str) { if (!Socket) return; Socket.GetBytes = 0; Socket.SendBytes = 0; Socket.ConnectID = "" + ConnectIDCount + Str; ConnectIDCount++; }; global.socketRead = function(Socket, Buf) { Socket.GetBytes += Buf.length; }; global.socketWrite = function(Socket, Buf) { Socket.SendBytes += Buf.length; }; global.CloseSocket = function(Socket, StrError?, bHide?) { if (!Socket || Socket.WasClose) { if (Socket) Socket.SocketStatus = 0; return; } var Node = Socket.Node; if (Socket.Node && Socket.Node.Socket2 === Socket && Socket.Node.Socket && Socket.Node.Socket.SocketStatus === 200) SetSocketStatus(Socket.Node.Socket, 100); var StrNode = NodeInfo(Socket.Node); Socket.WasClose = 1; Socket.SocketStatus = 0; Socket.Node = undefined; Socket.end(); if (!bHide) global.AddNodeInfo(Node, "CLOSE " + StrNode + " *" + Socket.ConnectID + " - " + StrError); }; function SetSocketStatus(Socket, Status) { if (Socket && Socket.SocketStatus !== Status) { if (Status === 100 && (Socket.SocketStatus !== 3 && Socket.SocketStatus !== 200)) { global.ToLogTrace("===================ERROR=================== " + Status); return; } if (Status === 100 && Socket.Node) Socket.Node.LastTime = global.GetCurrentTime() - 0; Socket.SocketStatus = Status; Socket.TimeStatus = Date.now(); } }; function GetSocketStatus(Socket) { if (Socket && Socket.SocketStatus) { if (Socket.SocketStatus !== 100) { var Delta = Date.now() - Socket.TimeStatus; if (Delta > global.MAX_WAIT_PERIOD_FOR_STATUS) { global.CloseSocket(Socket, "MAX_WAIT_PERIOD_FOR_STATUS = " + Socket.SocketStatus + " time = " + Delta); } } return Socket.SocketStatus; } else { return 0; } }; function SocketInfo(Socket) { if (Socket) return "*" + Socket.ConnectID; else return ""; }; function SocketStatistic(Socket) { if (!Socket) return ""; var Str = ""; if (!Socket.SendBytes) Socket.SendBytes = 0; if (!Socket.GetBytes) Socket.GetBytes = 0; if (Socket.SendBytes) Str += " Send=" + Socket.SendBytes; if (Socket.GetBytes) Str += " Get=" + Socket.GetBytes; if (GetSocketStatus(Socket)) Str += " SocketStatus=" + GetSocketStatus(Socket); if (Str === "") Str = "0"; return Str; }; function NodeInfo(Node) { if (Node) return "" + Node.ip + ":" + Node.port + " " + SocketInfo(Node.Socket); else return ""; }; function NodeName(Node) { if (!Node) return ""; if (Node.Name) return Node.Name; if (global.LOCAL_RUN) return "" + Node.port; else { return "" + Node.ip + ":" + Node.addrStr.substr(0, 6); } }; function FindNodeByAddr(Addr, bConnect) { var Node = global.SERVER.NodesMap[Addr.trim()]; if (Node && Node.ConnectStatus() === 100) return Node; if (Node && bConnect) { Node.NextConnectDelta = 1000; global.SERVER.StartConnectTry(Node); return false; } return undefined; }; function AddNodeInfo(Node, Str, bSet) { if (!global.STAT_MODE) return; if (!Node) return; if (!Node.Info) Node.Info = ""; if (bSet) { Node.Info = ""; } else { if (Node.Socket && Node.Socket.Info) { Node.Info += Node.Socket.Info + "\n"; Node.Socket.Info = ""; } } if (Node.Info.length > 1000) { Node.PrevInfo = Node.Info; Node.Info = ""; } { var timesend = global.GetStrOnlyTimeUTC(); Str = timesend + " " + Str; Node.Info += Str + "\n"; } }; global.SocketStatistic = SocketStatistic; global.GetSocketStatus = GetSocketStatus; global.SetSocketStatus = SetSocketStatus; global.NodeInfo = NodeInfo; global.NodeName = NodeName; global.SocketInfo = SocketInfo; global.FindNodeByAddr = FindNodeByAddr; global.AddNodeInfo = AddNodeInfo;