2018-01-09 16:59:06 +01:00
package main
import (
2018-01-27 17:48:53 +01:00
"crypto/sha256"
2018-04-01 16:35:32 +02:00
"encoding/hex"
2018-01-27 15:26:08 +01:00
"errors"
"fmt"
2018-02-04 11:31:54 +01:00
"io"
2018-01-27 15:26:08 +01:00
"io/ioutil"
2018-01-09 17:19:03 +01:00
"math/rand"
2018-01-09 16:59:06 +01:00
"net"
2018-01-27 15:26:08 +01:00
"net/url"
2019-10-09 16:09:19 +02:00
"sort"
2018-01-09 16:59:06 +01:00
"strings"
"sync"
2018-01-09 17:15:07 +01:00
"time"
2018-01-09 16:59:06 +01:00
2018-01-10 16:42:14 +01:00
"github.com/VividCortex/ewma"
2018-01-11 11:50:54 +01:00
"github.com/jedisct1/dlog"
2018-04-18 18:58:39 +02:00
stamps "github.com/jedisct1/go-dnsstamps"
2018-04-01 16:35:32 +02:00
"golang.org/x/crypto/ed25519"
2018-01-09 16:59:06 +01:00
)
2018-01-10 16:42:14 +01:00
const (
RTTEwmaDecay = 10.0
2018-01-18 13:01:16 +01:00
)
2018-01-09 18:27:04 +01:00
type RegisteredServer struct {
2018-01-31 09:42:56 +01:00
name string
2018-04-14 15:03:21 +02:00
stamp stamps . ServerStamp
2018-01-31 09:42:56 +01:00
description string
2018-01-09 18:27:04 +01:00
}
2018-01-09 17:15:07 +01:00
type ServerInfo struct {
2018-01-10 16:42:14 +01:00
sync . RWMutex
2018-04-14 15:03:21 +02:00
Proto stamps . StampProtoType
2018-01-09 17:15:07 +01:00
MagicQuery [ 8 ] byte
ServerPk [ 32 ] byte
SharedKey [ 32 ] byte
CryptoConstruction CryptoConstruction
Name string
Timeout time . Duration
2018-01-27 15:26:08 +01:00
URL * url . URL
HostName string
2018-01-09 17:15:07 +01:00
UDPAddr * net . UDPAddr
TCPAddr * net . TCPAddr
2019-10-14 01:45:38 +02:00
RelayUDPAddr * net . UDPAddr
RelayTCPAddr * net . TCPAddr
2018-01-10 16:42:14 +01:00
lastActionTS time . Time
rtt ewma . MovingAverage
2018-01-17 22:12:34 +01:00
initialRtt int
2018-02-05 11:30:10 +01:00
useGet bool
2018-01-09 17:15:07 +01:00
}
2018-02-04 21:13:54 +01:00
type LBStrategy int
const (
LBStrategyNone = LBStrategy ( iota )
LBStrategyP2
LBStrategyPH
2019-06-02 13:24:24 +02:00
LBStrategyFirst
2018-02-04 21:13:54 +01:00
LBStrategyRandom
)
const DefaultLBStrategy = LBStrategyP2
2018-01-09 16:59:06 +01:00
type ServersInfo struct {
sync . RWMutex
2018-03-02 02:30:25 +01:00
inner [ ] * ServerInfo
2018-01-09 18:27:04 +01:00
registeredServers [ ] RegisteredServer
2018-02-04 21:13:54 +01:00
lbStrategy LBStrategy
2019-06-03 13:04:34 +02:00
lbEstimator bool
2018-01-09 16:59:06 +01:00
}
2019-06-03 16:44:09 +02:00
func NewServersInfo ( ) ServersInfo {
return ServersInfo { lbStrategy : DefaultLBStrategy , lbEstimator : true , registeredServers : make ( [ ] RegisteredServer , 0 ) }
}
2019-10-09 17:25:27 +02:00
func ( serversInfo * ServersInfo ) registerServer ( name string , stamp stamps . ServerStamp ) error {
2018-01-17 21:23:01 +01:00
newRegisteredServer := RegisteredServer { name : name , stamp : stamp }
serversInfo . Lock ( )
defer serversInfo . Unlock ( )
for i , oldRegisteredServer := range serversInfo . registeredServers {
if oldRegisteredServer . name == name {
serversInfo . registeredServers [ i ] = newRegisteredServer
return nil
}
}
serversInfo . registeredServers = append ( serversInfo . registeredServers , newRegisteredServer )
return nil
}
2018-04-14 15:03:21 +02:00
func ( serversInfo * ServersInfo ) refreshServer ( proxy * Proxy , name string , stamp stamps . ServerStamp ) error {
2019-03-14 01:59:57 +01:00
serversInfo . RLock ( )
2019-10-18 19:02:48 +02:00
isNew := true
for _ , oldServer := range serversInfo . inner {
2018-01-31 00:19:53 +01:00
if oldServer . Name == name {
2019-10-18 19:02:48 +02:00
isNew = false
2018-01-31 00:19:53 +01:00
break
}
}
2019-03-14 01:59:57 +01:00
serversInfo . RUnlock ( )
2019-10-18 19:02:48 +02:00
newServer , err := fetchServerInfo ( proxy , name , stamp , isNew )
2018-01-09 16:59:06 +01:00
if err != nil {
return err
}
2018-01-31 00:19:53 +01:00
if name != newServer . Name {
dlog . Fatalf ( "[%s] != [%s]" , name , newServer . Name )
}
2018-01-10 16:42:14 +01:00
newServer . rtt = ewma . NewMovingAverage ( RTTEwmaDecay )
2019-06-03 17:07:30 +02:00
newServer . rtt . Set ( float64 ( newServer . initialRtt ) )
2019-10-18 19:02:48 +02:00
isNew = true
2019-03-14 01:59:57 +01:00
serversInfo . Lock ( )
for i , oldServer := range serversInfo . inner {
if oldServer . Name == name {
2019-10-18 18:57:04 +02:00
serversInfo . inner [ i ] = & newServer
isNew = false
2019-03-14 01:59:57 +01:00
break
}
}
2019-10-18 18:57:04 +02:00
if isNew {
serversInfo . inner = append ( serversInfo . inner , & newServer )
serversInfo . registeredServers = append ( serversInfo . registeredServers , RegisteredServer { name : name , stamp : stamp } )
2018-01-09 17:15:07 +01:00
}
2019-10-18 18:57:04 +02:00
serversInfo . Unlock ( )
2018-01-09 16:59:06 +01:00
return nil
}
2018-01-17 17:22:29 +01:00
func ( serversInfo * ServersInfo ) refresh ( proxy * Proxy ) ( int , error ) {
2018-01-30 23:50:42 +01:00
dlog . Debug ( "Refreshing certificates" )
2018-01-09 17:34:19 +01:00
serversInfo . RLock ( )
2018-01-09 18:27:04 +01:00
registeredServers := serversInfo . registeredServers
2018-01-09 17:34:19 +01:00
serversInfo . RUnlock ( )
2018-01-17 17:22:29 +01:00
liveServers := 0
var err error
2018-01-09 18:27:04 +01:00
for _ , registeredServer := range registeredServers {
2018-01-17 21:23:01 +01:00
if err = serversInfo . refreshServer ( proxy , registeredServer . name , registeredServer . stamp ) ; err == nil {
2018-01-17 17:22:29 +01:00
liveServers ++
}
2018-01-09 17:34:19 +01:00
}
2018-01-17 22:12:34 +01:00
serversInfo . Lock ( )
2019-10-09 16:09:19 +02:00
sort . SliceStable ( serversInfo . inner , func ( i , j int ) bool {
return serversInfo . inner [ i ] . initialRtt < serversInfo . inner [ j ] . initialRtt
} )
2018-01-17 22:12:34 +01:00
inner := serversInfo . inner
innerLen := len ( inner )
2019-06-03 18:51:21 +02:00
if innerLen > 1 {
dlog . Notice ( "Sorted latencies:" )
for i := 0 ; i < innerLen ; i ++ {
dlog . Noticef ( "- %5dms %s" , inner [ i ] . initialRtt , inner [ i ] . Name )
}
2019-06-03 13:04:34 +02:00
}
2018-01-30 23:50:42 +01:00
if innerLen > 0 {
2018-01-17 22:12:34 +01:00
dlog . Noticef ( "Server with the lowest initial latency: %s (rtt: %dms)" , inner [ 0 ] . Name , inner [ 0 ] . initialRtt )
}
serversInfo . Unlock ( )
2018-01-17 17:22:29 +01:00
return liveServers , err
}
2018-01-09 17:34:19 +01:00
2019-10-20 17:17:21 +02:00
func ( serversInfo * ServersInfo ) estimatorUpdate ( ) {
candidate := rand . Intn ( len ( serversInfo . inner ) )
if candidate == 0 {
return
}
2018-02-21 00:14:18 +01:00
candidateRtt , currentBestRtt := serversInfo . inner [ candidate ] . rtt . Value ( ) , serversInfo . inner [ 0 ] . rtt . Value ( )
if currentBestRtt < 0 {
currentBestRtt = candidateRtt
serversInfo . inner [ 0 ] . rtt . Set ( currentBestRtt )
}
partialSort := false
if candidateRtt < currentBestRtt {
2018-01-10 16:42:14 +01:00
serversInfo . inner [ candidate ] , serversInfo . inner [ 0 ] = serversInfo . inner [ 0 ] , serversInfo . inner [ candidate ]
2018-02-21 00:14:18 +01:00
partialSort = true
2019-06-03 17:10:38 +02:00
dlog . Debugf ( "New preferred candidate: %v (rtt: %d vs previous: %d)" , serversInfo . inner [ 0 ] . Name , int ( candidateRtt ) , int ( currentBestRtt ) )
2019-06-03 16:44:09 +02:00
} else if candidateRtt > 0 && candidateRtt >= currentBestRtt * 4.0 {
2018-02-21 00:14:18 +01:00
if time . Since ( serversInfo . inner [ candidate ] . lastActionTS ) > time . Duration ( 1 * time . Minute ) {
serversInfo . inner [ candidate ] . rtt . Add ( MinF ( MaxF ( candidateRtt / 2.0 , currentBestRtt * 2.0 ) , candidateRtt ) )
2019-06-03 17:35:16 +02:00
dlog . Debugf ( "Giving a new chance to candidate [%s], lowering its RTT from %d to %d (best: %d)" , serversInfo . inner [ candidate ] . Name , int ( candidateRtt ) , int ( serversInfo . inner [ candidate ] . rtt . Value ( ) ) , int ( currentBestRtt ) )
2018-02-21 00:14:18 +01:00
partialSort = true
}
}
if partialSort {
2019-06-03 13:04:34 +02:00
serversCount := len ( serversInfo . inner )
2018-02-21 00:14:18 +01:00
for i := 1 ; i < serversCount ; i ++ {
if serversInfo . inner [ i - 1 ] . rtt . Value ( ) > serversInfo . inner [ i ] . rtt . Value ( ) {
serversInfo . inner [ i - 1 ] , serversInfo . inner [ i ] = serversInfo . inner [ i ] , serversInfo . inner [ i - 1 ]
}
}
2018-01-10 16:42:14 +01:00
}
2019-06-03 13:04:34 +02:00
}
func ( serversInfo * ServersInfo ) getOne ( ) * ServerInfo {
serversInfo . Lock ( )
defer serversInfo . Unlock ( )
serversCount := len ( serversInfo . inner )
if serversCount <= 0 {
return nil
}
if serversInfo . lbEstimator {
2019-10-20 17:17:21 +02:00
serversInfo . estimatorUpdate ( )
2019-06-03 13:04:34 +02:00
}
var candidate int
2018-02-04 21:13:54 +01:00
switch serversInfo . lbStrategy {
2019-06-02 13:24:24 +02:00
case LBStrategyFirst :
2018-02-04 21:13:54 +01:00
candidate = 0
case LBStrategyPH :
2019-10-20 17:13:30 +02:00
candidate = rand . Intn ( Max ( Min ( serversCount , 2 ) , serversCount / 2 ) )
2018-02-04 21:13:54 +01:00
case LBStrategyRandom :
2018-02-21 02:40:54 +01:00
candidate = rand . Intn ( serversCount )
2018-02-04 21:13:54 +01:00
default :
2018-02-21 02:40:54 +01:00
candidate = rand . Intn ( Min ( serversCount , 2 ) )
2018-02-04 21:13:54 +01:00
}
2018-03-02 02:30:25 +01:00
serverInfo := serversInfo . inner [ candidate ]
2019-06-03 17:32:54 +02:00
dlog . Debugf ( "Using candidate [%s] RTT: %d" , ( * serverInfo ) . Name , int ( ( * serverInfo ) . rtt . Value ( ) ) )
2018-02-22 14:20:59 +01:00
2018-01-09 16:59:06 +01:00
return serverInfo
}
2019-10-18 19:00:48 +02:00
func fetchServerInfo ( proxy * Proxy , name string , stamp stamps . ServerStamp , isNew bool ) ( ServerInfo , error ) {
2018-04-14 15:03:21 +02:00
if stamp . Proto == stamps . StampProtoTypeDNSCrypt {
2019-10-18 19:00:48 +02:00
return fetchDNSCryptServerInfo ( proxy , name , stamp , isNew )
2018-04-14 15:03:21 +02:00
} else if stamp . Proto == stamps . StampProtoTypeDoH {
2019-10-18 19:00:48 +02:00
return fetchDoHServerInfo ( proxy , name , stamp , isNew )
2018-01-27 15:26:08 +01:00
}
return ServerInfo { } , errors . New ( "Unsupported protocol" )
}
2019-10-20 19:11:54 +02:00
func route ( proxy * Proxy , name string , stamp * stamps . ServerStamp ) ( * net . UDPAddr , * net . TCPAddr , error ) {
2019-10-20 12:26:12 +02:00
routes := proxy . routes
if routes == nil {
return nil , nil , nil
}
relayNames , ok := ( * routes ) [ name ]
2019-10-20 14:19:21 +02:00
if ! ok {
relayNames , ok = ( * routes ) [ "*" ]
}
2019-10-20 12:26:12 +02:00
if ! ok {
return nil , nil , nil
}
var relayName string
if len ( relayNames ) > 0 {
candidate := rand . Intn ( len ( relayNames ) )
relayName = relayNames [ candidate ]
}
var relayCandidateStamp * stamps . ServerStamp
if len ( relayName ) == 0 {
return nil , nil , fmt . Errorf ( "Route declared for [%v] but an empty relay list" , name )
} else if relayStamp , err := stamps . NewServerStampFromString ( relayName ) ; err == nil {
relayCandidateStamp = & relayStamp
} else if _ , err := net . ResolveUDPAddr ( "udp" , relayName ) ; err == nil {
relayCandidateStamp = & stamps . ServerStamp {
ServerAddrStr : relayName ,
Proto : stamps . StampProtoTypeDNSCryptRelay ,
}
} else {
2019-10-20 14:19:21 +02:00
for _ , registeredServer := range proxy . registeredRelays {
if registeredServer . name == relayName {
relayCandidateStamp = & registeredServer . stamp
break
}
}
2019-10-20 12:26:12 +02:00
for _ , registeredServer := range proxy . registeredServers {
if registeredServer . name == relayName {
relayCandidateStamp = & registeredServer . stamp
2019-10-20 14:19:21 +02:00
break
2019-10-20 12:26:12 +02:00
}
}
}
if relayCandidateStamp == nil {
return nil , nil , fmt . Errorf ( "Undefined relay [%v] for server [%v]" , relayName , name )
}
if relayCandidateStamp . Proto == stamps . StampProtoTypeDNSCrypt ||
relayCandidateStamp . Proto == stamps . StampProtoTypeDNSCryptRelay {
relayUDPAddr , err := net . ResolveUDPAddr ( "udp" , relayCandidateStamp . ServerAddrStr )
if err != nil {
return nil , nil , err
}
relayTCPAddr , err := net . ResolveTCPAddr ( "tcp" , relayCandidateStamp . ServerAddrStr )
if err != nil {
return nil , nil , err
}
return relayUDPAddr , relayTCPAddr , nil
}
return nil , nil , fmt . Errorf ( "Invalid relay [%v] for server [%v]" , relayName , name )
}
2019-10-18 19:00:48 +02:00
func fetchDNSCryptServerInfo ( proxy * Proxy , name string , stamp stamps . ServerStamp , isNew bool ) ( ServerInfo , error ) {
2018-04-14 15:03:21 +02:00
if len ( stamp . ServerPk ) != ed25519 . PublicKeySize {
serverPk , err := hex . DecodeString ( strings . Replace ( string ( stamp . ServerPk ) , ":" , "" , - 1 ) )
2018-04-01 16:35:32 +02:00
if err != nil || len ( serverPk ) != ed25519 . PublicKeySize {
2018-04-14 15:03:21 +02:00
dlog . Fatalf ( "Unsupported public key for [%s]: [%s]" , name , stamp . ServerPk )
2018-04-01 16:35:32 +02:00
}
2018-04-14 15:03:21 +02:00
dlog . Warnf ( "Public key [%s] shouldn't be hex-encoded any more" , string ( stamp . ServerPk ) )
stamp . ServerPk = serverPk
2018-04-01 16:35:32 +02:00
}
2019-10-20 19:11:54 +02:00
relayUDPAddr , relayTCPAddr , err := route ( proxy , name , & stamp )
2019-10-20 12:26:12 +02:00
if err != nil {
return ServerInfo { } , err
2019-10-14 01:45:38 +02:00
}
2019-10-19 23:50:05 +02:00
certInfo , rtt , err := FetchCurrentDNSCryptCert ( proxy , & name , proxy . mainProto , stamp . ServerPk , stamp . ServerAddrStr , stamp . ProviderName , isNew , relayUDPAddr , relayTCPAddr )
if err != nil {
return ServerInfo { } , err
}
remoteUDPAddr , err := net . ResolveUDPAddr ( "udp" , stamp . ServerAddrStr )
if err != nil {
return ServerInfo { } , err
}
remoteTCPAddr , err := net . ResolveTCPAddr ( "tcp" , stamp . ServerAddrStr )
if err != nil {
return ServerInfo { } , err
}
2018-04-01 16:35:32 +02:00
return ServerInfo {
2018-04-14 15:03:21 +02:00
Proto : stamps . StampProtoTypeDNSCrypt ,
2018-04-01 16:35:32 +02:00
MagicQuery : certInfo . MagicQuery ,
ServerPk : certInfo . ServerPk ,
SharedKey : certInfo . SharedKey ,
CryptoConstruction : certInfo . CryptoConstruction ,
Name : name ,
Timeout : proxy . timeout ,
UDPAddr : remoteUDPAddr ,
TCPAddr : remoteTCPAddr ,
2019-10-14 01:45:38 +02:00
RelayUDPAddr : relayUDPAddr ,
RelayTCPAddr : relayTCPAddr ,
2018-04-01 16:35:32 +02:00
initialRtt : rtt ,
} , nil
}
2019-10-18 19:00:48 +02:00
func fetchDoHServerInfo ( proxy * Proxy , name string , stamp stamps . ServerStamp , isNew bool ) ( ServerInfo , error ) {
2018-04-14 15:03:21 +02:00
if len ( stamp . ServerAddrStr ) > 0 {
2019-10-20 17:11:08 +02:00
ipOnly , _ := ExtractHostAndPort ( stamp . ServerAddrStr , - 1 )
2018-01-30 13:29:47 +01:00
proxy . xTransport . cachedIPs . Lock ( )
2018-04-14 15:03:21 +02:00
proxy . xTransport . cachedIPs . cache [ stamp . ProviderName ] = ipOnly
2018-01-30 13:29:47 +01:00
proxy . xTransport . cachedIPs . Unlock ( )
2018-01-29 03:58:39 +01:00
}
2018-01-27 15:26:08 +01:00
url := & url . URL {
Scheme : "https" ,
2018-04-14 15:03:21 +02:00
Host : stamp . ProviderName ,
Path : stamp . Path ,
2018-01-27 15:26:08 +01:00
}
2018-01-30 15:46:21 +01:00
body := [ ] byte {
0xca , 0xfe , 0x01 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x02 , 0x00 , 0x01 , 0x00 , 0x00 , 0x29 , 0x10 , 0x00 , 0x00 , 0x00 , 0x80 , 0x00 , 0x00 , 0x00 ,
2018-01-27 16:48:22 +01:00
}
2018-02-05 11:30:10 +01:00
useGet := false
if _ , _ , err := proxy . xTransport . DoHQuery ( useGet , url , body , proxy . timeout ) ; err != nil {
useGet = true
if _ , _ , err := proxy . xTransport . DoHQuery ( useGet , url , body , proxy . timeout ) ; err != nil {
return ServerInfo { } , err
}
dlog . Debugf ( "Server [%s] doesn't appear to support POST; falling back to GET requests" , name )
2018-01-27 16:48:22 +01:00
}
2018-02-05 11:30:10 +01:00
resp , rtt , err := proxy . xTransport . DoHQuery ( useGet , url , body , proxy . timeout )
2018-01-30 15:46:21 +01:00
if err != nil {
2018-01-27 15:26:08 +01:00
return ServerInfo { } , err
}
2018-01-27 17:48:53 +01:00
tls := resp . TLS
if tls == nil || ! tls . HandshakeComplete {
return ServerInfo { } , errors . New ( "TLS handshake failed" )
}
2019-05-12 09:55:13 +02:00
protocol := tls . NegotiatedProtocol
if len ( protocol ) == 0 {
protocol = "h1"
dlog . Warnf ( "[%s] does not support HTTP/2" , name )
}
dlog . Infof ( "[%s] TLS version: %x - Protocol: %v - Cipher suite: %v" , name , tls . Version , protocol , tls . CipherSuite )
2019-06-07 01:23:48 +02:00
showCerts := proxy . showCerts
2018-01-27 17:48:53 +01:00
found := false
var wantedHash [ 32 ] byte
for _ , cert := range tls . PeerCertificates {
h := sha256 . Sum256 ( cert . RawTBSCertificate )
2018-02-05 13:24:17 +01:00
if showCerts {
2019-06-07 01:23:48 +02:00
dlog . Noticef ( "Advertised cert: [%s] [%x]" , cert . Subject , h )
2018-02-05 13:24:17 +01:00
} else {
dlog . Debugf ( "Advertised cert: [%s] [%x]" , cert . Subject , h )
}
2018-04-14 15:03:21 +02:00
for _ , hash := range stamp . Hashes {
2018-01-31 18:16:54 +01:00
if len ( hash ) == len ( wantedHash ) {
copy ( wantedHash [ : ] , hash )
if h == wantedHash {
found = true
break
}
}
}
if found {
2018-01-27 17:48:53 +01:00
break
}
}
2018-04-14 15:03:21 +02:00
if ! found && len ( stamp . Hashes ) > 0 {
2018-01-27 17:48:53 +01:00
return ServerInfo { } , fmt . Errorf ( "Certificate hash [%x] not found for [%s]" , wantedHash , name )
}
2018-02-04 11:31:54 +01:00
respBody , err := ioutil . ReadAll ( io . LimitReader ( resp . Body , MaxHTTPBodyLength ) )
2018-01-27 15:26:08 +01:00
if err != nil {
return ServerInfo { } , err
}
2018-01-27 16:59:45 +01:00
if len ( respBody ) < MinDNSPacketSize || len ( respBody ) > MaxDNSPacketSize ||
respBody [ 0 ] != 0xca || respBody [ 1 ] != 0xfe || respBody [ 4 ] != 0x00 || respBody [ 5 ] != 0x01 {
2018-01-27 15:26:08 +01:00
return ServerInfo { } , errors . New ( "Webserver returned an unexpected response" )
}
2019-06-03 17:07:30 +02:00
xrtt := int ( rtt . Nanoseconds ( ) / 1000000 )
2018-01-31 00:19:53 +01:00
if isNew {
2019-06-03 17:07:30 +02:00
dlog . Noticef ( "[%s] OK (DoH) - rtt: %dms" , name , xrtt )
2018-01-31 00:19:53 +01:00
} else {
2019-06-03 17:07:30 +02:00
dlog . Infof ( "[%s] OK (DoH) - rtt: %dms" , name , xrtt )
2018-01-31 00:19:53 +01:00
}
2018-03-17 22:47:17 +01:00
return ServerInfo {
2018-04-14 15:03:21 +02:00
Proto : stamps . StampProtoTypeDoH ,
2018-01-27 15:26:08 +01:00
Name : name ,
Timeout : proxy . timeout ,
URL : url ,
2018-04-14 15:03:21 +02:00
HostName : stamp . ProviderName ,
2019-06-03 17:07:30 +02:00
initialRtt : xrtt ,
2018-02-05 11:30:10 +01:00
useGet : useGet ,
2018-03-17 22:47:17 +01:00
} , nil
2018-01-27 15:26:08 +01:00
}
2018-01-10 16:42:14 +01:00
func ( serverInfo * ServerInfo ) noticeFailure ( proxy * Proxy ) {
serverInfo . Lock ( )
2018-02-21 00:14:18 +01:00
serverInfo . rtt . Add ( float64 ( proxy . timeout . Nanoseconds ( ) / 1000000 ) )
2018-01-10 16:42:14 +01:00
serverInfo . Unlock ( )
}
func ( serverInfo * ServerInfo ) noticeBegin ( proxy * Proxy ) {
serverInfo . Lock ( )
serverInfo . lastActionTS = time . Now ( )
serverInfo . Unlock ( )
}
func ( serverInfo * ServerInfo ) noticeSuccess ( proxy * Proxy ) {
now := time . Now ( )
serverInfo . Lock ( )
2018-02-21 00:14:18 +01:00
elapsed := now . Sub ( serverInfo . lastActionTS )
elapsedMs := elapsed . Nanoseconds ( ) / 1000000
if elapsedMs > 0 && elapsed < proxy . timeout {
serverInfo . rtt . Add ( float64 ( elapsedMs ) )
2018-01-10 16:42:14 +01:00
}
serverInfo . Unlock ( )
2018-01-10 16:01:29 +01:00
}