本文整理匯總了Golang中github.com/Psiphon-Inc/goarista/monotime.Now函數的典型用法代碼示例。如果您正苦於以下問題:Golang Now函數的具體用法?Golang Now怎麽用?Golang Now使用的例子?那麽, 這裏精選的函數代碼示例或許可以為您提供幫助。
在下文中一共展示了Now函數的15個代碼示例,這些例子默認根據受歡迎程度排序。您可以為喜歡或者感覺有用的代碼點讚,您的評價將有助於係統推薦出更棒的Golang代碼示例。
示例1: IsUntunneled
// IsUntunneled takes a destination hostname or IP address and determines
// if it should be accessed through a tunnel. When a hostname is presented, it
// is first resolved to an IP address which can be matched against the routes data.
// Multiple goroutines may invoke RequiresTunnel simultaneously. Multi-reader
// locks are used in the implementation to enable concurrent access, with no locks
// held during network access.
func (classifier *SplitTunnelClassifier) IsUntunneled(targetAddress string) bool {
if !classifier.hasRoutes() {
return false
}
classifier.mutex.RLock()
cachedClassification, ok := classifier.cache[targetAddress]
classifier.mutex.RUnlock()
if ok && cachedClassification.expiry.After(monotime.Now()) {
return cachedClassification.isUntunneled
}
ipAddr, ttl, err := tunneledLookupIP(
classifier.dnsServerAddress, classifier.dnsTunneler, targetAddress)
if err != nil {
NoticeAlert("failed to resolve address for split tunnel classification: %s", err)
return false
}
expiry := monotime.Now().Add(ttl)
isUntunneled := classifier.ipAddressInRoutes(ipAddr)
// TODO: garbage collect expired items from cache?
classifier.mutex.Lock()
classifier.cache[targetAddress] = &classification{isUntunneled, expiry}
classifier.mutex.Unlock()
if isUntunneled {
NoticeUntunneled(targetAddress)
}
return isUntunneled
}
示例2: NewActivityMonitoredConn
// NewActivityMonitoredConn creates a new ActivityMonitoredConn.
func NewActivityMonitoredConn(
conn net.Conn,
inactivityTimeout time.Duration,
activeOnWrite bool,
activityUpdater ActivityUpdater,
lruEntry *LRUConnsEntry) (*ActivityMonitoredConn, error) {
if inactivityTimeout > 0 {
err := conn.SetDeadline(time.Now().Add(inactivityTimeout))
if err != nil {
return nil, ContextError(err)
}
}
now := int64(monotime.Now())
return &ActivityMonitoredConn{
Conn: conn,
inactivityTimeout: inactivityTimeout,
activeOnWrite: activeOnWrite,
realStartTime: time.Now(),
monotonicStartTime: now,
lastReadActivityTime: now,
activityUpdater: activityUpdater,
lruEntry: lruEntry,
}, nil
}
示例3: Read
func (conn *ActivityMonitoredConn) Read(buffer []byte) (int, error) {
n, err := conn.Conn.Read(buffer)
if err == nil {
if conn.inactivityTimeout > 0 {
err = conn.Conn.SetDeadline(time.Now().Add(conn.inactivityTimeout))
if err != nil {
return n, ContextError(err)
}
}
readActivityTime := int64(monotime.Now())
if conn.activityUpdater != nil {
conn.activityUpdater.UpdateProgress(
int64(n), 0, readActivityTime-atomic.LoadInt64(&conn.lastReadActivityTime))
}
if conn.lruEntry != nil {
conn.lruEntry.Touch()
}
atomic.StoreInt64(&conn.lastReadActivityTime, readActivityTime)
}
// Note: no context error to preserve error type
return n, err
}
示例4: NewDNSResolver
// NewDNSResolver initializes a new DNSResolver, loading it with
// a fresh resolver value. The load must succeed, so either
// "/etc/resolv.conf" must contain a valid "nameserver" line with
// a DNS server IP address, or a valid "defaultResolver" default
// value must be provided.
// On systems without "/etc/resolv.conf", "defaultResolver" is
// required.
//
// The resolver is considered stale and reloaded if last checked
// more than 5 seconds before the last Get(), which is similar to
// frequencies in other implementations:
//
// - https://golang.org/src/net/dnsclient_unix.go,
// resolverConfig.tryUpdate: 5 seconds
//
// - https://github.com/ambrop72/badvpn/blob/master/udpgw/udpgw.c,
// maybe_update_dns: 2 seconds
//
func NewDNSResolver(defaultResolver string) (*DNSResolver, error) {
dns := &DNSResolver{
lastReloadTime: int64(monotime.Now()),
}
dns.ReloadableFile = common.NewReloadableFile(
DNS_SYSTEM_CONFIG_FILENAME,
func(fileContent []byte) error {
resolver, err := parseResolveConf(fileContent)
if err != nil {
// On error, state remains the same
return common.ContextError(err)
}
dns.resolver = resolver
log.WithContextFields(
LogFields{
"resolver": resolver.String(),
}).Debug("loaded system DNS resolver")
return nil
})
_, err := dns.Reload()
if err != nil {
if defaultResolver == "" {
return nil, common.ContextError(err)
}
log.WithContextFields(
LogFields{"err": err}).Info(
"failed to load system DNS resolver; using default")
resolver, err := parseResolver(defaultResolver)
if err != nil {
return nil, common.ContextError(err)
}
dns.resolver = resolver
}
return dns, nil
}
示例5: Get
// Get returns the cached resolver, first updating the cached
// value if it's stale. If reloading fails, the previous value
// is used.
func (dns *DNSResolver) Get() net.IP {
// Every UDP DNS port forward frequently calls Get(), so this code
// is intended to minimize blocking. Most callers will hit just the
// atomic.LoadInt64 reload time check and the RLock (an atomic.AddInt32
// when no write lock is pending). An atomic.CompareAndSwapInt32 is
// used to ensure only one goroutine enters Reload() and blocks on
// its write lock. Finally, since since ReloadableFile.Reload
// checks whether the underlying file has changed _before_ aquiring a
// write lock, we only incur write lock blocking when "/etc/resolv.conf"
// has actually changed.
lastReloadTime := monotime.Time(atomic.LoadInt64(&dns.lastReloadTime))
stale := monotime.Now().After(lastReloadTime.Add(DNS_SYSTEM_CONFIG_RELOAD_PERIOD))
if stale {
isReloader := atomic.CompareAndSwapInt32(&dns.isReloading, 0, 1)
if isReloader {
// Unconditionally set last reload time. Even on failure only
// want to retry after another DNS_SYSTEM_CONFIG_RELOAD_PERIOD.
atomic.StoreInt64(&dns.lastReloadTime, time.Now().Unix())
_, err := dns.Reload()
if err != nil {
log.WithContextFields(
LogFields{"err": err}).Info(
"failed to reload system DNS resolver")
}
atomic.StoreInt32(&dns.isReloading, 0)
}
}
dns.ReloadableFile.RLock()
defer dns.ReloadableFile.RUnlock()
return dns.resolver
}
示例6: pumpWrites
// pumpWrites causes goroutines blocking on meekConn.Write() to write
// to the specified writer. This function blocks until the meek response
// body limits (size for protocol v1, turn around time for protocol v2+)
// are met, or the meekConn is closed.
// Note: channel scheme assumes only one concurrent call to pumpWrites
func (conn *meekConn) pumpWrites(writer io.Writer) error {
startTime := monotime.Now()
timeout := time.NewTimer(MEEK_TURN_AROUND_TIMEOUT)
defer timeout.Stop()
for {
select {
case buffer := <-conn.nextWriteBuffer:
_, err := writer.Write(buffer)
// Assumes that writeResult won't block.
// Note: always send the err to writeResult,
// as the Write() caller is blocking on this.
conn.writeResult <- err
if err != nil {
return err
}
if conn.protocolVersion < MEEK_PROTOCOL_VERSION_2 {
// Protocol v1 clients expect at most
// MEEK_MAX_PAYLOAD_LENGTH response bodies
return nil
}
totalElapsedTime := monotime.Since(startTime) / time.Millisecond
if totalElapsedTime >= MEEK_EXTENDED_TURN_AROUND_TIMEOUT {
return nil
}
timeout.Reset(MEEK_TURN_AROUND_TIMEOUT)
case <-timeout.C:
return nil
case <-conn.closeBroadcast:
return io.EOF
}
}
}
示例7: classifyImpairedProtocol
// classifyImpairedProtocol tracks "impaired" protocol classifications for failed
// tunnels. A protocol is classified as impaired if a tunnel using that protocol
// fails, repeatedly, shortly after the start of the connection. During tunnel
// establishment, impaired protocols are briefly skipped.
//
// One purpose of this measure is to defend against an attack where the adversary,
// for example, tags an OSSH TCP connection as an "unidentified" protocol; allows
// it to connect; but then kills the underlying TCP connection after a short time.
// Since OSSH has less latency than other protocols that may bypass an "unidentified"
// filter, these other protocols might never be selected for use.
//
// Concurrency note: only the runTunnels() goroutine may call classifyImpairedProtocol
func (controller *Controller) classifyImpairedProtocol(failedTunnel *Tunnel) {
if failedTunnel.establishedTime.Add(IMPAIRED_PROTOCOL_CLASSIFICATION_DURATION).After(monotime.Now()) {
controller.impairedProtocolClassification[failedTunnel.protocol] += 1
} else {
controller.impairedProtocolClassification[failedTunnel.protocol] = 0
}
if len(controller.getImpairedProtocols()) == len(common.SupportedTunnelProtocols) {
// Reset classification if all protocols are classified as impaired as
// the network situation (or attack) may not be protocol-specific.
// TODO: compare against count of distinct supported protocols for
// current known server entries.
controller.impairedProtocolClassification = make(map[string]int)
}
}
示例8: upgradeDownloader
// upgradeDownloader makes periodic attemps to complete a client upgrade
// download. DownloadUpgrade() is resumable, so each attempt has potential for
// getting closer to completion, even in conditions where the download or
// tunnel is repeatedly interrupted.
// An upgrade download is triggered by either a handshake response indicating
// that a new version is available; or after failing to connect, in which case
// it's useful to check, out-of-band, for an upgrade with new circumvention
// capabilities.
// Once the download operation completes successfully, the downloader exits
// and is not run again: either there is not a newer version, or the upgrade
// has been downloaded and is ready to be applied.
// We're assuming that the upgrade will be applied and the entire system
// restarted before another upgrade is to be downloaded.
//
// TODO: refactor upgrade downloader and remote server list fetcher to use
// common code (including the resumable download routines).
//
func (controller *Controller) upgradeDownloader() {
defer controller.runWaitGroup.Done()
var lastDownloadTime monotime.Time
downloadLoop:
for {
// Wait for a signal before downloading
var handshakeVersion string
select {
case handshakeVersion = <-controller.signalDownloadUpgrade:
case <-controller.shutdownBroadcast:
break downloadLoop
}
// Unless handshake is explicitly advertizing a new version, skip
// checking entirely when a recent download was successful.
if handshakeVersion == "" &&
lastDownloadTime != 0 &&
lastDownloadTime.Add(DOWNLOAD_UPGRADE_STALE_PERIOD).After(monotime.Now()) {
continue
}
retryLoop:
for {
// Don't attempt to download while there is no network connectivity,
// to avoid alert notice noise.
if !WaitForNetworkConnectivity(
controller.config.NetworkConnectivityChecker,
controller.shutdownBroadcast) {
break downloadLoop
}
// Pick any active tunnel and make the next download attempt. If there's
// no active tunnel, the untunneledDialConfig will be used.
tunnel := controller.getNextActiveTunnel()
err := DownloadUpgrade(
controller.config,
handshakeVersion,
tunnel,
controller.untunneledDialConfig)
if err == nil {
lastDownloadTime = monotime.Now()
break retryLoop
}
NoticeAlert("failed to download upgrade: %s", err)
timeout := time.After(
time.Duration(*controller.config.DownloadUpgradeRetryPeriodSeconds) * time.Second)
select {
case <-timeout:
case <-controller.shutdownBroadcast:
break downloadLoop
}
}
}
NoticeInfo("exiting upgrade downloader")
}
示例9: remoteServerListFetcher
// remoteServerListFetcher fetches an out-of-band list of server entries
// for more tunnel candidates. It fetches when signalled, with retries
// on failure.
func (controller *Controller) remoteServerListFetcher() {
defer controller.runWaitGroup.Done()
if controller.config.RemoteServerListUrl == "" {
NoticeAlert("remote server list URL is blank")
return
}
if controller.config.RemoteServerListSignaturePublicKey == "" {
NoticeAlert("remote server list signature public key blank")
return
}
var lastFetchTime monotime.Time
fetcherLoop:
for {
// Wait for a signal before fetching
select {
case <-controller.signalFetchRemoteServerList:
case <-controller.shutdownBroadcast:
break fetcherLoop
}
// Skip fetch entirely (i.e., send no request at all, even when ETag would save
// on response size) when a recent fetch was successful
if lastFetchTime != 0 &&
lastFetchTime.Add(FETCH_REMOTE_SERVER_LIST_STALE_PERIOD).After(monotime.Now()) {
continue
}
retryLoop:
for {
// Don't attempt to fetch while there is no network connectivity,
// to avoid alert notice noise.
if !WaitForNetworkConnectivity(
controller.config.NetworkConnectivityChecker,
controller.shutdownBroadcast) {
break fetcherLoop
}
// Pick any active tunnel and make the next fetch attempt. If there's
// no active tunnel, the untunneledDialConfig will be used.
tunnel := controller.getNextActiveTunnel()
err := FetchRemoteServerList(
controller.config,
tunnel,
controller.untunneledDialConfig)
if err == nil {
lastFetchTime = monotime.Now()
break retryLoop
}
NoticeAlert("failed to fetch remote server list: %s", err)
timeout := time.After(
time.Duration(*controller.config.FetchRemoteServerListRetryPeriodSeconds) * time.Second)
select {
case <-timeout:
case <-controller.shutdownBroadcast:
break fetcherLoop
}
}
}
NoticeInfo("exiting remote server list fetcher")
}
示例10: operateTunnel
// operateTunnel monitors the health of the tunnel and performs
// periodic work.
//
// BytesTransferred and TotalBytesTransferred notices are emitted
// for live reporting and diagnostics reporting, respectively.
//
// Status requests are sent to the Psiphon API to report bytes
// transferred.
//
// Periodic SSH keep alive packets are sent to ensure the underlying
// TCP connection isn't terminated by NAT, or other network
// interference -- or test if it has been terminated while the device
// has been asleep. When a keep alive times out, the tunnel is
// considered failed.
//
// An immediate SSH keep alive "probe" is sent to test the tunnel and
// server responsiveness when a port forward failure is detected: a
// failed dial or failed read/write. This keep alive has a shorter
// timeout.
//
// Note that port foward failures may be due to non-failure conditions.
// For example, when the user inputs an invalid domain name and
// resolution is done by the ssh server; or trying to connect to a
// non-white-listed port; and the error message in these cases is not
// distinguishable from a a true server error (a common error message,
// "ssh: rejected: administratively prohibited (open failed)", may be
// returned for these cases but also if the server has run out of
// ephemeral ports, for example).
//
// SSH keep alives are not sent when the tunnel has been recently
// active (not only does tunnel activity obviate the necessity of a keep
// alive, testing has shown that keep alives may time out for "busy"
// tunnels, especially over meek protocol and other high latency
// conditions).
//
// "Recently active" is defined has having received payload bytes. Sent
// bytes are not considered as testing has shown bytes may appear to
// send when certain NAT devices have interfered with the tunnel, while
// no bytes are received. In a pathological case, with DNS implemented
// as tunneled UDP, a browser may wait excessively for a domain name to
// resolve, while no new port forward is attempted which would otherwise
// result in a tunnel failure detection.
//
// TODO: change "recently active" to include having received any
// SSH protocol messages from the server, not just user payload?
//
func (tunnel *Tunnel) operateTunnel(tunnelOwner TunnelOwner) {
defer tunnel.operateWaitGroup.Done()
lastBytesReceivedTime := monotime.Now()
lastTotalBytesTransferedTime := monotime.Now()
totalSent := int64(0)
totalReceived := int64(0)
noticeBytesTransferredTicker := time.NewTicker(1 * time.Second)
defer noticeBytesTransferredTicker.Stop()
// The next status request and ssh keep alive times are picked at random,
// from a range, to make the resulting traffic less fingerprintable,
// Note: not using Tickers since these are not fixed time periods.
nextStatusRequestPeriod := func() time.Duration {
return makeRandomPeriod(
PSIPHON_API_STATUS_REQUEST_PERIOD_MIN,
PSIPHON_API_STATUS_REQUEST_PERIOD_MAX)
}
statsTimer := time.NewTimer(nextStatusRequestPeriod())
defer statsTimer.Stop()
// Schedule an immediate status request to deliver any unreported
// persistent stats.
// Note: this may not be effective when there's an outstanding
// asynchronous untunneled final status request is holding the
// persistent stats records. It may also conflict with other
// tunnel candidates which attempt to send an immediate request
// before being discarded. For now, we mitigate this with a short,
// random delay.
unreported := CountUnreportedPersistentStats()
if unreported > 0 {
NoticeInfo("Unreported persistent stats: %d", unreported)
statsTimer.Reset(makeRandomPeriod(
PSIPHON_API_STATUS_REQUEST_SHORT_PERIOD_MIN,
PSIPHON_API_STATUS_REQUEST_SHORT_PERIOD_MAX))
}
nextSshKeepAlivePeriod := func() time.Duration {
return makeRandomPeriod(
TUNNEL_SSH_KEEP_ALIVE_PERIOD_MIN,
TUNNEL_SSH_KEEP_ALIVE_PERIOD_MAX)
}
// TODO: don't initialize timer when config.DisablePeriodicSshKeepAlive is set
sshKeepAliveTimer := time.NewTimer(nextSshKeepAlivePeriod())
if tunnel.config.DisablePeriodicSshKeepAlive {
sshKeepAliveTimer.Stop()
} else {
defer sshKeepAliveTimer.Stop()
}
//.........這裏部分代碼省略.........
示例11: EstablishTunnel
// EstablishTunnel first makes a network transport connection to the
// Psiphon server and then establishes an SSH client session on top of
// that transport. The SSH server is authenticated using the public
// key in the server entry.
// Depending on the server's capabilities, the connection may use
// plain SSH over TCP, obfuscated SSH over TCP, or obfuscated SSH over
// HTTP (meek protocol).
// When requiredProtocol is not blank, that protocol is used. Otherwise,
// the a random supported protocol is used.
// untunneledDialConfig is used for untunneled final status requests.
func EstablishTunnel(
config *Config,
untunneledDialConfig *DialConfig,
sessionId string,
pendingConns *common.Conns,
serverEntry *protocol.ServerEntry,
adjustedEstablishStartTime monotime.Time,
tunnelOwner TunnelOwner) (tunnel *Tunnel, err error) {
selectedProtocol, err := selectProtocol(config, serverEntry)
if err != nil {
return nil, common.ContextError(err)
}
// Build transport layers and establish SSH connection. Note that
// dialConn and monitoredConn are the same network connection.
dialResult, err := dialSsh(
config, pendingConns, serverEntry, selectedProtocol, sessionId)
if err != nil {
return nil, common.ContextError(err)
}
// Cleanup on error
defer func() {
if err != nil {
dialResult.sshClient.Close()
dialResult.monitoredConn.Close()
pendingConns.Remove(dialResult.dialConn)
}
}()
// The tunnel is now connected
tunnel = &Tunnel{
mutex: new(sync.Mutex),
config: config,
untunneledDialConfig: untunneledDialConfig,
isClosed: false,
serverEntry: serverEntry,
protocol: selectedProtocol,
conn: dialResult.monitoredConn,
sshClient: dialResult.sshClient,
sshServerRequests: dialResult.sshRequests,
operateWaitGroup: new(sync.WaitGroup),
shutdownOperateBroadcast: make(chan struct{}),
// A buffer allows at least one signal to be sent even when the receiver is
// not listening. Senders should not block.
signalPortForwardFailure: make(chan struct{}, 1),
dialStats: dialResult.dialStats,
// Buffer allows SetClientVerificationPayload to submit one new payload
// without blocking or dropping it.
newClientVerificationPayload: make(chan string, 1),
}
// Create a new Psiphon API server context for this tunnel. This includes
// performing a handshake request. If the handshake fails, this establishment
// fails.
if !config.DisableApi {
NoticeInfo("starting server context for %s", tunnel.serverEntry.IpAddress)
tunnel.serverContext, err = NewServerContext(tunnel, sessionId)
if err != nil {
return nil, common.ContextError(
fmt.Errorf("error starting server context for %s: %s",
tunnel.serverEntry.IpAddress, err))
}
}
// establishDuration is the elapsed time between the controller starting tunnel
// establishment and this tunnel being established. The reported value represents
// how long the user waited between starting the client and having a usable tunnel;
// or how long between the client detecting an unexpected tunnel disconnect and
// completing automatic reestablishment.
//
// This time period may include time spent unsuccessfully connecting to other
// servers. Time spent waiting for network connectivity is excluded.
tunnel.establishDuration = monotime.Since(adjustedEstablishStartTime)
tunnel.establishedTime = monotime.Now()
// Now that network operations are complete, cancel interruptibility
pendingConns.Remove(dialResult.dialConn)
// Spawn the operateTunnel goroutine, which monitors the tunnel and handles periodic stats updates.
tunnel.operateWaitGroup.Add(1)
go tunnel.operateTunnel(tunnelOwner)
return tunnel, nil
}
示例12: touch
func (session *meekSession) touch() {
atomic.StoreInt64(&session.lastActivity, int64(monotime.Now()))
}
示例13: remoteServerListFetcher
// remoteServerListFetcher fetches an out-of-band list of server entries
// for more tunnel candidates. It fetches when signalled, with retries
// on failure.
func (controller *Controller) remoteServerListFetcher(
name string,
fetcher RemoteServerListFetcher,
signal <-chan struct{},
retryPeriod, stalePeriod time.Duration) {
defer controller.runWaitGroup.Done()
var lastFetchTime monotime.Time
fetcherLoop:
for {
// Wait for a signal before fetching
select {
case <-signal:
case <-controller.shutdownBroadcast:
break fetcherLoop
}
// Skip fetch entirely (i.e., send no request at all, even when ETag would save
// on response size) when a recent fetch was successful
if lastFetchTime != 0 &&
lastFetchTime.Add(stalePeriod).After(monotime.Now()) {
continue
}
retryLoop:
for {
// Don't attempt to fetch while there is no network connectivity,
// to avoid alert notice noise.
if !WaitForNetworkConnectivity(
controller.config.NetworkConnectivityChecker,
controller.shutdownBroadcast) {
break fetcherLoop
}
// Pick any active tunnel and make the next fetch attempt. If there's
// no active tunnel, the untunneledDialConfig will be used.
tunnel := controller.getNextActiveTunnel()
err := fetcher(
controller.config,
tunnel,
controller.untunneledDialConfig)
if err == nil {
lastFetchTime = monotime.Now()
break retryLoop
}
NoticeAlert("failed to fetch %s remote server list: %s", name, err)
timeout := time.After(retryPeriod)
select {
case <-timeout:
case <-controller.shutdownBroadcast:
break fetcherLoop
}
}
}
NoticeInfo("exiting %s remote server list fetcher", name)
}
示例14: establishCandidateGenerator
// establishCandidateGenerator populates the candidate queue with server entries
// from the data store. Server entries are iterated in rank order, so that promoted
// servers with higher rank are priority candidates.
func (controller *Controller) establishCandidateGenerator(impairedProtocols []string) {
defer controller.establishWaitGroup.Done()
defer close(controller.candidateServerEntries)
// establishStartTime is used to calculate and report the
// client's tunnel establishment duration.
//
// networkWaitDuration is the elapsed time spent waiting
// for network connectivity. This duration will be excluded
// from reported tunnel establishment duration.
establishStartTime := monotime.Now()
var networkWaitDuration time.Duration
iterator, err := NewServerEntryIterator(controller.config)
if err != nil {
NoticeAlert("failed to iterate over candidates: %s", err)
controller.SignalComponentFailure()
return
}
defer iterator.Close()
isServerAffinityCandidate := true
// TODO: reconcile server affinity scheme with multi-tunnel mode
if controller.config.TunnelPoolSize > 1 {
isServerAffinityCandidate = false
close(controller.serverAffinityDoneBroadcast)
}
loop:
// Repeat until stopped
for i := 0; ; i++ {
networkWaitStartTime := monotime.Now()
if !WaitForNetworkConnectivity(
controller.config.NetworkConnectivityChecker,
controller.stopEstablishingBroadcast,
controller.shutdownBroadcast) {
break loop
}
networkWaitDuration += monotime.Since(networkWaitStartTime)
// Send each iterator server entry to the establish workers
startTime := monotime.Now()
for {
serverEntry, err := iterator.Next()
if err != nil {
NoticeAlert("failed to get next candidate: %s", err)
controller.SignalComponentFailure()
break loop
}
if serverEntry == nil {
// Completed this iteration
break
}
if controller.config.TargetApiProtocol == common.PSIPHON_SSH_API_PROTOCOL &&
!serverEntry.SupportsSSHAPIRequests() {
continue
}
// Disable impaired protocols. This is only done for the
// first iteration of the ESTABLISH_TUNNEL_WORK_TIME
// loop since (a) one iteration should be sufficient to
// evade the attack; (b) there's a good chance of false
// positives (such as short tunnel durations due to network
// hopping on a mobile device).
// Impaired protocols logic is not applied when
// config.TunnelProtocol is specified.
// The edited serverEntry is temporary copy which is not
// stored or reused.
if i == 0 && controller.config.TunnelProtocol == "" {
serverEntry.DisableImpairedProtocols(impairedProtocols)
if len(serverEntry.GetSupportedProtocols()) == 0 {
// Skip this server entry, as it has no supported
// protocols after disabling the impaired ones
// TODO: modify ServerEntryIterator to skip these?
continue
}
}
// adjustedEstablishStartTime is establishStartTime shifted
// to exclude time spent waiting for network connectivity.
candidate := &candidateServerEntry{
serverEntry: serverEntry,
isServerAffinityCandidate: isServerAffinityCandidate,
adjustedEstablishStartTime: establishStartTime.Add(networkWaitDuration),
}
// Note: there must be only one server affinity candidate, as it
// closes the serverAffinityDoneBroadcast channel.
isServerAffinityCandidate = false
// TODO: here we could generate multiple candidates from the
//.........這裏部分代碼省略.........
示例15: run
func run(t *testing.T, rateLimits RateLimits) {
// Run a local HTTP server which serves large chunks of data
go func() {
handler := func(w http.ResponseWriter, r *http.Request) {
_, _ = ioutil.ReadAll(r.Body)
testData, _ := MakeSecureRandomBytes(testDataSize)
w.Write(testData)
}
server := &http.Server{
Addr: serverAddress,
Handler: http.HandlerFunc(handler),
}
server.ListenAndServe()
}()
// TODO: properly synchronize with server startup
time.Sleep(1 * time.Second)
// Set up a HTTP client with a throttled connection
throttledDial := func(network, addr string) (net.Conn, error) {
conn, err := net.Dial(network, addr)
if err != nil {
return conn, err
}
return NewThrottledConn(conn, rateLimits), nil
}
client := &http.Client{
Transport: &http.Transport{
Dial: throttledDial,
},
}
// Upload and download a large chunk of data, and time it
testData, _ := MakeSecureRandomBytes(testDataSize)
requestBody := bytes.NewReader(testData)
startTime := monotime.Now()
response, err := client.Post("http://"+serverAddress, "application/octet-stream", requestBody)
if err == nil && response.StatusCode != http.StatusOK {
response.Body.Close()
err = fmt.Errorf("unexpected response code: %d", response.StatusCode)
}
if err != nil {
t.Fatalf("request failed: %s", err)
}
defer response.Body.Close()
// Test: elapsed upload time must reflect rate limit
checkElapsedTime(t, testDataSize, rateLimits.WriteBytesPerSecond, monotime.Since(startTime))
startTime = monotime.Now()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
t.Fatalf("read response failed: %s", err)
}
if len(body) != testDataSize {
t.Fatalf("unexpected response size: %d", len(body))
}
// Test: elapsed download time must reflect rate limit
checkElapsedTime(t, testDataSize, rateLimits.ReadBytesPerSecond, monotime.Since(startTime))
}