]> Cypherpunks.ru repositories - nncp.git/blob - src/call.go
Generate ACKs during tossing
[nncp.git] / src / call.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2023 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package nncp
19
20 import (
21         "errors"
22         "fmt"
23         "net"
24         "os"
25         "strings"
26         "time"
27
28         "github.com/dustin/go-humanize"
29         "github.com/gorhill/cronexpr"
30         nncpYggdrasil "go.cypherpunks.ru/nncp/v8/yggdrasil"
31 )
32
33 type Call struct {
34         Cron           *cronexpr.Expression
35         Nice           uint8
36         Xx             TRxTx
37         RxRate         int
38         TxRate         int
39         Addr           *string
40         OnlineDeadline time.Duration
41         MaxOnlineTime  time.Duration
42         WhenTxExists   bool
43         NoCK           bool
44         MCDIgnore      bool
45
46         AutoToss       bool
47         AutoTossDoSeen bool
48         AutoTossNoFile bool
49         AutoTossNoFreq bool
50         AutoTossNoExec bool
51         AutoTossNoTrns bool
52         AutoTossNoArea bool
53         AutoTossNoACK  bool
54         AutoTossGenACK bool
55 }
56
57 func (ctx *Ctx) CallNode(
58         node *Node,
59         addrs []string,
60         nice uint8,
61         xxOnly TRxTx,
62         rxRate, txRate int,
63         onlineDeadline, maxOnlineTime time.Duration,
64         listOnly bool,
65         noCK bool,
66         onlyPkts map[[MTHSize]byte]bool,
67 ) (isGood bool) {
68         for _, addr := range addrs {
69                 les := LEs{{"Node", node.Id}, {"Addr", addr}}
70                 ctx.LogD("calling", les, func(les LEs) string {
71                         return fmt.Sprintf("Calling %s (%s)", node.Name, addr)
72                 })
73                 var conn ConnDeadlined
74                 var err error
75                 if addr[0] == '|' {
76                         conn, err = NewPipeConn(addr[1:])
77                 } else if addr == UCSPITCPClient {
78                         ucspiConn := UCSPIConn{R: os.NewFile(6, "R"), W: os.NewFile(7, "W")}
79                         if ucspiConn.R == nil {
80                                 err = errors.New("no 6 file descriptor")
81                         }
82                         if ucspiConn.W == nil {
83                                 err = errors.New("no 7 file descriptor")
84                         }
85                         conn = ucspiConn
86                         addr = UCSPITCPRemoteAddr()
87                         if addr == "" {
88                                 addr = UCSPITCPClient
89                         }
90                 } else if strings.HasPrefix(addr, "yggdrasilc://") {
91                         conn, err = nncpYggdrasil.NewConn(ctx.YggdrasilAliases, addr)
92                 } else {
93                         conn, err = net.Dial("tcp", addr)
94                 }
95                 if err != nil {
96                         ctx.LogE("calling", les, err, func(les LEs) string {
97                                 return fmt.Sprintf("Calling %s (%s)", node.Name, addr)
98                         })
99                         continue
100                 }
101                 ctx.LogD("call-connected", les, func(les LEs) string {
102                         return fmt.Sprintf("Connected %s (%s)", node.Name, addr)
103                 })
104                 state := SPState{
105                         Ctx:            ctx,
106                         Node:           node,
107                         Nice:           nice,
108                         onlineDeadline: onlineDeadline,
109                         maxOnlineTime:  maxOnlineTime,
110                         xxOnly:         xxOnly,
111                         rxRate:         rxRate,
112                         txRate:         txRate,
113                         listOnly:       listOnly,
114                         NoCK:           noCK,
115                         onlyPkts:       onlyPkts,
116                 }
117                 if err = state.StartI(conn); err == nil {
118                         ctx.LogI("call-started", les, func(les LEs) string {
119                                 return fmt.Sprintf("Connection to %s (%s)", node.Name, addr)
120                         })
121                         isGood = state.Wait()
122                         ctx.LogI("call-finished", append(
123                                 les,
124                                 LE{"Duration", int64(state.Duration.Seconds())},
125                                 LE{"RxBytes", state.RxBytes},
126                                 LE{"RxSpeed", state.RxSpeed},
127                                 LE{"TxBytes", state.TxBytes},
128                                 LE{"TxSpeed", state.TxSpeed},
129                         ), func(les LEs) string {
130                                 return fmt.Sprintf(
131                                         "Finished call with %s (%d:%d:%d): %s received (%s/sec), %s transferred (%s/sec)",
132                                         node.Name,
133                                         int(state.Duration.Hours()),
134                                         int(state.Duration.Minutes()),
135                                         int(state.Duration.Seconds())%60,
136                                         humanize.IBytes(uint64(state.RxBytes)),
137                                         humanize.IBytes(uint64(state.RxSpeed)),
138                                         humanize.IBytes(uint64(state.TxBytes)),
139                                         humanize.IBytes(uint64(state.TxSpeed)),
140                                 )
141                         })
142                         conn.Close()
143                         break
144                 } else {
145                         ctx.LogE("call-started", les, err, func(les LEs) string {
146                                 return fmt.Sprintf("Connection to %s (%s)", node.Name, addr)
147                         })
148                         conn.Close()
149                 }
150         }
151         return
152 }