func NetworkTick() { if common.IsListenTCP() { if !TCPServerStarted { TCPServerStarted = true go tcp_server() } } Mutex_net.Lock() conn_cnt := OutConsActive Mutex_net.Unlock() if next_drop_slowest.IsZero() { next_drop_slowest = time.Now().Add(DropSlowestEvery) } else if conn_cnt >= atomic.LoadUint32(&common.CFG.Net.MaxOutCons) { // Having max number of outgoing connections, check to drop the slowest one if time.Now().After(next_drop_slowest) { drop_slowest_peer() next_drop_slowest = time.Now().Add(DropSlowestEvery) } } // hammering protection - expire recently disconnected if next_clean_hammers.IsZero() { next_clean_hammers = time.Now().Add(HammeringMinReconnect) } else if time.Now().After(next_clean_hammers) { HammeringMutex.Lock() for k, t := range RecentlyDisconencted { if time.Now().Sub(t) >= HammeringMinReconnect { delete(RecentlyDisconencted, k) } } HammeringMutex.Unlock() ExpireCachedBlocks() next_clean_hammers = time.Now().Add(HammeringMinReconnect) } for conn_cnt < atomic.LoadUint32(&common.CFG.Net.MaxOutCons) { adrs := peersdb.GetBestPeers(16, ConnectionActive) if len(adrs) == 0 { common.LockCfg() if common.CFG.ConnectOnly == "" && common.DebugLevel > 0 { println("no new peers", len(OpenCons), conn_cnt) } common.UnlockCfg() break } DoNetwork(adrs[rand.Int31n(int32(len(adrs)))]) Mutex_net.Lock() conn_cnt = OutConsActive Mutex_net.Unlock() } }
// Process that handles communication with a single peer func (c *OneConnection) Run() { c.SendVersion() c.Mutex.Lock() c.LastDataGot = time.Now() c.NextBlocksAsk = time.Now() // ask for blocks ASAP c.NextGetAddr = time.Now() // do getaddr ~10 seconds from now c.NextPing = time.Now().Add(5 * time.Second) // do first ping ~5 seconds from now c.Mutex.Unlock() for !c.IsBroken() { c.Mutex.Lock() c.LoopCnt++ c.Mutex.Unlock() cmd := c.FetchMessage() if c.IsBroken() { break } // Timeout ping in progress if c.PingInProgress != nil && time.Now().After(c.LastPingSent.Add(PingTimeout)) { if common.DebugLevel > 0 { println(c.PeerAddr.Ip(), "ping timeout") } common.CountSafe("PingTimeout") c.HandlePong() // this will set LastPingSent to nil } if cmd == nil { c.Tick() continue } c.Mutex.Lock() c.LastDataGot = time.Now() c.LastCmdRcvd = cmd.cmd c.LastBtsRcvd = uint32(len(cmd.pl)) c.Mutex.Unlock() c.PeerAddr.Alive() if common.DebugLevel < 0 { fmt.Println(c.PeerAddr.Ip(), "->", cmd.cmd, len(cmd.pl)) } if c.Send.Buf != nil && len(c.Send.Buf) > SendBufSizeHoldOn { common.CountSafe("hold_" + cmd.cmd) common.CountSafeAdd("hbts_"+cmd.cmd, uint64(len(cmd.pl))) continue } common.CountSafe("rcvd_" + cmd.cmd) common.CountSafeAdd("rbts_"+cmd.cmd, uint64(len(cmd.pl))) switch cmd.cmd { case "version": er := c.HandleVersion(cmd.pl) if er != nil { println("version:", er.Error()) c.Disconnect() } case "verack": c.VerackReceived = true if common.IsListenTCP() { c.SendOwnAddr() } case "inv": c.ProcessInv(cmd.pl) case "tx": if common.CFG.TXPool.Enabled { c.ParseTxNet(cmd.pl) } case "addr": ParseAddr(cmd.pl) case "block": //block received netBlockReceived(c, cmd.pl) case "getblocks": c.GetBlocks(cmd.pl) case "getdata": c.ProcessGetData(cmd.pl) case "getaddr": c.SendAddr() case "alert": c.HandleAlert(cmd.pl) case "ping": re := make([]byte, len(cmd.pl)) copy(re, cmd.pl) c.SendRawMsg("pong", re) case "pong": if c.PingInProgress == nil { common.CountSafe("PongUnexpected") } else if bytes.Equal(cmd.pl, c.PingInProgress) { c.HandlePong() } else { common.CountSafe("PongMismatch") } case "getheaders": c.GetHeaders(cmd.pl) case "notfound": common.CountSafe("NotFound") default: if common.DebugLevel > 0 { println(cmd.cmd, "from", c.PeerAddr.Ip()) } } } c.Mutex.Lock() ban := c.banit c.Mutex.Unlock() if ban { c.PeerAddr.Ban() common.CountSafe("PeersBanned") } else if c.Incoming { HammeringMutex.Lock() RecentlyDisconencted[c.PeerAddr.NetAddr.Ip4] = time.Now() HammeringMutex.Unlock() } if common.DebugLevel > 0 { println("Disconnected from", c.PeerAddr.Ip()) } c.NetConn.Close() }
func p_cfg(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } common.LockCfg() defer common.UnlockCfg() if r.Method == "POST" { if len(r.Form["configjson"]) > 0 { e := json.Unmarshal([]byte(r.Form["configjson"][0]), &common.CFG) if e == nil { common.Reset() } if len(r.Form["save"]) > 0 { common.SaveConfig() } http.Redirect(w, r, "/", http.StatusFound) return } if len(r.Form["walletdata"]) > 0 && len(r.Form["walletfname"]) > 0 { fn := r.Form["walletfname"][0] if fn != "" { fn = common.GocoinHomeDir + "wallet" + string(os.PathSeparator) + fn ioutil.WriteFile(fn, []byte(r.Form["walletdata"][0]), 0660) wallet.LoadWallet(fn) } http.Redirect(w, r, "/wal", http.StatusFound) return } if len(r.Form["shutdown"]) > 0 { usif.Exit_now = true w.Write([]byte("Your node should shut down soon")) return } return } // for any other GET we need a matching session-id if !checksid(r) { new_session_id(w) return } if len(r.Form["txponoff"]) > 0 { common.CFG.TXPool.Enabled = !common.CFG.TXPool.Enabled http.Redirect(w, r, "txs", http.StatusFound) return } if len(r.Form["txronoff"]) > 0 { common.CFG.TXRoute.Enabled = !common.CFG.TXRoute.Enabled http.Redirect(w, r, "txs", http.StatusFound) return } if len(r.Form["lonoff"]) > 0 { common.SetListenTCP(common.IsListenTCP(), true) http.Redirect(w, r, "net", http.StatusFound) return } if len(r.Form["drop"]) > 0 { network.DropPeer(r.Form["drop"][0]) http.Redirect(w, r, "net", http.StatusFound) return } if len(r.Form["savecfg"]) > 0 { dat, _ := json.Marshal(&common.CFG) if dat != nil { ioutil.WriteFile(common.ConfigFile, dat, 0660) } http.Redirect(w, r, "/", http.StatusFound) return } if len(r.Form["beepblock"]) > 0 { common.CFG.Beeps.NewBlock = !common.CFG.Beeps.NewBlock http.Redirect(w, r, "/", http.StatusFound) return } if len(r.Form["freemem"]) > 0 { sys.FreeMem() http.Redirect(w, r, "/", http.StatusFound) return } if len(r.Form["mid"]) > 0 { v, e := strconv.ParseUint(r.Form["mid"][0], 10, 32) if e == nil && v < uint64(len(common.MinerIds)) { common.CFG.Beeps.MinerID = string(common.MinerIds[v].Tag) } else { common.CFG.Beeps.MinerID = "" } http.Redirect(w, r, "miners", http.StatusFound) return } }
// TCP server func tcp_server() { ad, e := net.ResolveTCPAddr("tcp4", fmt.Sprint("0.0.0.0:", common.DefaultTcpPort)) if e != nil { println("ResolveTCPAddr", e.Error()) return } lis, e := net.ListenTCP("tcp4", ad) if e != nil { println("ListenTCP", e.Error()) return } defer lis.Close() //fmt.Println("TCP server started at", ad.String()) for common.IsListenTCP() { common.CountSafe("NetServerLoops") Mutex_net.Lock() ica := InConsActive Mutex_net.Unlock() if ica < atomic.LoadUint32(&common.CFG.Net.MaxInCons) { lis.SetDeadline(time.Now().Add(time.Second)) tc, e := lis.AcceptTCP() if e == nil { var terminate bool if common.DebugLevel > 0 { fmt.Println("Incoming connection from", tc.RemoteAddr().String()) } ad, e := peersdb.NewPeerFromString(tc.RemoteAddr().String()) if e == nil { // Hammering protection HammeringMutex.Lock() ti, ok := RecentlyDisconencted[ad.NetAddr.Ip4] HammeringMutex.Unlock() if ok && time.Now().Sub(ti) < HammeringMinReconnect { //println(ad.Ip(), "is hammering within", time.Now().Sub(ti).String()) common.CountSafe("InConnHammer") ad.Ban() terminate = true } if !terminate { // Incoming IP passed all the initial checks - talk to it conn := NewConnection(ad) conn.ConnectedAt = time.Now() conn.Incoming = true conn.NetConn = tc Mutex_net.Lock() if _, ok := OpenCons[ad.UniqID()]; ok { //fmt.Println(ad.Ip(), "already connected") common.CountSafe("SameIpReconnect") Mutex_net.Unlock() terminate = true } else { OpenCons[ad.UniqID()] = conn InConsActive++ Mutex_net.Unlock() go func() { conn.Run() Mutex_net.Lock() delete(OpenCons, ad.UniqID()) InConsActive-- Mutex_net.Unlock() }() } } } else { if common.DebugLevel > 0 { println("NewPeerFromString:", e.Error()) } common.CountSafe("InConnRefused") terminate = true } // had any error occured - close teh TCP connection if terminate { tc.Close() } } } else { time.Sleep(1e9) } } Mutex_net.Lock() for _, c := range OpenCons { if c.Incoming { c.Disconnect() } } TCPServerStarted = false Mutex_net.Unlock() //fmt.Println("TCP server stopped") }
func p_net(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } net_page := load_template("net.html") net_row := load_template("net_row.html") network.Mutex_net.Lock() srt := make(network.SortedKeys, len(network.OpenCons)) cnt := 0 for k, v := range network.OpenCons { if !v.IsBroken() { srt[cnt].Key = k srt[cnt].ConnID = v.ConnID cnt++ } } sort.Sort(srt) net_page = strings.Replace(net_page, "{OUT_CONNECTIONS}", fmt.Sprint(network.OutConsActive), 1) net_page = strings.Replace(net_page, "{IN_CONNECTIONS}", fmt.Sprint(network.InConsActive), 1) net_page = strings.Replace(net_page, "{LISTEN_TCP}", fmt.Sprint(common.IsListenTCP(), network.TCPServerStarted), 1) net_page = strings.Replace(net_page, "{EXTERNAL_ADDR}", btc.NewNetAddr(network.BestExternalAddr()).String(), 1) for idx := range srt { v := network.OpenCons[srt[idx].Key] s := net_row v.Mutex.Lock() s = strings.Replace(s, "{CONNID}", fmt.Sprint(v.ConnID), -1) if v.Incoming { s = strings.Replace(s, "{CONN_DIR_ICON}", "<img src=\"webui/incoming.png\">", 1) } else { s = strings.Replace(s, "{CONN_DIR_ICON}", "<img src=\"webui/outgoing.png\">", 1) } s = strings.Replace(s, "{PEER_ADDR}", v.PeerAddr.Ip(), 1) s = strings.Replace(s, "{PERR_PING}", fmt.Sprint(v.GetAveragePing()), 1) s = strings.Replace(s, "{LAST_RCVD_LEN}", fmt.Sprint(v.LastBtsRcvd), 1) s = strings.Replace(s, "{LAST_RCVD_CMD}", v.LastCmdRcvd, 1) s = strings.Replace(s, "{LAST_SENT_LEN}", fmt.Sprint(v.LastBtsSent), 1) s = strings.Replace(s, "{LAST_SENT_CNT}", v.LastCmdSent, 1) s = strings.Replace(s, "{TOTAL_RCVD}", common.BytesToString(v.BytesReceived), 1) s = strings.Replace(s, "{TOTAL_SENT}", common.BytesToString(v.BytesSent), 1) s = strings.Replace(s, "{NODE_VERSION}", fmt.Sprint(v.Node.Version), 1) s = strings.Replace(s, "{USER_AGENT}", v.Node.Agent, 1) if v.Send.Buf != nil { s = strings.Replace(s, "<!--SENDBUF-->", common.BytesToString(uint64(len(v.Send.Buf))), 1) } if len(v.GetBlockInProgress) > 0 { s = strings.Replace(s, "<!--BLKSINPROG-->", fmt.Sprint(len(v.GetBlockInProgress), "blks "), 1) } v.Mutex.Unlock() net_page = templ_add(net_page, "<!--PEER_ROW-->", s) } network.Mutex_net.Unlock() write_html_head(w, r) w.Write([]byte(net_page)) write_html_tail(w) }