]> Cypherpunks.ru repositories - nncp.git/blob - src/call.go
de1ce4f6796e12f1490cef36455c69dbc1f03426
[nncp.git] / src / call.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2022 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 )
31
32 const YggdrasilPrefix = "yggdrasil:"
33
34 type Call struct {
35         Cron           *cronexpr.Expression
36         Nice           uint8
37         Xx             TRxTx
38         RxRate         int
39         TxRate         int
40         Addr           *string
41         OnlineDeadline time.Duration
42         MaxOnlineTime  time.Duration
43         WhenTxExists   bool
44         NoCK           bool
45         MCDIgnore      bool
46
47         AutoToss       bool
48         AutoTossDoSeen bool
49         AutoTossNoFile bool
50         AutoTossNoFreq bool
51         AutoTossNoExec bool
52         AutoTossNoTrns bool
53         AutoTossNoArea bool
54 }
55
56 func (ctx *Ctx) CallNode(
57         node *Node,
58         addrs []string,
59         nice uint8,
60         xxOnly TRxTx,
61         rxRate, txRate int,
62         onlineDeadline, maxOnlineTime time.Duration,
63         listOnly bool,
64         noCK bool,
65         onlyPkts map[[MTHSize]byte]bool,
66 ) (isGood bool) {
67         for _, addr := range addrs {
68                 les := LEs{{"Node", node.Id}, {"Addr", addr}}
69                 ctx.LogD("calling", les, func(les LEs) string {
70                         return fmt.Sprintf("Calling %s (%s)", node.Name, addr)
71                 })
72                 var conn ConnDeadlined
73                 var err error
74                 if addr[0] == '|' {
75                         conn, err = NewPipeConn(addr[1:])
76                 } else if addr == UCSPITCPClient {
77                         ucspiConn := UCSPIConn{R: os.NewFile(6, "R"), W: os.NewFile(7, "W")}
78                         if ucspiConn.R == nil {
79                                 err = errors.New("no 6 file descriptor")
80                         }
81                         if ucspiConn.W == nil {
82                                 err = errors.New("no 7 file descriptor")
83                         }
84                         conn = ucspiConn
85                         addr = UCSPITCPRemoteAddr()
86                         if addr == "" {
87                                 addr = UCSPITCPClient
88                         }
89                 } else if strings.HasPrefix(addr, YggdrasilPrefix) {
90                         conn, err = NewYggdrasilConn(
91                                 ctx.YggdrasilAliases,
92                                 strings.TrimPrefix(addr, YggdrasilPrefix),
93                         )
94                 } else {
95                         conn, err = net.Dial("tcp", addr)
96                 }
97                 if err != nil {
98                         ctx.LogE("calling", les, err, func(les LEs) string {
99                                 return fmt.Sprintf("Calling %s (%s)", node.Name, addr)
100                         })
101                         continue
102                 }
103                 ctx.LogD("call-connected", les, func(les LEs) string {
104                         return fmt.Sprintf("Connected %s (%s)", node.Name, addr)
105                 })
106                 state := SPState{
107                         Ctx:            ctx,
108                         Node:           node,
109                         Nice:           nice,
110                         onlineDeadline: onlineDeadline,
111                         maxOnlineTime:  maxOnlineTime,
112                         xxOnly:         xxOnly,
113                         rxRate:         rxRate,
114                         txRate:         txRate,
115                         listOnly:       listOnly,
116                         NoCK:           noCK,
117                         onlyPkts:       onlyPkts,
118                 }
119                 if err = state.StartI(conn); err == nil {
120                         ctx.LogI("call-started", les, func(les LEs) string {
121                                 return fmt.Sprintf("Connection to %s (%s)", node.Name, addr)
122                         })
123                         state.Wait()
124                         ctx.LogI("call-finished", append(
125                                 les,
126                                 LE{"Duration", int64(state.Duration.Seconds())},
127                                 LE{"RxBytes", state.RxBytes},
128                                 LE{"RxSpeed", state.RxSpeed},
129                                 LE{"TxBytes", state.TxBytes},
130                                 LE{"TxSpeed", state.TxSpeed},
131                         ), func(les LEs) string {
132                                 return fmt.Sprintf(
133                                         "Finished call with %s (%d:%d:%d): %s received (%s/sec), %s transferred (%s/sec)",
134                                         node.Name,
135                                         int(state.Duration.Hours()),
136                                         int(state.Duration.Minutes()),
137                                         int(state.Duration.Seconds())%60,
138                                         humanize.IBytes(uint64(state.RxBytes)),
139                                         humanize.IBytes(uint64(state.RxSpeed)),
140                                         humanize.IBytes(uint64(state.TxBytes)),
141                                         humanize.IBytes(uint64(state.TxSpeed)),
142                                 )
143                         })
144                         isGood = true
145                         conn.Close()
146                         break
147                 } else {
148                         ctx.LogE("call-started", les, err, func(les LEs) string {
149                                 return fmt.Sprintf("Connection to %s (%s)", node.Name, addr)
150                         })
151                         conn.Close()
152                 }
153         }
154         return
155 }