]> Cypherpunks.ru repositories - nncp.git/blob - src/call.go
Bad exit code if queues are not empty
[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         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 }
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, "yggdrasilc://") {
90                         conn, err = nncpYggdrasil.NewConn(ctx.YggdrasilAliases, addr)
91                 } else {
92                         conn, err = net.Dial("tcp", addr)
93                 }
94                 if err != nil {
95                         ctx.LogE("calling", les, err, func(les LEs) string {
96                                 return fmt.Sprintf("Calling %s (%s)", node.Name, addr)
97                         })
98                         continue
99                 }
100                 ctx.LogD("call-connected", les, func(les LEs) string {
101                         return fmt.Sprintf("Connected %s (%s)", node.Name, addr)
102                 })
103                 state := SPState{
104                         Ctx:            ctx,
105                         Node:           node,
106                         Nice:           nice,
107                         onlineDeadline: onlineDeadline,
108                         maxOnlineTime:  maxOnlineTime,
109                         xxOnly:         xxOnly,
110                         rxRate:         rxRate,
111                         txRate:         txRate,
112                         listOnly:       listOnly,
113                         NoCK:           noCK,
114                         onlyPkts:       onlyPkts,
115                 }
116                 if err = state.StartI(conn); err == nil {
117                         ctx.LogI("call-started", les, func(les LEs) string {
118                                 return fmt.Sprintf("Connection to %s (%s)", node.Name, addr)
119                         })
120                         isGood = state.Wait()
121                         ctx.LogI("call-finished", append(
122                                 les,
123                                 LE{"Duration", int64(state.Duration.Seconds())},
124                                 LE{"RxBytes", state.RxBytes},
125                                 LE{"RxSpeed", state.RxSpeed},
126                                 LE{"TxBytes", state.TxBytes},
127                                 LE{"TxSpeed", state.TxSpeed},
128                         ), func(les LEs) string {
129                                 return fmt.Sprintf(
130                                         "Finished call with %s (%d:%d:%d): %s received (%s/sec), %s transferred (%s/sec)",
131                                         node.Name,
132                                         int(state.Duration.Hours()),
133                                         int(state.Duration.Minutes()),
134                                         int(state.Duration.Seconds())%60,
135                                         humanize.IBytes(uint64(state.RxBytes)),
136                                         humanize.IBytes(uint64(state.RxSpeed)),
137                                         humanize.IBytes(uint64(state.TxBytes)),
138                                         humanize.IBytes(uint64(state.TxSpeed)),
139                                 )
140                         })
141                         conn.Close()
142                         break
143                 } else {
144                         ctx.LogE("call-started", les, err, func(les LEs) string {
145                                 return fmt.Sprintf("Connection to %s (%s)", node.Name, addr)
146                         })
147                         conn.Close()
148                 }
149         }
150         return
151 }