]> Cypherpunks.ru repositories - nncp.git/blob - src/call.go
f916a8290646a61d340bbe78dedfb7a65e6d20ec
[nncp.git] / src / call.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2021 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         "time"
26
27         "github.com/dustin/go-humanize"
28         "github.com/gorhill/cronexpr"
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 }
52
53 func (ctx *Ctx) CallNode(
54         node *Node,
55         addrs []string,
56         nice uint8,
57         xxOnly TRxTx,
58         rxRate, txRate int,
59         onlineDeadline, maxOnlineTime time.Duration,
60         listOnly bool,
61         noCK bool,
62         onlyPkts map[[MTHSize]byte]bool,
63 ) (isGood bool) {
64         for _, addr := range addrs {
65                 les := LEs{{"Node", node.Id}, {"Addr", addr}}
66                 ctx.LogD("calling", les, func(les LEs) string {
67                         return fmt.Sprintf("Calling %s (%s)", node.Name, addr)
68                 })
69                 var conn ConnDeadlined
70                 var err error
71                 if addr[0] == '|' {
72                         conn, err = NewPipeConn(addr[1:])
73                 } else if addr == UCSPITCPClient {
74                         ucspiConn := UCSPIConn{R: os.NewFile(6, "R"), W: os.NewFile(7, "W")}
75                         if ucspiConn.R == nil {
76                                 err = errors.New("no 6 file descriptor")
77                         }
78                         if ucspiConn.W == nil {
79                                 err = errors.New("no 7 file descriptor")
80                         }
81                         conn = ucspiConn
82                         addr = UCSPITCPRemoteAddr()
83                         if addr == "" {
84                                 addr = UCSPITCPClient
85                         }
86                 } else {
87                         conn, err = net.Dial("tcp", addr)
88                 }
89                 if err != nil {
90                         ctx.LogD("calling", append(les, LE{"Err", err}), func(les LEs) string {
91                                 return fmt.Sprintf("Calling %s (%s)", node.Name, addr)
92                         })
93                         continue
94                 }
95                 ctx.LogD("call-connected", les, func(les LEs) string {
96                         return fmt.Sprintf("Connected %s (%s)", node.Name, addr)
97                 })
98                 state := SPState{
99                         Ctx:            ctx,
100                         Node:           node,
101                         Nice:           nice,
102                         onlineDeadline: onlineDeadline,
103                         maxOnlineTime:  maxOnlineTime,
104                         xxOnly:         xxOnly,
105                         rxRate:         rxRate,
106                         txRate:         txRate,
107                         listOnly:       listOnly,
108                         NoCK:           noCK,
109                         onlyPkts:       onlyPkts,
110                 }
111                 if err = state.StartI(conn); err == nil {
112                         ctx.LogI("call-started", les, func(les LEs) string {
113                                 return fmt.Sprintf("Connection to %s (%s)", node.Name, addr)
114                         })
115                         state.Wait()
116                         ctx.LogI("call-finished", append(
117                                 les,
118                                 LE{"Duration", int64(state.Duration.Seconds())},
119                                 LE{"RxBytes", state.RxBytes},
120                                 LE{"RxSpeed", state.RxSpeed},
121                                 LE{"TxBytes", state.TxBytes},
122                                 LE{"TxSpeed", state.TxSpeed},
123                         ), func(les LEs) string {
124                                 return fmt.Sprintf(
125                                         "Finished call with %s (%d:%d:%d): %s received (%s/sec), %s transferred (%s/sec)",
126                                         node.Name,
127                                         int(state.Duration.Hours()),
128                                         int(state.Duration.Minutes()),
129                                         int(state.Duration.Seconds())%60,
130                                         humanize.IBytes(uint64(state.RxBytes)),
131                                         humanize.IBytes(uint64(state.RxSpeed)),
132                                         humanize.IBytes(uint64(state.TxBytes)),
133                                         humanize.IBytes(uint64(state.TxSpeed)),
134                                 )
135                         })
136                         isGood = true
137                         conn.Close()
138                         break
139                 } else {
140                         ctx.LogE("call-started", les, err, func(les LEs) string {
141                                 return fmt.Sprintf("Connection to %s (%s)", node.Name, addr)
142                         })
143                         conn.Close()
144                 }
145         }
146         return
147 }