Beispiel #1
0
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()
	}
}
Beispiel #2
0
func p_net(w http.ResponseWriter, r *http.Request) {
	if !ipchecker(r) {
		return
	}

	net_page := load_template("net.html")

	network.Mutex_net.Lock()
	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)

	network.Mutex_net.Unlock()

	write_html_head(w, r)
	w.Write([]byte(net_page))
	write_html_tail(w)
}
Beispiel #3
0
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)
}
Beispiel #4
0
// Process that handles communication with a single peer
func (c *OneConnection) Run() {
	c.SendVersion()

	c.Mutex.Lock()
	now := time.Now()
	c.X.LastDataGot = now
	c.nextMaintanence = now.Add(time.Minute)
	c.LastPingSent = now.Add(5*time.Second - common.PingPeerEvery) // do first ping ~5 seconds from now
	c.Mutex.Unlock()

	for !c.IsBroken() {
		if c.IsBroken() {
			break
		}

		if c.SendPendingData() {
			continue // Do now read the socket if we have pending data to send
		}

		cmd := c.FetchMessage()

		if cmd == nil {
			c.Tick()
			continue
		}

		if c.X.VerackReceived {
			c.PeerAddr.Alive()
		}
		c.Mutex.Lock()
		c.counters["rcvd_"+cmd.cmd]++
		c.counters["rbts_"+cmd.cmd] += uint64(len(cmd.pl))
		c.X.LastDataGot = time.Now()
		c.X.LastCmdRcvd = cmd.cmd
		c.X.LastBtsRcvd = uint32(len(cmd.pl))
		c.Mutex.Unlock()

		if common.DebugLevel < 0 {
			fmt.Println(c.PeerAddr.Ip(), "->", cmd.cmd, len(cmd.pl))
		}

		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 msg error:", er.Error())
				c.Disconnect()
				break
			}
			if c.Node.DoNotRelayTxs {
				c.DoS("SPV")
				break
			}
			if c.Node.Version >= 70012 {
				c.SendRawMsg("sendheaders", nil)
				if c.Node.Version >= 70013 {
					if common.CFG.TXPool.FeePerByte != 0 {
						var pl [8]byte
						binary.LittleEndian.PutUint64(pl[:], 1000*common.CFG.TXPool.FeePerByte)
						c.SendRawMsg("feefilter", pl[:])
					}
					if c.Node.Version >= 70014 {
						if (c.Node.Services & SERVICE_SEGWIT) == 0 {
							// if the node does not support segwit, request compact blocks
							// only if we have not achieved he segwit enforcement moment
							if common.BlockChain.Consensus.Enforce_SEGWIT == 0 ||
								common.Last.BlockHeight() < common.BlockChain.Consensus.Enforce_SEGWIT {
								c.SendRawMsg("sendcmpct", []byte{0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
							}
						} else {
							c.SendRawMsg("sendcmpct", []byte{0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
						}
					}
				}
			}

		case "verack":
			c.X.VerackReceived = true
			c.PeerAddr.Services = c.Node.Services
			c.PeerAddr.Save()
			if common.IsListenTCP() {
				c.SendOwnAddr()
			}

		case "inv":
			c.ProcessInv(cmd.pl)

		case "tx":
			if common.CFG.TXPool.Enabled {
				c.ParseTxNet(cmd.pl)
			}

		case "addr":
			c.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":
			if !c.X.GetAddrDone {
				c.SendAddr()
				c.X.GetAddrDone = true
			} else {
				c.Mutex.Lock()
				c.counters["SecondGetAddr"]++
				c.Mutex.Unlock()
				if c.Misbehave("SecondGetAddr", 1000/20) {
					break
				}
			}

		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")

		case "headers":
			if c.HandleHeaders(cmd.pl) > 0 {
				c.sendGetHeaders()
			}

		case "sendheaders":
			c.Node.SendHeaders = true

		case "feefilter":
			if len(cmd.pl) >= 8 {
				c.X.MinFeeSPKB = int64(binary.LittleEndian.Uint64(cmd.pl[:8]))
				//println(c.PeerAddr.Ip(), c.Node.Agent, "feefilter", c.X.MinFeeSPKB)
			}

		case "sendcmpct":
			if len(cmd.pl) >= 9 {
				version := binary.LittleEndian.Uint64(cmd.pl[1:9])
				if version > c.Node.SendCmpctVer {
					//println(c.ConnID, "sendcmpct", cmd.pl[0])
					c.Node.SendCmpctVer = version
					c.Node.HighBandwidth = cmd.pl[0] == 1
				} else {
					c.Mutex.Lock()
					c.counters[fmt.Sprint("SendCmpctV", version)]++
					c.Mutex.Unlock()
				}
			} else {
				println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "sendcmpct", hex.EncodeToString(cmd.pl))
			}

		case "cmpctblock":
			c.ProcessCmpctBlock(cmd.pl)

		case "getblocktxn":
			c.ProcessGetBlockTxn(cmd.pl)
			//println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "getblocktxn", hex.EncodeToString(cmd.pl))

		case "blocktxn":
			c.ProcessBlockTxn(cmd.pl)
			//println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn", hex.EncodeToString(cmd.pl))

		default:
			if common.DebugLevel > 0 {
				println(cmd.cmd, "from", c.PeerAddr.Ip())
			}
		}
	}

	c.Mutex.Lock()
	MutexRcv.Lock()
	for k, _ := range c.GetBlockInProgress {
		if rec, ok := BlocksToGet[k]; ok {
			rec.InProgress--
		} else {
			//println("ERROR! Block", bip.hash.String(), "in progress, but not in BlocksToGet")
		}
	}
	MutexRcv.Unlock()

	ban := c.banit
	c.Mutex.Unlock()
	if ban {
		c.PeerAddr.Ban()
		common.CountSafe("PeersBanned")
	} else if c.X.Incomming {
		HammeringMutex.Lock()
		RecentlyDisconencted[c.PeerAddr.NetAddr.Ip4] = time.Now()
		HammeringMutex.Unlock()
	}
	if common.DebugLevel != 0 {
		println("Disconnected from", c.PeerAddr.Ip())
	}
	c.Conn.Close()
}
Beispiel #5
0
func NetworkTick() {
	if common.IsListenTCP() {
		if !TCPServerStarted {
			TCPServerStarted = true
			go tcp_server()
		}
	}

	// Push GetHeaders if not in progress
	Mutex_net.Lock()
	var cnt_headers_in_progress int
	var max_headers_got_cnt int
	var _v *OneConnection
	for _, v := range OpenCons {
		v.Mutex.Lock()
		if !v.X.AllHeadersReceived || v.X.GetHeadersInProgress {
			cnt_headers_in_progress++
		} else if !v.X.LastHeadersEmpty {
			if _v == nil || v.X.TotalNewHeadersCount > max_headers_got_cnt {
				max_headers_got_cnt = v.X.TotalNewHeadersCount
				_v = v
			}
		}
		v.Mutex.Unlock()
	}
	conn_cnt := OutConsActive
	Mutex_net.Unlock()

	if cnt_headers_in_progress == 0 {
		if _v != nil {
			common.CountSafe("GetHeadersPush")
			/*println("No headers_in_progress, so take it from", _v.ConnID,
			_v.X.TotalNewHeadersCount, _v.X.LastHeadersEmpty)*/
			_v.Mutex.Lock()
			_v.X.AllHeadersReceived = false
			_v.Mutex.Unlock()
		} else {
			common.CountSafe("GetHeadersNone")
		}
	}

	if common.CFG.DropPeers.DropEachMinutes != 0 {
		if next_drop_peer.IsZero() {
			next_drop_peer = time.Now().Add(common.DropSlowestEvery)
		} else if time.Now().After(next_drop_peer) {
			drop_worst_peer()
			next_drop_peer = time.Now().Add(common.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()
		next_clean_hammers = time.Now().Add(HammeringMinReconnect)
	}

	for conn_cnt < atomic.LoadUint32(&common.CFG.Net.MaxOutCons) {
		var segwit_conns uint32
		if common.CFG.Net.MinSegwitCons > 0 {
			Mutex_net.Lock()
			for _, cc := range OpenCons {
				if (cc.Node.Services & SERVICE_SEGWIT) != 0 {
					segwit_conns++
				}
			}
			Mutex_net.Unlock()
		}

		adrs := peersdb.GetBestPeers(128, func(ad *peersdb.PeerAddr) bool {
			if segwit_conns < common.CFG.Net.MinSegwitCons && (ad.Services&SERVICE_SEGWIT) == 0 {
				return true
			}
			return ConnectionActive(ad)
		})
		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()
	}
}
Beispiel #6
0
// 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())
				}
				// set port to default, for incomming connections
				ad, e := peersdb.NewPeerFromString(tc.RemoteAddr().String(), true)
				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("BanHammerIn")
						ad.Ban()
						terminate = true
					}

					if !terminate {
						// Incoming IP passed all the initial checks - talk to it
						conn := NewConnection(ad)
						conn.X.ConnectedAt = time.Now()
						conn.X.Incomming = true
						conn.Conn = 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.X.Incomming {
			c.Disconnect()
		}
	}
	TCPServerStarted = false
	Mutex_net.Unlock()
	//fmt.Println("TCP server stopped")
}
Beispiel #7
0
// 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":
			c.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()
}
Beispiel #8
0
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.CFG.Walletdir + 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
	}

}