]> Cypherpunks.ru repositories - nncp.git/commitdiff
Simple rate limiter
authorSergey Matveev <stargrave@stargrave.org>
Sun, 10 Jun 2018 15:10:22 +0000 (18:10 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sun, 10 Jun 2018 15:32:39 +0000 (18:32 +0300)
doc/call.texi
doc/cfg.texi
doc/cmds.texi
doc/news.ru.texi
doc/news.texi
src/cypherpunks.ru/nncp/call.go
src/cypherpunks.ru/nncp/cfg.go
src/cypherpunks.ru/nncp/cmd/nncp-call/main.go
src/cypherpunks.ru/nncp/cmd/nncp-caller/main.go
src/cypherpunks.ru/nncp/node.go
src/cypherpunks.ru/nncp/sp.go

index 31d8f82ab6aab13cc815904e989f97813a5d0096..63e4c7981524ff54106c7e754e1cb2945c70a12a 100644 (file)
@@ -16,6 +16,8 @@ calls:
     onlinedeadline: 1800
     maxonlinetime: 1750
     nice: 64
+    rxrate: 10
+    txrate: 20
   -
     cron: "0 * * * SAT,SUN"
     xx: rx
@@ -167,6 +169,10 @@ Optional. Call only that address, instead of trying all from
 @ref{CfgAddrs, @emph{addrs}} configuration option. It can be either key
 from @emph{addrs} dictionary, or an ordinary @option{addr:port}.
 
+@item rxrate/txrate
+Optional. Override @ref{CfgXxRate, @emph{rxrate/txrate}} configuration
+option when calling.
+
 @item onlinedeadline
 Optional. Override @ref{CfgOnlineDeadline, @emph{onlinedeadline}}
 configuration option when calling.
index 5be0382bd69628ff5980d37b1abe971d548a36db..410bee884e2ef7305ccbff340a3846ab09f43471 100644 (file)
@@ -57,6 +57,8 @@ neigh:
     freqchunked: 1024
     freqminsize: 2048
     via: [alice]
+    rxrate: 10
+    txrate: 20
 @end verbatim
 
 @strong{spool} field contains an absolute path to @ref{Spool, spool}
@@ -143,6 +145,13 @@ pairs pointing to @ref{nncp-daemon}'s listening instance. May be omitted
 if either no direct connection exists, or @ref{nncp-call} is used with
 forced address specifying.
 
+@anchor{CfgXxRate}
+@item rxrate/txrate
+If greater than zero, then at most *rate packets per second will be
+sent/received after the handshake. It could be used as crude bandwidth
+traffic shaper: each packet has at most 64 KiB payload size. Could be
+omitted at all -- no rate limits.
+
 @anchor{CfgOnlineDeadline}
 @item onlinedeadline
 Online connection deadline of node inactivity in seconds. It is the time
index 33ad949dbbd86a49a7997bfe741d65568551a6b2..49a4f1d8e2bef53814fa878da089eba76d397614 100644 (file)
@@ -95,8 +95,13 @@ their integrity.
 @section nncp-call
 
 @verbatim
-% nncp-call [options] [-onlinedeadline INT] [-maxonlinetime INT] [-rx|-tx]
-                      NODE[:ADDR] [FORCEADDR]
+% nncp-call [options]
+    [-onlinedeadline INT]
+    [-maxonlinetime INT]
+    [-rx|-tx]
+    [-rxrate INT]
+    [-txrate INT]
+    NODE[:ADDR] [FORCEADDR]
 @end verbatim
 
 Call (connect to) specified @option{NODE} and run @ref{Sync,
@@ -111,7 +116,8 @@ transmission is performed. If @option{-tx} option is specified, then
 only outbound transmission is performed. @option{-onlinedeadline}
 overrides @ref{CfgOnlineDeadline, @emph{onlinedeadline}}.
 @option{-maxonlinetime} overrides @ref{CfgMaxOnlineTime,
-@emph{maxonlinetime}}.
+@emph{maxonlinetime}}. @option{-rxrate}/@option{-txrate} override
+@ref{CfgXxRate, rxrate/txrate}.
 
 @node nncp-caller
 @section nncp-caller
index dd20336f65c32e120142c8b0d2ddc1836047ae28..4d0451b9db39b28b1f9a3056fa55f2830e19c767 100644 (file)
 Если более высокоприоритетный пакет попадает в спул, то
 @command{nncp-daemon} добавит его в очередь отправки первым, прерывая
 низкоприоритетные передачи.
+@item
+К средствам связанным с online-соединениями (@command{nncp-daemon},
+@command{nncp-call}, @command{nncp-caller}) добавлен простой
+ограничитель скорости.
 @end itemize
 
 @node Релиз 3.2
index d69e02e03b52388c8db084a0a14c5e1feeba49a4..974dae918ac25f32bf1d546f6504f3ec4711314d 100644 (file)
@@ -14,6 +14,9 @@ notifier about that.
 @item
 If higher priority packet is spooled, then @command{nncp-daemon} will
 queue its sending first, interrupting lower priority transmissions.
+@item
+Simple packet rate limiter added to online-related tools
+(@command{nncp-daemon}, @command{nncp-call}, @command{nncp-caller}).
 @end itemize
 
 @node Release 3.2
index ab120ad890c69e824db3a66ce8bfcdc3d258db1b..fbdd05b014d2244061ebdab9af65d27f8b26414a 100644 (file)
@@ -21,9 +21,22 @@ package nncp
 import (
        "net"
        "strconv"
+
+       "github.com/gorhill/cronexpr"
 )
 
-func (ctx *Ctx) CallNode(node *Node, addrs []string, nice uint8, xxOnly TRxTx, onlineDeadline, maxOnlineTime uint) (isGood bool) {
+type Call struct {
+       Cron           *cronexpr.Expression
+       Nice           uint8
+       Xx             TRxTx
+       RxRate         int
+       TxRate         int
+       Addr           *string
+       OnlineDeadline uint
+       MaxOnlineTime  uint
+}
+
+func (ctx *Ctx) CallNode(node *Node, addrs []string, nice uint8, xxOnly TRxTx, rxRate, txRate int, onlineDeadline, maxOnlineTime uint) (isGood bool) {
        for _, addr := range addrs {
                sds := SDS{"node": node.Id, "addr": addr}
                ctx.LogD("call", sds, "dialing")
@@ -38,6 +51,8 @@ func (ctx *Ctx) CallNode(node *Node, addrs []string, nice uint8, xxOnly TRxTx, o
                        node.Id,
                        nice,
                        xxOnly,
+                       rxRate,
+                       txRate,
                        onlineDeadline,
                        maxOnlineTime,
                )
index 5d5d66f7e700c36ae35831abee277a9a3899f17f..381f7dec5abd0b6591565293720c4ea98a9cfa8d 100644 (file)
@@ -59,6 +59,8 @@ type NodeYAML struct {
 
        Addrs map[string]string `yaml:"addrs,omitempty"`
 
+       RxRate         *int  `yaml:"rxrate,omitempty"`
+       TxRate         *int  `yaml:"txrate,omitempty"`
        OnlineDeadline *uint `yaml:"onlinedeadline,omitempty"`
        MaxOnlineTime  *uint `yaml:"maxonlinetime,omitempty"`
 }
@@ -67,6 +69,8 @@ type CallYAML struct {
        Cron           string
        Nice           *int    `yaml:"nice,omitempty"`
        Xx             string  `yaml:"xx,omitempty"`
+       RxRate         *int    `yaml:"rxrate,omitempty"`
+       TxRate         *int    `yaml:"txrate,omitempty"`
        Addr           *string `yaml:"addr,omitempty"`
        OnlineDeadline *uint   `yaml:"onlinedeadline,omitempty"`
        MaxOnlineTime  *uint   `yaml:"maxonlinetime,omitempty"`
@@ -163,6 +167,15 @@ func NewNode(name string, yml NodeYAML) (*Node, error) {
                freqMinSize = int64(*yml.FreqMinSize) * 1024
        }
 
+       defRxRate := 0
+       if yml.RxRate != nil && *yml.RxRate > 0 {
+               defRxRate = *yml.RxRate
+       }
+       defTxRate := 0
+       if yml.TxRate != nil && *yml.TxRate > 0 {
+               defTxRate = *yml.TxRate
+       }
+
        defOnlineDeadline := uint(DefaultDeadline)
        if yml.OnlineDeadline != nil {
                if *yml.OnlineDeadline <= 0 {
@@ -181,6 +194,7 @@ func NewNode(name string, yml NodeYAML) (*Node, error) {
                if err != nil {
                        return nil, err
                }
+
                nice := uint8(255)
                if callYml.Nice != nil {
                        if *callYml.Nice < 1 || *callYml.Nice > 255 {
@@ -188,6 +202,7 @@ func NewNode(name string, yml NodeYAML) (*Node, error) {
                        }
                        nice = uint8(*callYml.Nice)
                }
+
                var xx TRxTx
                switch callYml.Xx {
                case "rx":
@@ -198,6 +213,16 @@ func NewNode(name string, yml NodeYAML) (*Node, error) {
                default:
                        return nil, errors.New("xx field must be either \"rx\" or \"tx\"")
                }
+
+               rxRate := 0
+               if callYml.RxRate != nil && *callYml.RxRate > 0 {
+                       rxRate = *callYml.RxRate
+               }
+               txRate := 0
+               if callYml.TxRate != nil && *callYml.TxRate > 0 {
+                       txRate = *callYml.TxRate
+               }
+
                var addr *string
                if callYml.Addr != nil {
                        if a, exists := yml.Addrs[*callYml.Addr]; exists {
@@ -206,6 +231,7 @@ func NewNode(name string, yml NodeYAML) (*Node, error) {
                                addr = callYml.Addr
                        }
                }
+
                onlineDeadline := defOnlineDeadline
                if callYml.OnlineDeadline != nil {
                        if *callYml.OnlineDeadline == 0 {
@@ -213,14 +239,18 @@ func NewNode(name string, yml NodeYAML) (*Node, error) {
                        }
                        onlineDeadline = *callYml.OnlineDeadline
                }
+
                var maxOnlineTime uint
                if callYml.MaxOnlineTime != nil {
                        maxOnlineTime = *callYml.MaxOnlineTime
                }
+
                calls = append(calls, &Call{
                        Cron:           expr,
                        Nice:           nice,
                        Xx:             xx,
+                       RxRate:         rxRate,
+                       TxRate:         txRate,
                        Addr:           addr,
                        OnlineDeadline: onlineDeadline,
                        MaxOnlineTime:  maxOnlineTime,
@@ -239,6 +269,8 @@ func NewNode(name string, yml NodeYAML) (*Node, error) {
                FreqMinSize:    freqMinSize,
                Calls:          calls,
                Addrs:          yml.Addrs,
+               RxRate:         defRxRate,
+               TxRate:         defTxRate,
                OnlineDeadline: defOnlineDeadline,
                MaxOnlineTime:  defMaxOnlineTime,
        }
index bbf9bfa2ff3671c63502cc117af56dc67377d0a3..d304aea2f636ba9578de3325783b33e6762d9845 100644 (file)
@@ -42,7 +42,9 @@ func main() {
                cfgPath   = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file")
                niceRaw   = flag.Int("nice", 255, "Minimal required niceness")
                rxOnly    = flag.Bool("rx", false, "Only receive packets")
-               txOnly    = flag.Bool("tx", false, "Only transfer packets")
+               txOnly    = flag.Bool("tx", false, "Only transmit packets")
+               rxRate    = flag.Int("rxrate", 0, "Maximal receive rate, pkts/sec")
+               txRate    = flag.Int("txrate", 0, "Maximal transmit rate, pkts/sec")
                spoolPath = flag.String("spool", "", "Override path to spool")
                logPath   = flag.String("log", "", "Override path to logfile")
                quiet     = flag.Bool("quiet", false, "Print only errors")
@@ -121,7 +123,16 @@ func main() {
                }
        }
 
-       if !ctx.CallNode(node, addrs, nice, xxOnly, *onlineDeadline, *maxOnlineTime) {
+       if !ctx.CallNode(
+               node,
+               addrs,
+               nice,
+               xxOnly,
+               *rxRate,
+               *txRate,
+               *onlineDeadline,
+               *maxOnlineTime,
+       ) {
                os.Exit(1)
        }
 }
index a975878cb4066635bd16aed4adb0e673ec61a71f..d9609420b2bb46a330b9c4e90016aa0ba88760e2 100644 (file)
@@ -128,6 +128,8 @@ func main() {
                                                        addrs,
                                                        call.Nice,
                                                        call.Xx,
+                                                       call.RxRate,
+                                                       call.TxRate,
                                                        call.OnlineDeadline,
                                                        call.MaxOnlineTime,
                                                )
index f1fb79ff5bdf8df4b7bca8f44bdc1eb08e3b4802..b6cdcc65f9b09f08d55530c71d8e4f0922c61f16 100644 (file)
@@ -24,7 +24,6 @@ import (
        "sync"
 
        "github.com/flynn/noise"
-       "github.com/gorhill/cronexpr"
        "golang.org/x/crypto/blake2b"
        "golang.org/x/crypto/ed25519"
        "golang.org/x/crypto/nacl/box"
@@ -49,6 +48,8 @@ type Node struct {
        FreqMinSize    int64
        Via            []*NodeId
        Addrs          map[string]string
+       RxRate         int
+       TxRate         int
        OnlineDeadline uint
        MaxOnlineTime  uint
        Calls          []*Call
@@ -67,15 +68,6 @@ type NodeOur struct {
        NoisePrv *[32]byte
 }
 
-type Call struct {
-       Cron           *cronexpr.Expression
-       Nice           uint8
-       Xx             TRxTx
-       Addr           *string
-       OnlineDeadline uint
-       MaxOnlineTime  uint
-}
-
 func NewNodeGenerate() (*NodeOur, error) {
        exchPub, exchPrv, err := box.GenerateKey(rand.Reader)
        if err != nil {
index 86cd96c833f6db6b7b0ab2dad707d8faddeecde4..5904b0438f6cbb9e4aa7794da35f8ddb32c37174 100644 (file)
@@ -188,6 +188,8 @@ type SPState struct {
        rxLock         *os.File
        txLock         *os.File
        xxOnly         TRxTx
+       rxRate         int
+       txRate         int
        isDead         bool
        sync.RWMutex
 }
@@ -271,7 +273,7 @@ func (ctx *Ctx) infosOur(nodeId *NodeId, nice uint8, seen *map[[32]byte]uint8) [
        return payloadsSplit(payloads)
 }
 
-func (ctx *Ctx) StartI(conn net.Conn, nodeId *NodeId, nice uint8, xxOnly TRxTx, onlineDeadline, maxOnlineTime uint) (*SPState, error) {
+func (ctx *Ctx) StartI(conn net.Conn, nodeId *NodeId, nice uint8, xxOnly TRxTx, rxRate, txRate int, onlineDeadline, maxOnlineTime uint) (*SPState, error) {
        err := ctx.ensureRxDir(nodeId)
        if err != nil {
                return nil, err
@@ -320,6 +322,8 @@ func (ctx *Ctx) StartI(conn net.Conn, nodeId *NodeId, nice uint8, xxOnly TRxTx,
                rxLock:         rxLock,
                txLock:         txLock,
                xxOnly:         xxOnly,
+               rxRate:         rxRate,
+               txRate:         txRate,
        }
 
        var infosPayloads [][]byte
@@ -427,6 +431,8 @@ func (ctx *Ctx) StartR(conn net.Conn, nice uint8, xxOnly TRxTx) (*SPState, error
                return nil, errors.New("Unknown peer: " + peerId)
        }
        state.Node = node
+       state.rxRate = node.RxRate
+       state.txRate = node.TxRate
        state.onlineDeadline = node.OnlineDeadline
        state.maxOnlineTime = node.MaxOnlineTime
        sds := SDS{"node": node.Id, "nice": strconv.Itoa(int(nice))}
@@ -570,6 +576,11 @@ func (state *SPState) StartWorkers(conn net.Conn, infosPayloads [][]byte, payloa
                                }
                                freq := state.queueTheir[0].freq
                                state.RUnlock()
+
+                               if state.txRate > 0 {
+                                       time.Sleep(time.Second / time.Duration(state.txRate))
+                               }
+
                                sdsp := SdsAdd(sds, SDS{
                                        "xx":   string(TTx),
                                        "hash": ToBase32(freq.Hash[:]),
@@ -707,6 +718,9 @@ func (state *SPState) StartWorkers(conn net.Conn, infosPayloads [][]byte, payloa
                                        state.payloads <- reply
                                }
                        }()
+                       if state.rxRate > 0 {
+                               time.Sleep(time.Second / time.Duration(state.rxRate))
+                       }
                }
        }()