2019-03-14 11:30:04 +03:00
package tcp
import (
"io"
"net"
2019-09-13 18:46:04 +03:00
"time"
2019-03-14 11:30:04 +03:00
2020-09-16 16:46:04 +03:00
"github.com/traefik/traefik/v2/pkg/log"
2019-03-14 11:30:04 +03:00
)
2020-05-11 13:06:07 +03:00
// Proxy forwards a TCP request to a TCP service.
2019-03-14 11:30:04 +03:00
type Proxy struct {
2019-09-13 18:46:04 +03:00
target * net . TCPAddr
terminationDelay time . Duration
2019-03-14 11:30:04 +03:00
}
2020-05-11 13:06:07 +03:00
// NewProxy creates a new Proxy.
2019-09-13 18:46:04 +03:00
func NewProxy ( address string , terminationDelay time . Duration ) ( * Proxy , error ) {
2019-03-14 11:30:04 +03:00
tcpAddr , err := net . ResolveTCPAddr ( "tcp" , address )
if err != nil {
return nil , err
}
2019-05-09 15:30:06 +03:00
2019-09-13 18:46:04 +03:00
return & Proxy { target : tcpAddr , terminationDelay : terminationDelay } , nil
2019-03-14 11:30:04 +03:00
}
2020-05-11 13:06:07 +03:00
// ServeTCP forwards the connection to a service.
2019-09-13 18:46:04 +03:00
func ( p * Proxy ) ServeTCP ( conn WriteCloser ) {
2019-03-14 11:30:04 +03:00
log . Debugf ( "Handling connection from %s" , conn . RemoteAddr ( ) )
2019-09-13 18:46:04 +03:00
// needed because of e.g. server.trackedConnection
2019-03-14 11:30:04 +03:00
defer conn . Close ( )
2019-05-09 15:30:06 +03:00
2019-03-14 11:30:04 +03:00
connBackend , err := net . DialTCP ( "tcp" , nil , p . target )
if err != nil {
log . Errorf ( "Error while connection to backend: %v" , err )
return
}
2019-09-13 18:46:04 +03:00
// maybe not needed, but just in case
2019-03-14 11:30:04 +03:00
defer connBackend . Close ( )
2019-09-13 18:46:04 +03:00
errChan := make ( chan error )
go p . connCopy ( conn , connBackend , errChan )
go p . connCopy ( connBackend , conn , errChan )
2019-03-14 11:30:04 +03:00
err = <- errChan
if err != nil {
2019-09-13 18:46:04 +03:00
log . WithoutContext ( ) . Errorf ( "Error during connection: %v" , err )
2019-03-14 11:30:04 +03:00
}
2019-09-13 18:46:04 +03:00
<- errChan
2019-03-14 11:30:04 +03:00
}
2019-09-13 18:46:04 +03:00
func ( p Proxy ) connCopy ( dst , src WriteCloser , errCh chan error ) {
2019-03-14 11:30:04 +03:00
_ , err := io . Copy ( dst , src )
errCh <- err
2019-09-13 18:46:04 +03:00
errClose := dst . CloseWrite ( )
if errClose != nil {
2019-09-13 21:00:06 +03:00
log . WithoutContext ( ) . Debugf ( "Error while terminating connection: %v" , errClose )
return
2019-09-13 18:46:04 +03:00
}
if p . terminationDelay >= 0 {
err := dst . SetReadDeadline ( time . Now ( ) . Add ( p . terminationDelay ) )
if err != nil {
2019-09-13 21:00:06 +03:00
log . WithoutContext ( ) . Debugf ( "Error while setting deadline: %v" , err )
2019-09-13 18:46:04 +03:00
}
}
2019-03-14 11:30:04 +03:00
}