func TestBackoff(t *testing.T) { b := net.Backoff{} eq := func(d time.Duration, ms int) { a := int(d / time.Millisecond) if a != ms { t.Errorf("Backoff #%d: %v should be %v", b.CurrentTry, a, ms) } } eq(b.NextDelay(), 5000) eq(b.NextDelay(), 6870) eq(b.NextDelay(), 9440) eq(b.NextDelay(), 12972) eq(b.NextDelay(), 17826) eq(b.NextDelay(), 24494) eq(b.NextDelay(), 33658) eq(b.NextDelay(), 46250) eq(b.NextDelay(), 63553) eq(b.NextDelay(), 87329) eq(b.NextDelay(), 120000) }
func (s *Server) logQueryLoop(logID int64, logURL string, start int64, entryChan chan<- entryBatch) { defer close(entryChan) numPerQuery := int64(10000) backoff := denet.Backoff{} client := ctclient.Client{ LogURL: logURL, } var sth *ctclient.STH ticker := time.NewTicker(2 * time.Minute) defer ticker.Stop() oneTick := make(chan struct{}, 1) oneTick <- struct{}{} var err error for { if atomic.LoadInt32(&s.stopping) != 0 { break } if sth == nil { select { case <-ticker.C: case <-oneTick: case <-s.stopChan: continue } log.Debug("getting STH...") sth, err = client.GetSTH() if err != nil { log.Errore(err, "failed to get STH") backoff.Sleep() continue } } end := start + numPerQuery if end > sth.TreeSize { end = sth.TreeSize } if start >= end { log.Debugf("log %d: at the end", logID) sth = nil continue } log.Debugf("get entries: %#v: (%d,%d)", logURL, start, end-1) entries, numEntries, err := client.GetEntries(start, end-1) if err == nil { backoff.Reset() entryChan <- entryBatch{ Entries: entries, NumEntries: numEntries, StartIndex: start, } start += int64(numEntries) //err := s.processEntries(logID, entries, &start, numEntries) //log.Fatale(err, "update log height") } else { log.Errore(err, "cannot get entries for log: ", logURL) backoff.Sleep() } } log.Debugf("log reader stopped: %#v", logURL) }
// Completes a given challenge, polling it until it is complete. Can be // cancelled using ctx. // // dnsName is the hostname which is being authorized. webPaths and priorKeyFunc // are passed to responders. // // The return value indicates whether the whole authorization has been invalidated // (set to "failed" status) as a result of an error. In this case a new authorization // must be created. func CompleteChallenge(c *acmeapi.Client, ch *acmeapi.Challenge, dnsName string, ccfg responder.ChallengeConfig, ctx context.Context) (invalidated bool, err error) { log.Debugf("attempting challenge type %s", ch.Type) var certs [][]byte for _, c := range ch.Certs { certs = append(certs, c) } r, err := responder.New(responder.Config{ Type: ch.Type, Token: ch.Token, AccountKey: c.AccountKey, Hostname: dnsName, AcceptableCertificates: certs, ChallengeConfig: ccfg, }) if err != nil { log.Debuge(err, "challenge instantiation failed") return false, err } err = r.Start() if err != nil { log.Debuge(err, "challenge start failed") return false, err } defer r.Stop() err = c.RespondToChallenge(ch, r.Validation(), r.ValidationSigningKey(), ctx) if err != nil { return false /* ??? */, err } b := denet.Backoff{ InitialDelay: 5 * time.Second, MaxDelay: 30 * time.Second, } for { log.Debug("waiting to poll challenge") select { case <-ctx.Done(): return true, ctx.Err() case <-r.RequestDetectedChan(): log.Debug("request detected") case <-time.After(b.NextDelay()): } log.Debug("querying challenge status") err := c.WaitLoadChallenge(ch, ctx) if err != nil { return false, err } if ch.Status.Final() { log.Debug("challenge now in final state") break } } if ch.Status != "valid" { return true, fmt.Errorf("challenge failed with status %#v", ch.Status) } return false, nil }