77 "fmt"
88 "net/http"
99 "os"
10+ "sync"
11+ "strings"
1012 "runtime"
1113
1214 _ "net/http/pprof"
@@ -16,56 +18,148 @@ import (
1618)
1719
1820var (
19- configureFile string
20- baseCfg = & baseConfig {}
21- pprofAddr string
2221 pprofEnabled = os .Getenv ("PROFILING" ) != ""
2322)
2423
2524func init () {
2625 gost .SetLogger (& gost.LogLogger {})
2726
27+ // TODO - Generate different certificates for each worker
28+ generateTLSCertificate ()
29+ }
30+
31+ func main () {
32+ var wg sync.WaitGroup
33+ wg .Add (1 ) // Gost must exit if any of the workers exit
34+
35+ // Split os.Args using -- and create a worker with each slice
36+ args := strings .Split (" " + strings .Join (os .Args [1 :], " " ) + " " , " -- " )
37+ if strings .Join (args , "" ) == "" {
38+ // Fix to show gost help if the resulting array is empty
39+ args [0 ] = " "
40+ }
41+ for wid , wargs := range args {
42+ if wargs != "" {
43+ go worker (wid , wargs , & wg )
44+ }
45+ }
46+ wg .Wait ()
47+ }
48+
49+ func worker (id int , args string , wg * sync.WaitGroup ) {
50+ defer wg .Done ()
51+
2852 var (
29- printVersion bool
53+ configureFile string
54+ baseCfg = & baseConfig {}
55+ pprofAddr string
3056 )
3157
32- flag .Var (& baseCfg .route .ChainNodes , "F" , "forward address, can make a forward chain" )
33- flag .Var (& baseCfg .route .ServeNodes , "L" , "listen address, can listen on multiple ports (required)" )
34- flag .StringVar (& configureFile , "C" , "" , "configure file" )
35- flag .BoolVar (& baseCfg .Debug , "D" , false , "enable debug log" )
36- flag .BoolVar (& printVersion , "V" , false , "print version" )
37- if pprofEnabled {
38- flag .StringVar (& pprofAddr , "P" , ":6060" , "profiling HTTP server address" )
39- }
40- flag .Parse ()
58+ init := func () error {
59+ var printVersion bool
60+
61+ wf := flag .NewFlagSet (os .Args [0 ], flag .ExitOnError )
62+
63+ wf .Var (& baseCfg .route .ChainNodes , "F" , "forward address, can make a forward chain" )
64+ wf .Var (& baseCfg .route .ServeNodes , "L" , "listen address, can listen on multiple ports (required)" )
65+ wf .StringVar (& configureFile , "C" , "" , "configure file" )
66+ wf .BoolVar (& baseCfg .Debug , "D" , false , "enable debug log" )
67+ wf .BoolVar (& printVersion , "V" , false , "print version" )
68+
69+ if pprofEnabled {
70+ // Every worker uses a different profiling server by default
71+ wf .StringVar (& pprofAddr , "P" , fmt .Sprintf (":606%d" , id ), "profiling HTTP server address" )
72+ }
73+
74+ wf .Parse (strings .Fields (args ))
75+
76+ if printVersion {
77+ fmt .Fprintf (os .Stdout , "gost %s (%s %s/%s)\n " , gost .Version , runtime .Version (), runtime .GOOS , runtime .GOARCH )
78+ os .Exit (0 )
79+ } else if wf .NFlag () == 0 {
80+ wf .Usage ()
81+ os .Exit (0 )
82+ } else if configureFile != "" {
83+ err := parseBaseConfig (configureFile , baseCfg )
84+ if err != nil {
85+ return err
86+ }
87+ }
4188
42- if printVersion {
43- fmt .Fprintf (os .Stdout , "gost %s (%s %s/%s)\n " ,
44- gost .Version , runtime .Version (), runtime .GOOS , runtime .GOARCH )
45- os .Exit (0 )
89+ if baseCfg .route .ServeNodes .String () == "[]" {
90+ configErrMsg := ""
91+ if configureFile != "" {
92+ configErrMsg = " or ServeNodes inside config file (-C)"
93+ }
94+ fmt .Fprintf (os .Stderr , "\n [!] Error: Missing -L flag%s\n \n " , configErrMsg )
95+ wf .Usage ()
96+ os .Exit (1 )
97+ }
98+
99+ return nil
46100 }
47101
48- if configureFile != "" {
49- _ , err := parseBaseConfig (configureFile )
102+ start := func () error {
103+ // TODO - Make debug worker independent
104+ if ! gost .Debug {
105+ gost .Debug = baseCfg .Debug
106+ }
107+
108+ var routers []router
109+ rts , err := baseCfg .route .GenRouters ()
50110 if err != nil {
51- log .Log (err )
52- os .Exit (1 )
111+ return err
112+ }
113+ routers = append (routers , rts ... )
114+
115+ for _ , route := range baseCfg .Routes {
116+ rts , err := route .GenRouters ()
117+ if err != nil {
118+ return err
119+ }
120+ routers = append (routers , rts ... )
121+ }
122+
123+ if len (routers ) == 0 {
124+ return errors .New ("invalid config" )
53125 }
126+ for i := range routers {
127+ go routers [i ].Serve ()
128+ }
129+
130+ return nil
54131 }
55- if flag .NFlag () == 0 {
56- flag .PrintDefaults ()
57- os .Exit (0 )
132+
133+ main := func () error {
134+ if pprofEnabled {
135+ go func () {
136+ log .Log ("profiling server on" , pprofAddr )
137+ log .Log (http .ListenAndServe (pprofAddr , nil ))
138+ }()
139+ }
140+
141+ err := start ()
142+ return err
58143 }
59- }
60144
61- func main () {
62- if pprofEnabled {
63- go func () {
64- log .Log ("profiling server on" , pprofAddr )
65- log .Log (http .ListenAndServe (pprofAddr , nil ))
66- }()
145+ if err := init (); err != nil {
146+ log .Log (err )
147+ return
148+ }
149+ if err := main (); err != nil {
150+ log .Log (err )
151+ return
67152 }
68153
154+ // Allow local functions to be garbage-collected
155+ init = nil
156+ main = nil
157+ start = nil
158+
159+ select {}
160+ }
161+
162+ func generateTLSCertificate () {
69163 // NOTE: as of 2.6, you can use custom cert/key files to initialize the default certificate.
70164 tlsConfig , err := tlsConfig (defaultCertFile , defaultKeyFile , "" )
71165 if err != nil {
@@ -81,41 +175,5 @@ func main() {
81175 } else {
82176 log .Log ("load TLS certificate files OK" )
83177 }
84-
85178 gost .DefaultTLSConfig = tlsConfig
86-
87- if err := start (); err != nil {
88- log .Log (err )
89- os .Exit (1 )
90- }
91-
92- select {}
93- }
94-
95- func start () error {
96- gost .Debug = baseCfg .Debug
97-
98- var routers []router
99- rts , err := baseCfg .route .GenRouters ()
100- if err != nil {
101- return err
102- }
103- routers = append (routers , rts ... )
104-
105- for _ , route := range baseCfg .Routes {
106- rts , err := route .GenRouters ()
107- if err != nil {
108- return err
109- }
110- routers = append (routers , rts ... )
111- }
112-
113- if len (routers ) == 0 {
114- return errors .New ("invalid config" )
115- }
116- for i := range routers {
117- go routers [i ].Serve ()
118- }
119-
120- return nil
121179}
0 commit comments