github.com/bluenviron/gomavlib/v2@v2.2.1-0.20240308101627-2c07e3da629c/endpoint_server.go (about)

     1  package gomavlib
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net"
     7  	"time"
     8  
     9  	"github.com/pion/transport/v2/udp"
    10  
    11  	"github.com/bluenviron/gomavlib/v2/pkg/timednetconn"
    12  )
    13  
    14  type endpointServerConf interface {
    15  	isUDP() bool
    16  	getAddress() string
    17  	init(*Node) (Endpoint, error)
    18  }
    19  
    20  // EndpointTCPServer sets up a endpoint that works with a TCP server.
    21  // TCP is fit for routing frames through the internet, but is not the most
    22  // appropriate way for transferring frames from a UAV to a GCS, since it does
    23  // not allow frame losses.
    24  type EndpointTCPServer struct {
    25  	// listen address, example: 0.0.0.0:5600
    26  	Address string
    27  }
    28  
    29  func (EndpointTCPServer) isUDP() bool {
    30  	return false
    31  }
    32  
    33  func (conf EndpointTCPServer) getAddress() string {
    34  	return conf.Address
    35  }
    36  
    37  // EndpointUDPServer sets up a endpoint that works with an UDP server.
    38  // This is the most appropriate way for transferring frames from a UAV to a GCS
    39  // if they are connected to the same network.
    40  type EndpointUDPServer struct {
    41  	// listen address, example: 0.0.0.0:5600
    42  	Address string
    43  }
    44  
    45  func (EndpointUDPServer) isUDP() bool {
    46  	return true
    47  }
    48  
    49  func (conf EndpointUDPServer) getAddress() string {
    50  	return conf.Address
    51  }
    52  
    53  type endpointServer struct {
    54  	conf         endpointServerConf
    55  	listener     net.Listener
    56  	writeTimeout time.Duration
    57  	idleTimeout  time.Duration
    58  
    59  	// in
    60  	terminate chan struct{}
    61  }
    62  
    63  func (conf EndpointTCPServer) init(node *Node) (Endpoint, error) {
    64  	return initEndpointServer(node, conf)
    65  }
    66  
    67  func (conf EndpointUDPServer) init(node *Node) (Endpoint, error) {
    68  	return initEndpointServer(node, conf)
    69  }
    70  
    71  func initEndpointServer(node *Node, conf endpointServerConf) (Endpoint, error) {
    72  	_, _, err := net.SplitHostPort(conf.getAddress())
    73  	if err != nil {
    74  		return nil, fmt.Errorf("invalid address")
    75  	}
    76  
    77  	var ln net.Listener
    78  	if conf.isUDP() {
    79  		addr, err := net.ResolveUDPAddr("udp4", conf.getAddress())
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  
    84  		ln, err = udp.Listen("udp4", addr)
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  	} else {
    89  		ln, err = net.Listen("tcp4", conf.getAddress())
    90  		if err != nil {
    91  			return nil, err
    92  		}
    93  	}
    94  
    95  	t := &endpointServer{
    96  		conf:         conf,
    97  		writeTimeout: node.conf.WriteTimeout,
    98  		idleTimeout:  node.conf.IdleTimeout,
    99  		listener:     ln,
   100  		terminate:    make(chan struct{}),
   101  	}
   102  	return t, nil
   103  }
   104  
   105  func (t *endpointServer) isEndpoint() {}
   106  
   107  func (t *endpointServer) Conf() EndpointConf {
   108  	return t.conf
   109  }
   110  
   111  func (t *endpointServer) close() {
   112  	close(t.terminate)
   113  	t.listener.Close()
   114  }
   115  
   116  func (t *endpointServer) oneChannelAtAtime() bool {
   117  	return false
   118  }
   119  
   120  func (t *endpointServer) provide() (string, io.ReadWriteCloser, error) {
   121  	nconn, err := t.listener.Accept()
   122  	// wait termination, do not report errors
   123  	if err != nil {
   124  		<-t.terminate
   125  		return "", nil, errTerminated
   126  	}
   127  
   128  	label := fmt.Sprintf("%s:%s", func() string {
   129  		if t.conf.isUDP() {
   130  			return "udp"
   131  		}
   132  		return "tcp"
   133  	}(), nconn.RemoteAddr())
   134  
   135  	conn := timednetconn.New(
   136  		t.idleTimeout,
   137  		t.writeTimeout,
   138  		nconn)
   139  
   140  	return label, conn, nil
   141  }