// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build go1.21

// The interop command is the client and server used by QUIC interoperability tests.
//
// https://github.com/marten-seemann/quic-interop-runner
package main

import (
	"bytes"
	"context"
	"crypto/tls"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"log/slog"
	"net"
	"net/url"
	"os"
	"path/filepath"
	"sync"

	"golang.org/x/net/internal/quic"
	"golang.org/x/net/internal/quic/qlog"
)

var (
	listen  = flag.String("listen", "", "listen address")
	cert    = flag.String("cert", "", "certificate")
	pkey    = flag.String("key", "", "private key")
	root    = flag.String("root", "", "serve files from this root")
	output  = flag.String("output", "", "directory to write files to")
	qlogdir = flag.String("qlog", "", "directory to write qlog output to")
)

func main() {
	ctx := context.Background()
	flag.Parse()
	urls := flag.Args()

	config := &quic.Config{
		TLSConfig: &tls.Config{
			InsecureSkipVerify: true,
			MinVersion:         tls.VersionTLS13,
			NextProtos:         []string{"hq-interop"},
		},
		MaxBidiRemoteStreams: -1,
		MaxUniRemoteStreams:  -1,
		QLogLogger: slog.New(qlog.NewJSONHandler(qlog.HandlerOptions{
			Level: quic.QLogLevelFrame,
			Dir:   *qlogdir,
		})),
	}
	if *cert != "" {
		c, err := tls.LoadX509KeyPair(*cert, *pkey)
		if err != nil {
			log.Fatal(err)
		}
		config.TLSConfig.Certificates = []tls.Certificate{c}
	}
	if *root != "" {
		config.MaxBidiRemoteStreams = 100
	}
	if keylog := os.Getenv("SSLKEYLOGFILE"); keylog != "" {
		f, err := os.Create(keylog)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		config.TLSConfig.KeyLogWriter = f
	}

	testcase := os.Getenv("TESTCASE")
	switch testcase {
	case "handshake", "keyupdate":
		basicTest(ctx, config, urls)
		return
	case "chacha20":
		// "[...] offer only ChaCha20 as a ciphersuite."
		//
		// crypto/tls does not support configuring TLS 1.3 ciphersuites,
		// so we can't support this test.
	case "transfer":
		// "The client should use small initial flow control windows
		// for both stream- and connection-level flow control
		// such that the during the transfer of files on the order of 1 MB
		// the flow control window needs to be increased."
		config.MaxStreamReadBufferSize = 64 << 10
		config.MaxConnReadBufferSize = 64 << 10
		basicTest(ctx, config, urls)
		return
	case "http3":
		// TODO
	case "multiconnect":
		// TODO
	case "resumption":
		// TODO
	case "retry":
		// TODO
	case "versionnegotiation":
		// "The client should start a connection using
		// an unsupported version number [...]"
		//
		// We don't support setting the client's version,
		// so only run this test as a server.
		if *listen != "" && len(urls) == 0 {
			basicTest(ctx, config, urls)
			return
		}
	case "v2":
		// We do not support QUIC v2.
	case "zerortt":
		// TODO
	}
	fmt.Printf("unsupported test case %q\n", testcase)
	os.Exit(127)
}

// basicTest runs the standard test setup.
//
// As a server, it serves the contents of the -root directory.
// As a client, it downloads all the provided URLs in parallel,
// making one connection to each destination server.
func basicTest(ctx context.Context, config *quic.Config, urls []string) {
	l, err := quic.Listen("udp", *listen, config)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("listening on %v", l.LocalAddr())

	byAuthority := map[string][]*url.URL{}
	for _, s := range urls {
		u, addr, err := parseURL(s)
		if err != nil {
			log.Fatal(err)
		}
		byAuthority[addr] = append(byAuthority[addr], u)
	}
	var g sync.WaitGroup
	defer g.Wait()
	for addr, u := range byAuthority {
		addr, u := addr, u
		g.Add(1)
		go func() {
			defer g.Done()
			fetchFrom(ctx, l, addr, u)
		}()
	}

	if config.MaxBidiRemoteStreams >= 0 {
		serve(ctx, l)
	}
}

func serve(ctx context.Context, l *quic.Endpoint) error {
	for {
		c, err := l.Accept(ctx)
		if err != nil {
			return err
		}
		go serveConn(ctx, c)
	}
}

func serveConn(ctx context.Context, c *quic.Conn) {
	for {
		s, err := c.AcceptStream(ctx)
		if err != nil {
			return
		}
		go func() {
			if err := serveReq(ctx, s); err != nil {
				log.Print("serveReq:", err)
			}
		}()
	}
}

func serveReq(ctx context.Context, s *quic.Stream) error {
	defer s.Close()
	req, err := io.ReadAll(s)
	if err != nil {
		return err
	}
	if !bytes.HasSuffix(req, []byte("\r\n")) {
		return errors.New("invalid request")
	}
	req = bytes.TrimSuffix(req, []byte("\r\n"))
	if !bytes.HasPrefix(req, []byte("GET /")) {
		return errors.New("invalid request")
	}
	req = bytes.TrimPrefix(req, []byte("GET /"))
	if !filepath.IsLocal(string(req)) {
		return errors.New("invalid request")
	}
	f, err := os.Open(filepath.Join(*root, string(req)))
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = io.Copy(s, f)
	return err
}

func parseURL(s string) (u *url.URL, authority string, err error) {
	u, err = url.Parse(s)
	if err != nil {
		return nil, "", err
	}
	host := u.Hostname()
	port := u.Port()
	if port == "" {
		port = "443"
	}
	authority = net.JoinHostPort(host, port)
	return u, authority, nil
}

func fetchFrom(ctx context.Context, l *quic.Endpoint, addr string, urls []*url.URL) {
	conn, err := l.Dial(ctx, "udp", addr)
	if err != nil {
		log.Printf("%v: %v", addr, err)
		return
	}
	log.Printf("connected to %v", addr)
	defer conn.Close()
	var g sync.WaitGroup
	for _, u := range urls {
		u := u
		g.Add(1)
		go func() {
			defer g.Done()
			if err := fetchOne(ctx, conn, u); err != nil {
				log.Printf("fetch %v: %v", u, err)
			} else {
				log.Printf("fetched %v", u)
			}
		}()
	}
	g.Wait()
}

func fetchOne(ctx context.Context, conn *quic.Conn, u *url.URL) error {
	if len(u.Path) == 0 || u.Path[0] != '/' || !filepath.IsLocal(u.Path[1:]) {
		return errors.New("invalid path")
	}
	file, err := os.Create(filepath.Join(*output, u.Path[1:]))
	if err != nil {
		return err
	}
	s, err := conn.NewStream(ctx)
	if err != nil {
		return err
	}
	defer s.Close()
	if _, err := s.Write([]byte("GET " + u.Path + "\r\n")); err != nil {
		return err
	}
	s.CloseWrite()
	if _, err := io.Copy(file, s); err != nil {
		return err
	}
	return nil
}
