Skip to content

Commit

Permalink
Merge pull request #3878 from fatedier/dev
Browse files Browse the repository at this point in the history
bump version
  • Loading branch information
fatedier authored Dec 21, 2023
2 parents 051299e + 5e77c8e commit 2b83436
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 47 deletions.
5 changes: 1 addition & 4 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
### Summary

copilot:summary

### WHY

<!-- author to complete -->
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ issues:
- linters:
- revive
text: "unused-parameter"
- linters:
- unparam
text: "is always false"

# Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all
Expand Down
10 changes: 1 addition & 9 deletions Release.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
### Features

* The new command line parameter `--strict_config` has been added to enable strict configuration validation mode. It will throw an error for unknown fields instead of ignoring them. In future versions, we will set the default value of this parameter to true to avoid misconfigurations.
* Support `SSH reverse tunneling`. With this feature, you can expose your local service without running frpc, only using SSH. The SSH reverse tunnel agent has many functional limitations compared to the frpc agent. The currently supported proxy types are tcp, http, https, tcpmux, and stcp.
* The frpc tcpmux command line parameters have been updated to support configuring `http_user` and `http_pwd`.
* The frpc stcp/sudp/xtcp command line parameters have been updated to support configuring `allow_users`.

### Fixes

* frpc: Return code 1 when the first login attempt fails and exits.
* When auth.method is `oidc` and auth.additionalScopes contains `HeartBeats`, if obtaining AccessToken fails, the application will be unresponsive.
* frpc has a certain chance to panic when login: close of closed channel.
6 changes: 3 additions & 3 deletions client/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,15 @@ func (ctl *Control) heartbeatWorker() {
// Users can still enable heartbeat feature by setting HeartbeatInterval to a positive value.
if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 {
// send heartbeat to server
sendHeartBeat := func() error {
sendHeartBeat := func() (bool, error) {
xl.Debug("send heartbeat to server")
pingMsg := &msg.Ping{}
if err := ctl.sessionCtx.AuthSetter.SetPing(pingMsg); err != nil {
xl.Warn("error during ping authentication: %v, skip sending ping message", err)
return err
return false, err
}
_ = ctl.msgDispatcher.Send(pingMsg)
return nil
return false, nil
}

go wait.BackoffUntil(sendHeartBeat,
Expand Down
23 changes: 9 additions & 14 deletions client/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,16 +192,16 @@ func (svr *Service) keepControllerWorking() {
// the control immediately exits. It is necessary to limit the frequency of reconnection in this case.
// The interval for the first three retries in 1 minute will be very short, and then it will increase exponentially.
// The maximum interval is 20 seconds.
wait.BackoffUntil(func() error {
wait.BackoffUntil(func() (bool, error) {
// loopLoginUntilSuccess is another layer of loop that will continuously attempt to
// login to the server until successful.
svr.loopLoginUntilSuccess(20*time.Second, false)
if svr.ctl != nil {
<-svr.ctl.Done()
return errors.New("control is closed and try another loop")
return false, errors.New("control is closed and try another loop")
}
// If the control is nil, it means that the login failed and the service is also closed.
return nil
return false, nil
}, wait.NewFastBackoffManager(
wait.FastBackoffOptions{
Duration: time.Second,
Expand Down Expand Up @@ -282,17 +282,16 @@ func (svr *Service) login() (conn net.Conn, connector Connector, err error) {

func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginExit bool) {
xl := xlog.FromContextSafe(svr.ctx)
successCh := make(chan struct{})

loginFunc := func() error {
loginFunc := func() (bool, error) {
xl.Info("try to connect to server...")
conn, connector, err := svr.login()
if err != nil {
xl.Warn("connect to server error: %v", err)
if firstLoginExit {
svr.cancel(cancelErr{Err: err})
}
return err
return false, err
}

svr.cfgMu.RLock()
Expand All @@ -315,7 +314,7 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE
if err != nil {
conn.Close()
xl.Error("NewControl error: %v", err)
return err
return false, err
}
ctl.SetInWorkConnCallback(svr.handleWorkConnCb)

Expand All @@ -327,21 +326,17 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE
}
svr.ctl = ctl
svr.ctlMu.Unlock()

close(successCh)
return nil
return true, nil
}

// try to reconnect to server until success
wait.BackoffUntil(loginFunc, wait.NewFastBackoffManager(
wait.FastBackoffOptions{
Duration: time.Second,
Duration: time.Millisecond,
Factor: 2,
Jitter: 0.1,
MaxDuration: maxInterval,
}),
true,
wait.MergeAndCloseOnAnyStopChannel(svr.ctx.Done(), successCh))
}), true, svr.ctx.Done())
}

func (svr *Service) UpdateAllConfigurer(proxyCfgs []v1.ProxyConfigurer, visitorCfgs []v1.VisitorConfigurer) error {
Expand Down
2 changes: 1 addition & 1 deletion pkg/util/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"strings"
)

var version = "0.53.0"
var version = "0.53.1"

func Full() string {
return version
Expand Down
29 changes: 13 additions & 16 deletions pkg/util/wait/backoff.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ package wait

import (
"math/rand"
"sync"
"time"

"github.com/samber/lo"

"github.com/fatedier/frp/pkg/util/util"
)

Expand Down Expand Up @@ -114,7 +113,7 @@ func (f *fastBackoffImpl) Backoff(previousDuration time.Duration, previousCondit
return f.options.Duration
}

func BackoffUntil(f func() error, backoff BackoffManager, sliding bool, stopCh <-chan struct{}) {
func BackoffUntil(f func() (bool, error), backoff BackoffManager, sliding bool, stopCh <-chan struct{}) {
var delay time.Duration
previousError := false

Expand All @@ -132,7 +131,9 @@ func BackoffUntil(f func() error, backoff BackoffManager, sliding bool, stopCh <
delay = backoff.Backoff(delay, previousError)
}

if err := f(); err != nil {
if done, err := f(); done {
return
} else if err != nil {
previousError = true
} else {
previousError = false
Expand All @@ -143,12 +144,6 @@ func BackoffUntil(f func() error, backoff BackoffManager, sliding bool, stopCh <
}

ticker.Reset(delay)
select {
case <-stopCh:
return
default:
}

select {
case <-stopCh:
return
Expand All @@ -171,9 +166,9 @@ func Jitter(duration time.Duration, maxFactor float64) time.Duration {
}

func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
ff := func() error {
ff := func() (bool, error) {
f()
return nil
return false, nil
}
BackoffUntil(ff, BackoffFunc(func(time.Duration, bool) time.Duration {
return period
Expand All @@ -182,16 +177,18 @@ func Until(f func(), period time.Duration, stopCh <-chan struct{}) {

func MergeAndCloseOnAnyStopChannel[T any](upstreams ...<-chan T) <-chan T {
out := make(chan T)

closeOnce := sync.Once{}
for _, upstream := range upstreams {
ch := upstream
go lo.Try0(func() {
go func() {
select {
case <-ch:
close(out)
closeOnce.Do(func() {
close(out)
})
case <-out:
}
})
}()
}
return out
}

0 comments on commit 2b83436

Please sign in to comment.