Update upstream source from tag 'upstream/0.9.2'
Update to upstream version '0.9.2'
with Debian dir 00afb51a816907e238ef2f15ebce2b5c7c9f6ff1
Federico Grau
2 years ago
0 | 0 | [![PkgGoDev](https://pkg.go.dev/badge/github.com/la5nta/wl2k-go)](https://pkg.go.dev/github.com/la5nta/wl2k-go) |
1 | [![Build Status](https://travis-ci.com/la5nta/wl2k-go.svg?branch=master)](https://travis-ci.com/la5nta/wl2k-go) | |
1 | [![Build Status](https://app.travis-ci.com/la5nta/wl2k-go.svg?branch=master)](https://app.travis-ci.com/la5nta/wl2k-go) | |
2 | 2 | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/j76on3km4vy5vsq0/branch/master?svg=true)](https://ci.appveyor.com/project/martinhpedersen/wl2k-go) |
3 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/la5nta/wl2k-go)](https://goreportcard.com/report/github.com/la5nta/wl2k-go) |
4 | 4 |
216 | 216 | // The given conn should always be closed after returning from this method. |
217 | 217 | // If an error occurred, echo it to the remote. |
218 | 218 | defer func() { |
219 | defer conn.Close() | |
219 | 220 | switch { |
220 | 221 | case err == nil: |
221 | 222 | // Success :-) |
232 | 233 | // Echo the error to the remote peer and disconnect. |
233 | 234 | conn.SetDeadline(time.Now().Add(time.Minute)) |
234 | 235 | fmt.Fprintf(conn, "*** %s\r\n", err) |
235 | conn.Close() | |
236 | 236 | } |
237 | 237 | }() |
238 | 238 |
44 | 44 | ErrConnectTimeout = errors.New("Connect timeout") |
45 | 45 | ErrChecksumMismatch = errors.New("Control protocol checksum mismatch") |
46 | 46 | ErrTNCClosed = errors.New("TNC closed") |
47 | ErrUnsupportedBandwidth = errors.New("Unsupported ARQ bandwidth") | |
47 | 48 | ) |
48 | 49 | |
49 | 50 | // Bandwidth definitions of all supported ARQ bandwidths. |
80 | 81 | // IsZero returns true if bw is it's zero value. |
81 | 82 | func (bw Bandwidth) IsZero() bool { return bw.Max == 0 } |
82 | 83 | |
84 | // BandwidthFromString returns a Bandwidth representation of the given string. | |
85 | // | |
86 | // The string must be a valid ARDOP ARQ bandwidth string (e.g. "2000MAX", "2000FORCED"). | |
87 | // The MAX/FORCED suffix may be omitted. Defaults to MAX. | |
88 | func BandwidthFromString(str string) (Bandwidth, error) { | |
89 | // Default to MAX if MAX/FORCED is not given. | |
90 | if strings.HasSuffix(str, "0") { | |
91 | str += "MAX" | |
92 | } | |
93 | for _, bw := range Bandwidths() { | |
94 | if bw.String() == str { | |
95 | return bw, nil | |
96 | } | |
97 | } | |
98 | return Bandwidth{}, ErrUnsupportedBandwidth | |
99 | } | |
100 | ||
101 | // Bandwidths returns a list of all ARDOP ARQ bandwidths. | |
102 | func Bandwidths() []Bandwidth { | |
103 | return []Bandwidth{ | |
104 | Bandwidth200Max, | |
105 | Bandwidth500Max, | |
106 | Bandwidth1000Max, | |
107 | Bandwidth2000Max, | |
108 | Bandwidth200Forced, | |
109 | Bandwidth500Forced, | |
110 | Bandwidth1000Forced, | |
111 | Bandwidth2000Forced, | |
112 | } | |
113 | } | |
114 | ||
83 | 115 | var stateMap = map[string]State{ |
84 | 116 | "": Unknown, |
85 | 117 | "OFFLINE": Offline, |
137 | 137 | case cmdAbort, cmdDisconnect, cmdClose, cmdDisconnected, cmdCRCFault, cmdPending, cmdCancelPending, cmdSendID: |
138 | 138 | |
139 | 139 | // (echo-back only) |
140 | case cmdInitialize, cmdARQCall, cmdARQBW, cmdProtocolMode: | |
140 | case cmdInitialize, cmdARQCall, cmdProtocolMode: | |
141 | 141 | |
142 | 142 | // State |
143 | 143 | case cmdNewState, cmdState: |
145 | 145 | |
146 | 146 | // string |
147 | 147 | case cmdFault, cmdMyCall, cmdGridSquare, cmdCapture, |
148 | cmdPlayback, cmdVersion, cmdTarget, cmdStatus: | |
148 | cmdPlayback, cmdVersion, cmdTarget, cmdStatus, cmdARQBW: | |
149 | 149 | msg.value = parts[1] |
150 | 150 | |
151 | 151 | // []string (space separated) |
10 | 10 | |
11 | 11 | func TestParse(t *testing.T) { |
12 | 12 | tests := map[string]ctrlMsg{ |
13 | "NEWSTATE DISC": ctrlMsg{cmdNewState, Disconnected}, | |
14 | "PTT True": ctrlMsg{cmdPTT, true}, | |
15 | "PTT False": ctrlMsg{cmdPTT, false}, | |
16 | "PTT trUE": ctrlMsg{cmdPTT, true}, | |
17 | "CODEC True": ctrlMsg{cmdCodec, true}, | |
18 | "foobar baz": ctrlMsg{command("FOOBAR"), nil}, | |
19 | "DISCONNECTED": ctrlMsg{cmdDisconnected, nil}, | |
20 | "FAULT 5/Error in the application.": ctrlMsg{cmdFault, "5/Error in the application."}, | |
21 | "BUFFER 300": ctrlMsg{cmdBuffer, 300}, | |
22 | "MYCALL LA5NTA": ctrlMsg{cmdMyCall, "LA5NTA"}, | |
23 | "GRIDSQUARE JP20QH": ctrlMsg{cmdGridSquare, "JP20QH"}, | |
24 | "MYAUX LA5NTA,LE3OF": ctrlMsg{cmdMyAux, []string{"LA5NTA", "LE3OF"}}, | |
25 | "MYAUX LA5NTA, LE3OF": ctrlMsg{cmdMyAux, []string{"LA5NTA", "LE3OF"}}, | |
26 | "VERSION 1.4.7.0": ctrlMsg{cmdVersion, "1.4.7.0"}, | |
27 | "FREQUENCY 14096400": ctrlMsg{cmdFrequency, 14096400}, | |
13 | "NEWSTATE DISC": {cmdNewState, Disconnected}, | |
14 | "PTT True": {cmdPTT, true}, | |
15 | "PTT False": {cmdPTT, false}, | |
16 | "PTT trUE": {cmdPTT, true}, | |
17 | "CODEC True": {cmdCodec, true}, | |
18 | "foobar baz": {command("FOOBAR"), nil}, | |
19 | "DISCONNECTED": {cmdDisconnected, nil}, | |
20 | "FAULT 5/Error in the application.": {cmdFault, "5/Error in the application."}, | |
21 | "BUFFER 300": {cmdBuffer, 300}, | |
22 | "MYCALL LA5NTA": {cmdMyCall, "LA5NTA"}, | |
23 | "GRIDSQUARE JP20QH": {cmdGridSquare, "JP20QH"}, | |
24 | "MYAUX LA5NTA,LE3OF": {cmdMyAux, []string{"LA5NTA", "LE3OF"}}, | |
25 | "MYAUX LA5NTA, LE3OF": {cmdMyAux, []string{"LA5NTA", "LE3OF"}}, | |
26 | "VERSION 1.4.7.0": {cmdVersion, "1.4.7.0"}, | |
27 | "FREQUENCY 14096400": {cmdFrequency, 14096400}, | |
28 | "ARQBW 200MAX": {cmdARQBW, "200MAX"}, | |
28 | 29 | } |
29 | 30 | for input, expected := range tests { |
30 | 31 | got := parseCtrlMsg(input) |
23 | 23 | eofChan chan struct{} |
24 | 24 | ctrlIn broadcaster |
25 | 25 | isTCP bool |
26 | onClose []func() error | |
26 | 27 | |
27 | 28 | remoteAddr Addr |
28 | 29 | localAddr Addr |
38 | 39 | nWritten int |
39 | 40 | } |
40 | 41 | |
41 | //TODO: implement | |
42 | // TODO: implement | |
42 | 43 | func (conn *tncConn) SetDeadline(t time.Time) error { return nil } |
43 | 44 | func (conn *tncConn) SetReadDeadline(t time.Time) error { return nil } |
44 | 45 | func (conn *tncConn) SetWriteDeadline(t time.Time) error { return nil } |
57 | 58 | } |
58 | 59 | |
59 | 60 | if len(data) > len(p) { |
60 | panic("too large") //TODO: Handle | |
61 | panic("too large") // TODO: Handle | |
61 | 62 | } |
62 | 63 | |
63 | 64 | for i, b := range data { |
71 | 72 | conn.dataLock.Lock() |
72 | 73 | defer conn.dataLock.Unlock() |
73 | 74 | |
74 | //TODO: Consider implementing chunking | |
75 | // TODO: Consider implementing chunking | |
75 | 76 | if len(p) > 65535 { // uint16 (length bytes) max |
76 | 77 | p = p[:65535] |
77 | 78 | } |
142 | 143 | |
143 | 144 | func (conn *tncConn) signalClosed() { close(conn.eofChan) } |
144 | 145 | |
145 | const flushAndCloseTimeout = 30 * time.Second //TODO: Remove when time is right (see Close). | |
146 | const flushAndCloseTimeout = 30 * time.Second // TODO: Remove when time is right (see Close). | |
146 | 147 | |
147 | 148 | // Close closes the current connection. |
148 | 149 | // |
151 | 152 | if conn == nil { |
152 | 153 | return nil |
153 | 154 | } |
155 | ||
156 | defer func() { | |
157 | for _, fn := range conn.onClose { | |
158 | err := fn() | |
159 | if err != nil && debugEnabled() { | |
160 | log.Printf("onClose func failed: %v", err) | |
161 | } | |
162 | } | |
163 | }() | |
154 | 164 | |
155 | 165 | // Flush: (THIS WILL PROBABLY BE REMOVED WHEN ARDOP MATURES) |
156 | 166 | // We have to flush, because ardop will disconnect without waiting for the last |
10 | 10 | "github.com/la5nta/wl2k-go/transport" |
11 | 11 | ) |
12 | 12 | |
13 | // DialURL dials ardop:// URLs | |
13 | // DialURL dials ardop:// URLs. | |
14 | // | |
15 | // Parameter bw can be used to set the ARQ bandwidth for this connection. See DialBandwidth for details. | |
14 | 16 | func (tnc *TNC) DialURL(url *transport.URL) (net.Conn, error) { |
15 | 17 | if url.Scheme != "ardop" { |
16 | 18 | return nil, transport.ErrUnsupportedScheme |
17 | 19 | } |
18 | ||
19 | return tnc.Dial(url.Target) | |
20 | bwStr := url.Params.Get("bw") | |
21 | if bwStr == "" { | |
22 | return tnc.Dial(url.Target) | |
23 | } | |
24 | bw, err := BandwidthFromString(bwStr) | |
25 | if err != nil { | |
26 | return nil, err | |
27 | } | |
28 | return tnc.DialBandwidth(url.Target, bw) | |
20 | 29 | } |
21 | 30 | |
31 | // Dial dials a ARQ connection. | |
22 | 32 | func (tnc *TNC) Dial(targetcall string) (net.Conn, error) { |
33 | return tnc.DialBandwidth(targetcall, Bandwidth{}) | |
34 | } | |
35 | ||
36 | // DialBandwidth dials a ARQ connection after setting the given ARQ bandwidth temporarily. | |
37 | // | |
38 | // The ARQ bandwidth setting is reverted on any Dial error and when calling conn.Close(). | |
39 | func (tnc *TNC) DialBandwidth(targetcall string, bw Bandwidth) (net.Conn, error) { | |
23 | 40 | if tnc.closed { |
24 | 41 | return nil, ErrTNCClosed |
25 | 42 | } |
26 | 43 | |
44 | var defers []func() error | |
45 | if !bw.IsZero() { | |
46 | currentBw, err := tnc.ARQBandwidth() | |
47 | if err != nil { | |
48 | return nil, err | |
49 | } | |
50 | if err := tnc.SetARQBandwidth(bw); err != nil { | |
51 | return nil, err | |
52 | } | |
53 | defers = append(defers, func() error { return tnc.SetARQBandwidth(currentBw) }) | |
54 | } | |
55 | ||
27 | 56 | if err := tnc.arqCall(targetcall, 10); err != nil { |
57 | for _, fn := range defers { | |
58 | _ = fn() | |
59 | } | |
28 | 60 | return nil, err |
29 | 61 | } |
30 | 62 | |
31 | 63 | mycall, err := tnc.MyCall() |
32 | 64 | if err != nil { |
65 | for _, fn := range defers { | |
66 | _ = fn() | |
67 | } | |
33 | 68 | return nil, fmt.Errorf("Error when getting mycall: %s", err) |
34 | 69 | } |
35 | 70 | |
42 | 77 | dataIn: tnc.dataIn, |
43 | 78 | eofChan: make(chan struct{}), |
44 | 79 | isTCP: tnc.isTCP, |
80 | onClose: defers, | |
45 | 81 | } |
46 | 82 | |
47 | 83 | return tnc.data, nil |
301 | 301 | } |
302 | 302 | |
303 | 303 | if err != nil { |
304 | panic(err) //FIXME | |
304 | panic(err) // FIXME | |
305 | 305 | } |
306 | 306 | } |
307 | 307 | } |
404 | 404 | // Sets the ARQ bandwidth |
405 | 405 | func (tnc *TNC) SetARQBandwidth(bw Bandwidth) error { |
406 | 406 | return tnc.set(cmdARQBW, bw) |
407 | } | |
408 | ||
409 | func (tnc *TNC) ARQBandwidth() (Bandwidth, error) { | |
410 | str, err := tnc.getString(cmdARQBW) | |
411 | if err != nil { | |
412 | return Bandwidth{}, err | |
413 | } | |
414 | bw, err := BandwidthFromString(str) | |
415 | if err != nil { | |
416 | return Bandwidth{}, fmt.Errorf("invalid ARQBW response: %w", err) | |
417 | } | |
418 | return bw, nil | |
407 | 419 | } |
408 | 420 | |
409 | 421 | // Sets the ARQ timeout |