github.com/jshiv/can-go@v0.2.1-0.20210224011015-069e90e90bdf/pkg/socketcan/dial.go (about)

     1  package socketcan
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  )
     7  
     8  const udp = "udp"
     9  
    10  // Dial connects to the address on the named net.
    11  //
    12  // Linux only: If net is "can" it creates a SocketCAN connection to the device
    13  // (address is interpreted as a device name).
    14  //
    15  // If net is "udp" it assumes UDP multicast and sets up 2 connections, one for
    16  // receiving and one for transmitting.
    17  // See: https://golang.org/pkg/net/#Dial
    18  func Dial(network, address string) (net.Conn, error) {
    19  	switch network {
    20  	case udp:
    21  		return udpTransceiver(network, address)
    22  	case canRawNetwork:
    23  		return dialRaw(address) // platform-specific
    24  	default:
    25  		return net.Dial(network, address)
    26  	}
    27  }
    28  
    29  // DialContext connects to the address on the named net using
    30  // the provided context.
    31  //
    32  // Linux only: If net is "can" it creates a SocketCAN connection to the device
    33  // (address is interpreted as a device name).
    34  //
    35  // See: https://golang.org/pkg/net/#Dialer.DialContext
    36  func DialContext(ctx context.Context, network, address string) (net.Conn, error) {
    37  	switch network {
    38  	case canRawNetwork:
    39  		return dialCtx(ctx, func() (net.Conn, error) {
    40  			return dialRaw(address)
    41  		})
    42  	case udp:
    43  		return dialCtx(ctx, func() (net.Conn, error) {
    44  			return udpTransceiver(network, address)
    45  		})
    46  	default:
    47  		var d net.Dialer
    48  		return d.DialContext(ctx, network, address)
    49  	}
    50  }
    51  
    52  func dialCtx(ctx context.Context, connProvider func() (net.Conn, error)) (net.Conn, error) {
    53  	resultChan := make(chan struct {
    54  		conn net.Conn
    55  		err  error
    56  	})
    57  	go func() {
    58  		conn, err := connProvider()
    59  		resultChan <- struct {
    60  			conn net.Conn
    61  			err  error
    62  		}{conn: conn, err: err}
    63  	}()
    64  	// wait for connection or timeout
    65  	select {
    66  	case result := <-resultChan:
    67  		return result.conn, result.err
    68  	case <-ctx.Done():
    69  		// timeout - make sure we clean up the connection
    70  		// error handling not possible since we've already returned
    71  		go func() {
    72  			result := <-resultChan
    73  			if result.conn != nil {
    74  				_ = result.conn.Close()
    75  			}
    76  		}()
    77  		return nil, ctx.Err()
    78  	}
    79  }