mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 13:05:22 +00:00 
			
		
		
		
	control/controlclient, tailcfg: add Debug.SleepSeconds (mapver 19)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
		| @@ -570,6 +570,11 @@ func (c *Direct) SendLiteMapUpdate(ctx context.Context) error { | |||||||
| 	return c.sendMapRequest(ctx, 1, nil) | 	return c.sendMapRequest(ctx, 1, nil) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // If we go more than pollTimeout without hearing from the server, | ||||||
|  | // end the long poll. We should be receiving a keep alive ping | ||||||
|  | // every minute. | ||||||
|  | const pollTimeout = 120 * time.Second | ||||||
|  |  | ||||||
| // cb nil means to omit peers. | // cb nil means to omit peers. | ||||||
| func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netmap.NetworkMap)) error { | func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netmap.NetworkMap)) error { | ||||||
| 	c.mu.Lock() | 	c.mu.Lock() | ||||||
| @@ -694,10 +699,6 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netm | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// If we go more than pollTimeout without hearing from the server, |  | ||||||
| 	// end the long poll. We should be receiving a keep alive ping |  | ||||||
| 	// every minute. |  | ||||||
| 	const pollTimeout = 120 * time.Second |  | ||||||
| 	timeout := time.NewTimer(pollTimeout) | 	timeout := time.NewTimer(pollTimeout) | ||||||
| 	timeoutReset := make(chan struct{}) | 	timeoutReset := make(chan struct{}) | ||||||
| 	pollDone := make(chan struct{}) | 	pollDone := make(chan struct{}) | ||||||
| @@ -795,6 +796,11 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netm | |||||||
| 			} | 			} | ||||||
| 			setControlAtomic(&controlUseDERPRoute, resp.Debug.DERPRoute) | 			setControlAtomic(&controlUseDERPRoute, resp.Debug.DERPRoute) | ||||||
| 			setControlAtomic(&controlTrimWGConfig, resp.Debug.TrimWGConfig) | 			setControlAtomic(&controlTrimWGConfig, resp.Debug.TrimWGConfig) | ||||||
|  | 			if sleep := time.Duration(resp.Debug.SleepSeconds * float64(time.Second)); sleep > 0 { | ||||||
|  | 				if err := sleepAsRequested(ctx, c.logf, timeoutReset, sleep); err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		nm := sess.netmapForResponse(&resp) | 		nm := sess.netmapForResponse(&resp) | ||||||
| @@ -1181,3 +1187,34 @@ func answerPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest) { | |||||||
| 		logf("answerPing complete to %v (after %v)", pr.URL, d) | 		logf("answerPing complete to %v (after %v)", pr.URL, d) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func sleepAsRequested(ctx context.Context, logf logger.Logf, timeoutReset chan<- struct{}, d time.Duration) error { | ||||||
|  | 	const maxSleep = 5 * time.Minute | ||||||
|  | 	if d > maxSleep { | ||||||
|  | 		logf("sleeping for %v, capped from server-requested %v ...", maxSleep, d) | ||||||
|  | 		d = maxSleep | ||||||
|  | 	} else { | ||||||
|  | 		logf("sleeping for server-requested %v ...", d) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ticker := time.NewTicker(pollTimeout / 2) | ||||||
|  | 	defer ticker.Stop() | ||||||
|  | 	timer := time.NewTimer(d) | ||||||
|  | 	defer timer.Stop() | ||||||
|  | 	for { | ||||||
|  | 		select { | ||||||
|  | 		case <-ctx.Done(): | ||||||
|  | 			return ctx.Err() | ||||||
|  | 		case <-timer.C: | ||||||
|  | 			return nil | ||||||
|  | 		case <-ticker.C: | ||||||
|  | 			select { | ||||||
|  | 			case timeoutReset <- struct{}{}: | ||||||
|  | 			case <-timer.C: | ||||||
|  | 				return nil | ||||||
|  | 			case <-ctx.Done(): | ||||||
|  | 				return ctx.Err() | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -41,7 +41,8 @@ import ( | |||||||
| //    16: 2021-04-15: client understands Node.Online, MapResponse.OnlineChange | //    16: 2021-04-15: client understands Node.Online, MapResponse.OnlineChange | ||||||
| //    17: 2021-04-18: MapResponse.Domain empty means unchanged | //    17: 2021-04-18: MapResponse.Domain empty means unchanged | ||||||
| //    18: 2021-04-19: MapResponse.Node nil means unchanged (all fields now omitempty) | //    18: 2021-04-19: MapResponse.Node nil means unchanged (all fields now omitempty) | ||||||
| const CurrentMapRequestVersion = 18 | //    19: 2021-04-21: MapResponse.Debug.SleepSeconds | ||||||
|  | const CurrentMapRequestVersion = 19 | ||||||
|  |  | ||||||
| type StableID string | type StableID string | ||||||
|  |  | ||||||
| @@ -1012,6 +1013,12 @@ type Debug struct { | |||||||
| 	// GoroutineDumpURL, if non-empty, requests that the client do | 	// GoroutineDumpURL, if non-empty, requests that the client do | ||||||
| 	// a one-time dump of its active goroutines to the given URL. | 	// a one-time dump of its active goroutines to the given URL. | ||||||
| 	GoroutineDumpURL string `json:",omitempty"` | 	GoroutineDumpURL string `json:",omitempty"` | ||||||
|  |  | ||||||
|  | 	// SleepSeconds requests that the client sleep for the | ||||||
|  | 	// provided number of seconds. | ||||||
|  | 	// The client can (and should) limit the value (such as 5 | ||||||
|  | 	// minutes). | ||||||
|  | 	SleepSeconds float64 `json:",omitempty"` | ||||||
| } | } | ||||||
|  |  | ||||||
| func (k MachineKey) String() string                   { return fmt.Sprintf("mkey:%x", k[:]) } | func (k MachineKey) String() string                   { return fmt.Sprintf("mkey:%x", k[:]) } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Brad Fitzpatrick
					Brad Fitzpatrick