github.com/la5nta/wl2k-go@v0.11.8/transport/ardop/dial.go (about) 1 // Copyright 2015 Martin Hebnes Pedersen (LA5NTA). All rights reserved. 2 // Use of this source code is governed by the MIT-license that can be 3 // found in the LICENSE file. 4 5 package ardop 6 7 import ( 8 "context" 9 "fmt" 10 "net" 11 12 "github.com/la5nta/wl2k-go/transport" 13 ) 14 15 // DialURL dials ardop:// URLs. 16 // 17 // Parameter bw can be used to set the ARQ bandwidth for this connection. See DialBandwidth for details. 18 func (tnc *TNC) DialURL(url *transport.URL) (net.Conn, error) { 19 if url.Scheme != "ardop" { 20 return nil, transport.ErrUnsupportedScheme 21 } 22 bwStr := url.Params.Get("bw") 23 if bwStr == "" { 24 return tnc.Dial(url.Target) 25 } 26 bw, err := BandwidthFromString(bwStr) 27 if err != nil { 28 return nil, err 29 } 30 return tnc.DialBandwidth(url.Target, bw) 31 } 32 33 // DialURLContext dials ardop:// URLs with cancellation support. See DialURL. 34 // 35 // If the context is cancelled while dialing, the connection may be closed gracefully before returning an error. 36 // Use Abort() for immediate cancellation of a dial operation. 37 func (tnc *TNC) DialURLContext(ctx context.Context, url *transport.URL) (net.Conn, error) { 38 var ( 39 conn net.Conn 40 err error 41 done = make(chan struct{}) 42 ) 43 go func() { 44 conn, err = tnc.DialURL(url) 45 close(done) 46 }() 47 select { 48 case <-done: 49 return conn, err 50 case <-ctx.Done(): 51 tnc.Disconnect() 52 return nil, ctx.Err() 53 } 54 } 55 56 // Dial dials a ARQ connection. 57 func (tnc *TNC) Dial(targetcall string) (net.Conn, error) { 58 return tnc.DialBandwidth(targetcall, Bandwidth{}) 59 } 60 61 // DialBandwidth dials a ARQ connection after setting the given ARQ bandwidth temporarily. 62 // 63 // The ARQ bandwidth setting is reverted on any Dial error and when calling conn.Close(). 64 func (tnc *TNC) DialBandwidth(targetcall string, bw Bandwidth) (net.Conn, error) { 65 if tnc.closed { 66 return nil, ErrTNCClosed 67 } 68 69 var defers []func() error 70 if !bw.IsZero() { 71 currentBw, err := tnc.ARQBandwidth() 72 if err != nil { 73 return nil, err 74 } 75 if err := tnc.SetARQBandwidth(bw); err != nil { 76 return nil, err 77 } 78 defers = append(defers, func() error { return tnc.SetARQBandwidth(currentBw) }) 79 } 80 81 if err := tnc.arqCall(targetcall, 10); err != nil { 82 for _, fn := range defers { 83 _ = fn() 84 } 85 return nil, err 86 } 87 88 mycall, err := tnc.MyCall() 89 if err != nil { 90 for _, fn := range defers { 91 _ = fn() 92 } 93 return nil, fmt.Errorf("Error when getting mycall: %s", err) 94 } 95 96 tnc.data = &tncConn{ 97 remoteAddr: Addr{targetcall}, 98 localAddr: Addr{mycall}, 99 ctrlOut: tnc.out, 100 dataOut: tnc.dataOut, 101 ctrlIn: tnc.in, 102 dataIn: tnc.dataIn, 103 eofChan: make(chan struct{}), 104 isTCP: tnc.isTCP, 105 onClose: defers, 106 } 107 108 return tnc.data, nil 109 }