Skip to content

Commit

Permalink
Merge branch 'master' into 412-upstream-validation
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Aug 16, 2024
2 parents 9fdb436 + 48ef185 commit 18ed578
Show file tree
Hide file tree
Showing 14 changed files with 1,280 additions and 1,112 deletions.
161 changes: 161 additions & 0 deletions internal/cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// Package cmd is the dnsproxy CLI entry point.
package cmd

import (
"context"
"fmt"
"log/slog"
"net/http"
"net/http/pprof"
"os"
"os/signal"
"syscall"
"time"

"github.com/AdguardTeam/dnsproxy/internal/version"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/osutil"
)

// Main is the entrypoint of dnsproxy CLI. Main may accept arguments, such as
// embedded assets and command-line arguments.
func Main() {
opts, exitCode, err := parseOptions()
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
}

if opts == nil {
os.Exit(exitCode)
}

logOutput := os.Stdout
if opts.LogOutput != "" {
// #nosec G302 -- Trust the file path that is given in the
// configuration.
logOutput, err = os.OpenFile(opts.LogOutput, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644)
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, fmt.Errorf("cannot create a log file: %s", err))

os.Exit(osutil.ExitCodeArgumentError)
}

defer func() { _ = logOutput.Close() }()
}

l := slogutil.New(&slogutil.Config{
Output: logOutput,
Format: slogutil.FormatDefault,
// TODO(d.kolyshev): Consider making configurable.
AddTimestamp: true,
Verbose: opts.Verbose,
})

ctx := context.Background()

if opts.Pprof {
runPprof(l)
}

err = runProxy(ctx, l, opts)
if err != nil {
l.ErrorContext(ctx, "running dnsproxy", slogutil.KeyError, err)

// As defers are skipped in case of os.Exit, close logOutput manually.
//
// TODO(a.garipov): Consider making logger.Close method.
if logOutput != os.Stdout {
_ = logOutput.Close()
}

os.Exit(osutil.ExitCodeFailure)
}
}

// runProxy starts and runs the proxy. l must not be nil.
//
// TODO(e.burkov): Move into separate dnssvc package.
func runProxy(ctx context.Context, l *slog.Logger, options *Options) (err error) {
var (
buildVersion = version.Version()
revision = version.Revision()
branch = version.Branch()
commitTime = version.CommitTime()
)

l.InfoContext(
ctx,
"dnsproxy starting",
"version", buildVersion,
"revision", revision,
"branch", branch,
"commit_time", commitTime,
)

// Prepare the proxy server and its configuration.
conf, err := createProxyConfig(ctx, l, options)
if err != nil {
return fmt.Errorf("configuring proxy: %w", err)
}

dnsProxy, err := proxy.New(conf)
if err != nil {
return fmt.Errorf("creating proxy: %w", err)
}

// Start the proxy server.
err = dnsProxy.Start(ctx)
if err != nil {
return fmt.Errorf("starting dnsproxy: %w", err)
}

// TODO(e.burkov): Use [service.SignalHandler].
signalChannel := make(chan os.Signal, 1)
signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM)
<-signalChannel

// Stopping the proxy.
err = dnsProxy.Shutdown(ctx)
if err != nil {
return fmt.Errorf("stopping dnsproxy: %w", err)
}

return nil
}

// runPprof runs pprof server on localhost:6060.
//
// TODO(e.burkov): Use [httputil.RoutePprof].
func runPprof(l *slog.Logger) {
mux := http.NewServeMux()
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
mux.Handle("/debug/pprof/allocs", pprof.Handler("allocs"))
mux.Handle("/debug/pprof/block", pprof.Handler("block"))
mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
mux.Handle("/debug/pprof/mutex", pprof.Handler("mutex"))
mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))

go func() {
// TODO(d.kolyshev): Consider making configurable.
pprofAddr := "localhost:6060"
l.Info("starting pprof", "addr", pprofAddr)

srv := &http.Server{
Addr: pprofAddr,
ReadTimeout: 60 * time.Second,
Handler: mux,
}

err := srv.ListenAndServe()
if err != nil && !errors.Is(err, http.ErrServerClosed) {
l.Error("pprof failed to listen %v", "addr", pprofAddr, slogutil.KeyError, err)
}
}()
}
Loading

0 comments on commit 18ed578

Please sign in to comment.