|
@@ -3,6 +3,7 @@ package netstat
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
"errors"
|
|
|
+ "log"
|
|
|
"net/http"
|
|
|
"os"
|
|
|
"os/exec"
|
|
@@ -10,10 +11,115 @@ import (
|
|
|
"runtime"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
+ "time"
|
|
|
|
|
|
"imuslab.com/zoraxy/mod/utils"
|
|
|
)
|
|
|
|
|
|
+// Float stat store the change of RX and TX
|
|
|
+type FlowStat struct {
|
|
|
+ RX int64
|
|
|
+ TX int64
|
|
|
+}
|
|
|
+
|
|
|
+// A new type of FloatStat that save the raw value from rx tx
|
|
|
+type RawFlowStat struct {
|
|
|
+ RX int64
|
|
|
+ TX int64
|
|
|
+}
|
|
|
+
|
|
|
+type NetStatBuffers struct {
|
|
|
+ StatRecordCount int //No. of record number to keep
|
|
|
+ PreviousStat *RawFlowStat //The value of the last instance of netstats
|
|
|
+ Stats []*FlowStat //Statistic of the flow
|
|
|
+ StopChan chan bool //Channel to stop the ticker
|
|
|
+}
|
|
|
+
|
|
|
+// Get a new network statistic buffers
|
|
|
+func NewNetStatBuffer(recordCount int) (*NetStatBuffers, error) {
|
|
|
+ //Get the initial measurements of netstats
|
|
|
+ rx, tx, err := GetNetworkInterfaceStats()
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ currnetNetSpec := RawFlowStat{
|
|
|
+ RX: rx,
|
|
|
+ TX: tx,
|
|
|
+ }
|
|
|
+
|
|
|
+ //Flood fill the stats with 0
|
|
|
+ initialStats := []*FlowStat{}
|
|
|
+ for i := 0; i < recordCount; i++ {
|
|
|
+ initialStats = append(initialStats, &FlowStat{
|
|
|
+ RX: 0,
|
|
|
+ TX: 0,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ //Setup a timer to get the value from NIC accumulation stats
|
|
|
+ ticker := time.NewTicker(time.Second)
|
|
|
+ defer ticker.Stop()
|
|
|
+
|
|
|
+ //Setup a stop channel
|
|
|
+ stopCh := make(chan bool)
|
|
|
+
|
|
|
+ thisNetBuffer := NetStatBuffers{
|
|
|
+ StatRecordCount: recordCount,
|
|
|
+ PreviousStat: &currnetNetSpec,
|
|
|
+ Stats: initialStats,
|
|
|
+ StopChan: stopCh,
|
|
|
+ }
|
|
|
+
|
|
|
+ // Update the buffer every second
|
|
|
+ go func(n *NetStatBuffers) {
|
|
|
+ for {
|
|
|
+ select {
|
|
|
+ case <-stopCh:
|
|
|
+ return
|
|
|
+
|
|
|
+ case <-ticker.C:
|
|
|
+ // Get the latest network interface stats
|
|
|
+ rx, tx, err := GetNetworkInterfaceStats()
|
|
|
+ if err != nil {
|
|
|
+ // Log the error, but don't stop the buffer
|
|
|
+ log.Printf("Failed to get network interface stats: %v", err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ //Calculate the difference between this and last values
|
|
|
+ drx := rx - n.PreviousStat.RX
|
|
|
+ dtx := tx - n.PreviousStat.TX
|
|
|
+
|
|
|
+ // Push the new stats to the buffer
|
|
|
+ newStat := &FlowStat{
|
|
|
+ RX: drx,
|
|
|
+ TX: dtx,
|
|
|
+ }
|
|
|
+
|
|
|
+ //Set current rx tx as the previous rxtx
|
|
|
+ n.PreviousStat = &RawFlowStat{
|
|
|
+ RX: rx,
|
|
|
+ TX: tx,
|
|
|
+ }
|
|
|
+
|
|
|
+ copy(initialStats, initialStats[1:])
|
|
|
+ initialStats = append(initialStats, newStat)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }(&thisNetBuffer)
|
|
|
+
|
|
|
+ return &thisNetBuffer, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (n *NetStatBuffers) HandleGetBufferedNetworkInterfaceStats(w http.ResponseWriter, r *http.Request) {
|
|
|
+ js, _ := json.Marshal(n.Stats)
|
|
|
+ utils.SendJSONResponse(w, string(js))
|
|
|
+}
|
|
|
+
|
|
|
+func (n *NetStatBuffers) Close() {
|
|
|
+ n.StopChan <- true
|
|
|
+}
|
|
|
+
|
|
|
func HandleGetNetworkInterfaceStats(w http.ResponseWriter, r *http.Request) {
|
|
|
rx, tx, err := GetNetworkInterfaceStats()
|
|
|
if err != nil {
|