Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added a 30s timeout for frpc subcommands to avoid long delays #4359

Merged
merged 1 commit into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@

<h3 align="center">Gold Sponsors</h3>
<!--gold sponsors start-->
<p align="center">
<a href="https://lokal.so/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_lokal.png">
</a>
</p>
<p align="center">
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
Expand Down
5 changes: 0 additions & 5 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP

<h3 align="center">Gold Sponsors</h3>
<!--gold sponsors start-->
<p align="center">
<a href="https://lokal.so/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_lokal.png">
</a>
</p>
<p align="center">
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
Expand Down
3 changes: 3 additions & 0 deletions Release.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
### Features

* Added a new plugin `tls2raw`: Enables TLS termination and forwarding of decrypted raw traffic to local service.
* Added a default timeout of 30 seconds for the frpc subcommands to prevent commands from being stuck for a long time due to network issues.

### Fixes

* Fixed the issue that when `loginFailExit = false`, the frpc stop command cannot be stopped correctly if the server is not successfully connected after startup.
46 changes: 27 additions & 19 deletions cmd/frpc/sub/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
package sub

import (
"context"
"fmt"
"os"
"strings"
"time"

"github.com/rodaine/table"
"github.com/spf13/cobra"
Expand All @@ -27,24 +29,24 @@ import (
clientsdk "github.com/fatedier/frp/pkg/sdk/client"
)

func init() {
rootCmd.AddCommand(NewAdminCommand(
"reload",
"Hot-Reload frpc configuration",
ReloadHandler,
))
var adminAPITimeout = 30 * time.Second

rootCmd.AddCommand(NewAdminCommand(
"status",
"Overview of all proxies status",
StatusHandler,
))
func init() {
commands := []struct {
name string
description string
handler func(*v1.ClientCommonConfig) error
}{
{"reload", "Hot-Reload frpc configuration", ReloadHandler},
{"status", "Overview of all proxies status", StatusHandler},
{"stop", "Stop the running frpc", StopHandler},
}

rootCmd.AddCommand(NewAdminCommand(
"stop",
"Stop the running frpc",
StopHandler,
))
for _, cmdConfig := range commands {
cmd := NewAdminCommand(cmdConfig.name, cmdConfig.description, cmdConfig.handler)
cmd.Flags().DurationVar(&adminAPITimeout, "api-timeout", adminAPITimeout, "Timeout for admin API calls")
rootCmd.AddCommand(cmd)
}
}

func NewAdminCommand(name, short string, handler func(*v1.ClientCommonConfig) error) *cobra.Command {
Expand Down Expand Up @@ -73,7 +75,9 @@ func NewAdminCommand(name, short string, handler func(*v1.ClientCommonConfig) er
func ReloadHandler(clientCfg *v1.ClientCommonConfig) error {
client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port)
client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password)
if err := client.Reload(strictConfigMode); err != nil {
ctx, cancel := context.WithTimeout(context.Background(), adminAPITimeout)
defer cancel()
if err := client.Reload(ctx, strictConfigMode); err != nil {
return err
}
fmt.Println("reload success")
Expand All @@ -83,7 +87,9 @@ func ReloadHandler(clientCfg *v1.ClientCommonConfig) error {
func StatusHandler(clientCfg *v1.ClientCommonConfig) error {
client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port)
client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password)
res, err := client.GetAllProxyStatus()
ctx, cancel := context.WithTimeout(context.Background(), adminAPITimeout)
defer cancel()
res, err := client.GetAllProxyStatus(ctx)
if err != nil {
return err
}
Expand All @@ -109,7 +115,9 @@ func StatusHandler(clientCfg *v1.ClientCommonConfig) error {
func StopHandler(clientCfg *v1.ClientCommonConfig) error {
client := clientsdk.New(clientCfg.WebServer.Addr, clientCfg.WebServer.Port)
client.SetAuth(clientCfg.WebServer.User, clientCfg.WebServer.Password)
if err := client.Stop(); err != nil {
ctx, cancel := context.WithTimeout(context.Background(), adminAPITimeout)
defer cancel()
if err := client.Stop(ctx); err != nil {
return err
}
fmt.Println("stop success")
Expand Down
25 changes: 13 additions & 12 deletions pkg/sdk/client/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"context"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -31,8 +32,8 @@ func (c *Client) SetAuth(user, pwd string) {
c.authPwd = pwd
}

func (c *Client) GetProxyStatus(name string) (*client.ProxyStatusResp, error) {
req, err := http.NewRequest("GET", "http://"+c.address+"/api/status", nil)
func (c *Client) GetProxyStatus(ctx context.Context, name string) (*client.ProxyStatusResp, error) {
req, err := http.NewRequestWithContext(ctx, "GET", "http://"+c.address+"/api/status", nil)
if err != nil {
return nil, err
}
Expand All @@ -54,8 +55,8 @@ func (c *Client) GetProxyStatus(name string) (*client.ProxyStatusResp, error) {
return nil, fmt.Errorf("no proxy status found")
}

func (c *Client) GetAllProxyStatus() (client.StatusResp, error) {
req, err := http.NewRequest("GET", "http://"+c.address+"/api/status", nil)
func (c *Client) GetAllProxyStatus(ctx context.Context) (client.StatusResp, error) {
req, err := http.NewRequestWithContext(ctx, "GET", "http://"+c.address+"/api/status", nil)
if err != nil {
return nil, err
}
Expand All @@ -70,7 +71,7 @@ func (c *Client) GetAllProxyStatus() (client.StatusResp, error) {
return allStatus, nil
}

func (c *Client) Reload(strictMode bool) error {
func (c *Client) Reload(ctx context.Context, strictMode bool) error {
v := url.Values{}
if strictMode {
v.Set("strictConfig", "true")
Expand All @@ -79,33 +80,33 @@ func (c *Client) Reload(strictMode bool) error {
if len(v) > 0 {
queryStr = "?" + v.Encode()
}
req, err := http.NewRequest("GET", "http://"+c.address+"/api/reload"+queryStr, nil)
req, err := http.NewRequestWithContext(ctx, "GET", "http://"+c.address+"/api/reload"+queryStr, nil)
if err != nil {
return err
}
_, err = c.do(req)
return err
}

func (c *Client) Stop() error {
req, err := http.NewRequest("POST", "http://"+c.address+"/api/stop", nil)
func (c *Client) Stop(ctx context.Context) error {
req, err := http.NewRequestWithContext(ctx, "POST", "http://"+c.address+"/api/stop", nil)
if err != nil {
return err
}
_, err = c.do(req)
return err
}

func (c *Client) GetConfig() (string, error) {
req, err := http.NewRequest("GET", "http://"+c.address+"/api/config", nil)
func (c *Client) GetConfig(ctx context.Context) (string, error) {
req, err := http.NewRequestWithContext(ctx, "GET", "http://"+c.address+"/api/config", nil)
if err != nil {
return "", err
}
return c.do(req)
}

func (c *Client) UpdateConfig(content string) error {
req, err := http.NewRequest("PUT", "http://"+c.address+"/api/config", strings.NewReader(content))
func (c *Client) UpdateConfig(ctx context.Context, content string) error {
req, err := http.NewRequestWithContext(ctx, "PUT", "http://"+c.address+"/api/config", strings.NewReader(content))
if err != nil {
return err
}
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 @@ -14,7 +14,7 @@

package version

var version = "0.59.0"
var version = "0.60.0"

func Full() string {
return version
Expand Down
9 changes: 5 additions & 4 deletions test/e2e/legacy/basic/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package basic

import (
"context"
"fmt"
"strconv"
"strings"
Expand Down Expand Up @@ -54,7 +55,7 @@ var _ = ginkgo.Describe("[Feature: ClientManage]", func() {
framework.NewRequestExpect(f).Port(p3Port).Ensure()

client := f.APIClientForFrpc(adminPort)
conf, err := client.GetConfig()
conf, err := client.GetConfig(context.Background())
framework.ExpectNoError(err)

newP2Port := f.AllocPort()
Expand All @@ -65,10 +66,10 @@ var _ = ginkgo.Describe("[Feature: ClientManage]", func() {
newClientConf = newClientConf[:p3Index]
}

err = client.UpdateConfig(newClientConf)
err = client.UpdateConfig(context.Background(), newClientConf)
framework.ExpectNoError(err)

err = client.Reload(true)
err = client.Reload(context.Background(), true)
framework.ExpectNoError(err)
time.Sleep(time.Second)

Expand Down Expand Up @@ -120,7 +121,7 @@ var _ = ginkgo.Describe("[Feature: ClientManage]", func() {
framework.NewRequestExpect(f).Port(testPort).Ensure()

client := f.APIClientForFrpc(adminPort)
err := client.Stop()
err := client.Stop(context.Background())
framework.ExpectNoError(err)

time.Sleep(3 * time.Second)
Expand Down
5 changes: 3 additions & 2 deletions test/e2e/legacy/basic/server.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package basic

import (
"context"
"fmt"
"net"
"strconv"
Expand Down Expand Up @@ -101,7 +102,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() {
client := f.APIClientForFrpc(adminPort)

// tcp random port
status, err := client.GetProxyStatus("tcp")
status, err := client.GetProxyStatus(context.Background(), "tcp")
framework.ExpectNoError(err)

_, portStr, err := net.SplitHostPort(status.RemoteAddr)
Expand All @@ -112,7 +113,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() {
framework.NewRequestExpect(f).Port(port).Ensure()

// udp random port
status, err = client.GetProxyStatus("udp")
status, err = client.GetProxyStatus(context.Background(), "udp")
framework.ExpectNoError(err)

_, portStr, err = net.SplitHostPort(status.RemoteAddr)
Expand Down
9 changes: 5 additions & 4 deletions test/e2e/v1/basic/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package basic

import (
"context"
"fmt"
"strconv"
"strings"
Expand Down Expand Up @@ -57,7 +58,7 @@ var _ = ginkgo.Describe("[Feature: ClientManage]", func() {
framework.NewRequestExpect(f).Port(p3Port).Ensure()

client := f.APIClientForFrpc(adminPort)
conf, err := client.GetConfig()
conf, err := client.GetConfig(context.Background())
framework.ExpectNoError(err)

newP2Port := f.AllocPort()
Expand All @@ -68,10 +69,10 @@ var _ = ginkgo.Describe("[Feature: ClientManage]", func() {
newClientConf = newClientConf[:p3Index]
}

err = client.UpdateConfig(newClientConf)
err = client.UpdateConfig(context.Background(), newClientConf)
framework.ExpectNoError(err)

err = client.Reload(true)
err = client.Reload(context.Background(), true)
framework.ExpectNoError(err)
time.Sleep(time.Second)

Expand Down Expand Up @@ -124,7 +125,7 @@ var _ = ginkgo.Describe("[Feature: ClientManage]", func() {
framework.NewRequestExpect(f).Port(testPort).Ensure()

client := f.APIClientForFrpc(adminPort)
err := client.Stop()
err := client.Stop(context.Background())
framework.ExpectNoError(err)

time.Sleep(3 * time.Second)
Expand Down
3 changes: 2 additions & 1 deletion test/e2e/v1/basic/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package basic

import (
"context"
"fmt"

"github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -72,7 +73,7 @@ var _ = ginkgo.Describe("[Feature: Config]", func() {

client := f.APIClientForFrpc(adminPort)
checkProxyFn := func(name string, localPort, remotePort int) {
status, err := client.GetProxyStatus(name)
status, err := client.GetProxyStatus(context.Background(), name)
framework.ExpectNoError(err)

framework.ExpectContainSubstring(status.LocalAddr, fmt.Sprintf(":%d", localPort))
Expand Down
5 changes: 3 additions & 2 deletions test/e2e/v1/basic/server.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package basic

import (
"context"
"fmt"
"net"
"strconv"
Expand Down Expand Up @@ -112,7 +113,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() {
client := f.APIClientForFrpc(adminPort)

// tcp random port
status, err := client.GetProxyStatus("tcp")
status, err := client.GetProxyStatus(context.Background(), "tcp")
framework.ExpectNoError(err)

_, portStr, err := net.SplitHostPort(status.RemoteAddr)
Expand All @@ -123,7 +124,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() {
framework.NewRequestExpect(f).Port(port).Ensure()

// udp random port
status, err = client.GetProxyStatus("udp")
status, err = client.GetProxyStatus(context.Background(), "udp")
framework.ExpectNoError(err)

_, portStr, err = net.SplitHostPort(status.RemoteAddr)
Expand Down