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 }