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