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  }