]> Cypherpunks.ru repositories - nncp.git/blob - src/call.go
Various Yggdrasil related refactoring and tcpip network stack
[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 }
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                         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                         isGood = true
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 }