From 1a1a9a63a1d1add608220623f9c4e487dc034e74 Mon Sep 17 00:00:00 2001 From: JordiSubira Date: Wed, 17 May 2023 12:55:33 +0200 Subject: [PATCH] after rebasing --- dispatcher/cmd/dispatcher/main.go | 178 ------ dispatcher/cmd/dispatcher/main_test.go | 487 -------------- dispatcher/dispatcher.go | 286 --------- .../internal/registration/bench_test.go | 109 ---- .../internal/registration/iatable_test.go | 172 ----- .../internal/registration/scmp_table_test.go | 67 -- dispatcher/mgmtapi/BUILD.bazel | 36 -- dispatcher/mgmtapi/client.gen.go | 594 ------------------ dispatcher/mgmtapi/server.gen.go | 225 ------- dispatcher/mgmtapi/spec.go | 51 -- dispatcher/mgmtapi/types.gen.go | 32 - private/svc/resolver_test.go | 1 + 12 files changed, 1 insertion(+), 2237 deletions(-) delete mode 100644 dispatcher/cmd/dispatcher/main.go delete mode 100644 dispatcher/cmd/dispatcher/main_test.go delete mode 100644 dispatcher/dispatcher.go delete mode 100644 dispatcher/internal/registration/bench_test.go delete mode 100644 dispatcher/internal/registration/iatable_test.go delete mode 100644 dispatcher/internal/registration/scmp_table_test.go delete mode 100644 dispatcher/mgmtapi/BUILD.bazel delete mode 100644 dispatcher/mgmtapi/client.gen.go delete mode 100644 dispatcher/mgmtapi/server.gen.go delete mode 100644 dispatcher/mgmtapi/spec.go delete mode 100644 dispatcher/mgmtapi/types.gen.go diff --git a/dispatcher/cmd/dispatcher/main.go b/dispatcher/cmd/dispatcher/main.go deleted file mode 100644 index ab26beac30..0000000000 --- a/dispatcher/cmd/dispatcher/main.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2018 ETH Zurich -// Copyright 2019 ETH Zurich, Anapaya Systems -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "errors" - "fmt" - "net" - "net/http" - _ "net/http/pprof" - "os" - - "github.com/go-chi/chi/v5" - "github.com/go-chi/cors" - "golang.org/x/sync/errgroup" - - "github.com/scionproto/scion/dispatcher/config" - api "github.com/scionproto/scion/dispatcher/mgmtapi" - "github.com/scionproto/scion/dispatcher/network" - "github.com/scionproto/scion/pkg/log" - "github.com/scionproto/scion/pkg/private/serrors" - "github.com/scionproto/scion/pkg/private/util" - "github.com/scionproto/scion/pkg/slayers/path" - "github.com/scionproto/scion/private/app" - "github.com/scionproto/scion/private/app/launcher" - "github.com/scionproto/scion/private/service" -) - -var globalCfg config.Config - -func main() { - application := launcher.Application{ - TOMLConfig: &globalCfg, - ShortName: "SCION Dispatcher", - RequiredIPs: requiredIPs, - Main: realMain, - } - application.Run() -} - -func realMain(ctx context.Context) error { - if err := util.CreateParentDirs(globalCfg.Dispatcher.ApplicationSocket); err != nil { - return serrors.WrapStr("creating directory tree for socket", err) - } - - path.StrictDecoding(false) - - var cleanup app.Cleanup - g, errCtx := errgroup.WithContext(ctx) - g.Go(func() error { - defer log.HandlePanic() - return RunDispatcher( - globalCfg.Dispatcher.DeleteSocket, - globalCfg.Dispatcher.ApplicationSocket, - os.FileMode(globalCfg.Dispatcher.SocketFileMode), - globalCfg.Dispatcher.UnderlayPort, - ) - }) - - // Initialise and start service management API endpoints. - if globalCfg.API.Addr != "" { - r := chi.NewRouter() - r.Use(cors.Handler(cors.Options{ - AllowedOrigins: []string{"*"}, - })) - r.Get("/", api.ServeSpecInteractive) - r.Get("/openapi.json", api.ServeSpecJSON) - server := api.Server{ - Config: service.NewConfigStatusPage(globalCfg).Handler, - Info: service.NewInfoStatusPage().Handler, - LogLevel: service.NewLogLevelStatusPage().Handler, - } - log.Info("Exposing API", "addr", globalCfg.API.Addr) - h := api.HandlerFromMuxWithBaseURL(&server, r, "/api/v1") - mgmtServer := &http.Server{ - Addr: globalCfg.API.Addr, - Handler: h, - } - cleanup.Add(mgmtServer.Close) - g.Go(func() error { - defer log.HandlePanic() - err := mgmtServer.ListenAndServe() - if err != nil && !errors.Is(err, http.ErrServerClosed) { - return serrors.WrapStr("serving service management API", err) - } - return nil - }) - } - - // Start HTTP endpoints. - statusPages := service.StatusPages{ - "info": service.NewInfoStatusPage(), - "config": service.NewConfigStatusPage(globalCfg), - "log/level": service.NewLogLevelStatusPage(), - } - if err := statusPages.Register(http.DefaultServeMux, globalCfg.Dispatcher.ID); err != nil { - return serrors.WrapStr("registering status pages", err) - } - - g.Go(func() error { - defer log.HandlePanic() - return globalCfg.Metrics.ServePrometheus(errCtx) - }) - - defer func() { - if err := deleteSocket(globalCfg.Dispatcher.ApplicationSocket); err != nil { - log.Error("deleting socket", "err", err) - } - }() - - g.Go(func() error { - defer log.HandlePanic() - <-errCtx.Done() - return cleanup.Do() - }) - - // XXX(lukedirtwalker): unfortunately the dispatcher can't be signalled to - // be stopped, so we just exit manually if the context is done. - select { - case <-ctx.Done(): - return nil - case <-errCtx.Done(): - return g.Wait() - } -} - -func RunDispatcher(deleteSocketFlag bool, applicationSocket string, socketFileMode os.FileMode, - underlayPort int) error { - - if deleteSocketFlag { - if err := deleteSocket(globalCfg.Dispatcher.ApplicationSocket); err != nil { - return err - } - } - dispatcher := &network.Dispatcher{ - UnderlaySocket: fmt.Sprintf(":%d", underlayPort), - ApplicationSocket: applicationSocket, - SocketFileMode: socketFileMode, - } - log.Debug("Dispatcher starting", "appSocket", applicationSocket, "underlayPort", underlayPort) - return dispatcher.ListenAndServe() -} - -func deleteSocket(socket string) error { - if _, err := os.Stat(socket); err != nil { - // File does not exist, or we can't read it, nothing to delete - return nil - } - if err := os.Remove(socket); err != nil { - return err - } - return nil -} - -func requiredIPs() ([]net.IP, error) { - if globalCfg.Metrics.Prometheus == "" { - return nil, nil - } - promAddr, err := net.ResolveTCPAddr("tcp", globalCfg.Metrics.Prometheus) - if err != nil { - return nil, serrors.WrapStr("parsing prometheus address", err) - } - return []net.IP{promAddr.IP}, nil -} diff --git a/dispatcher/cmd/dispatcher/main_test.go b/dispatcher/cmd/dispatcher/main_test.go deleted file mode 100644 index d3c4023d66..0000000000 --- a/dispatcher/cmd/dispatcher/main_test.go +++ /dev/null @@ -1,487 +0,0 @@ -// Copyright 2018 ETH Zurich -// Copyright 2019 ETH Zurich, Anapaya Systems -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "fmt" - "net" - "os" - "path/filepath" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/scionproto/scion/pkg/addr" - "github.com/scionproto/scion/pkg/private/xtest" - "github.com/scionproto/scion/pkg/snet" - "github.com/scionproto/scion/pkg/snet/path" - "github.com/scionproto/scion/pkg/sock/reliable" -) - -const ( - defaultTimeout = 2 * time.Second - defaultWaitDuration = 200 * time.Millisecond -) - -type TestSettings struct { - ApplicationSocket string - UnderlayPort int -} - -func InitTestSettings(t *testing.T, dispatcherTestPort int) *TestSettings { - socketName, err := getSocketName("/tmp") - if err != nil { - t.Fatal(err) - } - return &TestSettings{ - ApplicationSocket: socketName, - UnderlayPort: dispatcherTestPort, - } -} - -func getSocketName(dir string) (string, error) { - dir, err := os.MkdirTemp(dir, "dispatcher") - if err != nil { - return "", err - } - return filepath.Join(dir, "server.sock"), nil -} - -type ClientAddress struct { - IA addr.IA - PublicAddress addr.HostAddr - PublicPort uint16 - ServiceAddress addr.HostSVC - UnderlayAddress *net.UDPAddr - UnderlayPort uint16 -} - -type TestCase struct { - Name string - ClientAddress *ClientAddress - TestPackets []*snet.Packet - UnderlayAddress *net.UDPAddr - ExpectedPacket *snet.Packet -} - -func genTestCases(dispatcherPort int) []*TestCase { - // Addressing information - var ( - commonIA = xtest.MustParseIA("1-ff00:0:1") - commonPublicL3Address = addr.HostFromIP(net.IP{127, 0, 0, 1}) - commonUnderlayAddress = &net.UDPAddr{IP: net.IP{127, 0, 0, 1}, Port: dispatcherPort} - clientXAddress = &ClientAddress{ - IA: commonIA, - PublicAddress: commonPublicL3Address, - PublicPort: 8080, - ServiceAddress: addr.SvcNone, - UnderlayAddress: commonUnderlayAddress, - } - clientYAddress = &ClientAddress{ - IA: commonIA, - PublicAddress: commonPublicL3Address, - PublicPort: 8081, - ServiceAddress: addr.SvcCS, - UnderlayAddress: commonUnderlayAddress, - } - ) - - var testCases = []*TestCase{ - { - Name: "UDP/IPv4 packet", - ClientAddress: clientXAddress, - TestPackets: []*snet.Packet{ - { - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.UDPPayload{ - SrcPort: clientXAddress.PublicPort, - DstPort: clientXAddress.PublicPort, - Payload: []byte{1, 2, 3, 4}, - }, - Path: path.Empty{}, - }, - }, - }, - UnderlayAddress: clientXAddress.UnderlayAddress, - ExpectedPacket: &snet.Packet{ - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.UDPPayload{ - SrcPort: clientXAddress.PublicPort, - DstPort: clientXAddress.PublicPort, - Payload: []byte{1, 2, 3, 4}, - }, - Path: snet.RawPath{}, - }, - }, - }, - { - Name: "UDP/SVC packet", - ClientAddress: clientYAddress, - TestPackets: []*snet.Packet{ - { - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientYAddress.IA, - Host: clientYAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientYAddress.IA, - Host: clientYAddress.ServiceAddress, - }, - Payload: snet.UDPPayload{ - SrcPort: clientYAddress.PublicPort, - DstPort: clientYAddress.PublicPort, - Payload: []byte{5, 6, 7, 8}, - }, - Path: path.Empty{}, - }, - }, - }, - UnderlayAddress: clientXAddress.UnderlayAddress, - ExpectedPacket: &snet.Packet{ - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientYAddress.IA, - Host: clientYAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientYAddress.IA, - Host: clientYAddress.ServiceAddress, - }, - Payload: snet.UDPPayload{ - SrcPort: clientYAddress.PublicPort, - DstPort: clientYAddress.PublicPort, - Payload: []byte{5, 6, 7, 8}, - }, - Path: snet.RawPath{}, - }, - }, - }, - { - Name: "SCMP::Error, UDP quote", - ClientAddress: clientXAddress, - UnderlayAddress: clientXAddress.UnderlayAddress, - TestPackets: []*snet.Packet{ - { - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.SCMPDestinationUnreachable{ - Payload: MustPack(snet.Packet{ - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.UDPPayload{SrcPort: clientXAddress.PublicPort}, - Path: path.Empty{}, - }, - }), - }, - Path: path.Empty{}, - }, - }, - }, - ExpectedPacket: &snet.Packet{ - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.SCMPDestinationUnreachable{ - Payload: MustPack(snet.Packet{ - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.UDPPayload{SrcPort: clientXAddress.PublicPort}, - Path: path.Empty{}, - }, - }), - }, - Path: snet.RawPath{}, - }, - }, - }, - { - Name: "SCMP::Error, SCMP quote", - ClientAddress: clientXAddress, - UnderlayAddress: clientXAddress.UnderlayAddress, - TestPackets: []*snet.Packet{ - { - // Force a SCMP General ID registration to happen, but route it - // from nowhere so we don't get it back - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: xtest.MustParseIA("1-ff00:0:42"), // middle of nowhere - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientYAddress.IA, - Host: clientYAddress.PublicAddress, - }, - Payload: snet.SCMPEchoRequest{Identifier: 0xdead}, - Path: path.Empty{}, - }, - }, - { - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.SCMPDestinationUnreachable{ - Payload: MustPack(snet.Packet{ - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.SCMPEchoRequest{Identifier: 0xdead}, - Path: path.Empty{}, - }, - }), - }, - Path: path.Empty{}, - }, - }, - }, - ExpectedPacket: &snet.Packet{ - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.SCMPDestinationUnreachable{ - Payload: MustPack(snet.Packet{ - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.SCMPEchoRequest{Identifier: 0xdead}, - Path: path.Empty{}, - }, - }), - }, - Path: snet.RawPath{}, - }, - }, - }, - { - Name: "SCMP::General::EchoRequest", - ClientAddress: clientXAddress, - UnderlayAddress: clientYAddress.UnderlayAddress, - TestPackets: []*snet.Packet{ - { - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientYAddress.IA, - Host: clientYAddress.PublicAddress, - }, - Payload: snet.SCMPEchoRequest{ - Identifier: 0xdead, - SeqNumber: 0xcafe, - Payload: []byte("hello?"), - }, - Path: path.Empty{}, - }, - }, - }, - ExpectedPacket: &snet.Packet{ - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientYAddress.IA, - Host: clientYAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.SCMPEchoReply{ - Identifier: 0xdead, - SeqNumber: 0xcafe, - Payload: []byte("hello?"), - }, - Path: snet.RawPath{}, - }, - }, - }, - { - Name: "SCMP::General::TraceRouteRequest", - ClientAddress: clientXAddress, - UnderlayAddress: clientYAddress.UnderlayAddress, - TestPackets: []*snet.Packet{ - { - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientYAddress.IA, - Host: clientYAddress.PublicAddress, - }, - Payload: snet.SCMPTracerouteRequest{Identifier: 0xdeaf, Sequence: 0xcafd}, - Path: path.Empty{}, - }, - }, - }, - ExpectedPacket: &snet.Packet{ - PacketInfo: snet.PacketInfo{ - Source: snet.SCIONAddress{ - IA: clientYAddress.IA, - Host: clientYAddress.PublicAddress, - }, - Destination: snet.SCIONAddress{ - IA: clientXAddress.IA, - Host: clientXAddress.PublicAddress, - }, - Payload: snet.SCMPTracerouteReply{Identifier: 0xdeaf, Sequence: 0xcafd}, - Path: snet.RawPath{}, - }, - }, - }, - } - return testCases -} - -func TestDataplaneIntegration(t *testing.T) { - dispatcherTestPort := 40032 - settings := InitTestSettings(t, dispatcherTestPort) - - go func() { - err := RunDispatcher(false, settings.ApplicationSocket, reliable.DefaultDispSocketFileMode, - settings.UnderlayPort) - require.NoError(t, err, "dispatcher error") - }() - time.Sleep(defaultWaitDuration) - - testCases := genTestCases(dispatcherTestPort) - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - RunTestCase(t, tc, settings) - }) - time.Sleep(defaultWaitDuration) - } -} - -func RunTestCase(t *testing.T, tc *TestCase, settings *TestSettings) { - dispatcherService := reliable.NewDispatcher(settings.ApplicationSocket) - ctx, cancelF := context.WithTimeout(context.Background(), defaultTimeout) - defer cancelF() - conn, _, err := dispatcherService.Register( - ctx, - tc.ClientAddress.IA, - &net.UDPAddr{ - IP: tc.ClientAddress.PublicAddress.IP(), - Port: int(tc.ClientAddress.PublicPort), - }, - tc.ClientAddress.ServiceAddress, - ) - require.NoError(t, err, "unable to open socket") - // Always destroy the connection s.t. future tests aren't compromised by a - // fatal in this subtest - defer conn.Close() - - for _, packet := range tc.TestPackets { - require.NoError(t, packet.Serialize()) - fmt.Printf("sending packet: %x\n", packet.Bytes) - _, err = conn.WriteTo(packet.Bytes, tc.UnderlayAddress) - require.NoError(t, err, "unable to write message") - } - - err = conn.SetReadDeadline(time.Now().Add(defaultTimeout)) - require.NoError(t, err, "unable to set read deadline") - - rcvPkt := snet.Packet{} - rcvPkt.Prepare() - n, _, err := conn.ReadFrom(rcvPkt.Bytes) - require.NoError(t, err, "unable to read message") - rcvPkt.Bytes = rcvPkt.Bytes[:n] - - require.NoError(t, rcvPkt.Decode()) - - err = conn.Close() - require.NoError(t, err, "unable to close conn") - - assert.Equal(t, tc.ExpectedPacket.PacketInfo, rcvPkt.PacketInfo) -} - -func MustPack(pkt snet.Packet) []byte { - if err := pkt.Serialize(); err != nil { - panic(err) - } - return pkt.Bytes -} diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go deleted file mode 100644 index f38bf52d8e..0000000000 --- a/dispatcher/dispatcher.go +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright 2020 Anapaya Systems -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dispatcher - -import ( - "context" - "net" - "time" - - "github.com/scionproto/scion/dispatcher/internal/registration" - "github.com/scionproto/scion/dispatcher/internal/respool" - "github.com/scionproto/scion/pkg/addr" - "github.com/scionproto/scion/pkg/log" - "github.com/scionproto/scion/pkg/private/serrors" - "github.com/scionproto/scion/pkg/slayers" - "github.com/scionproto/scion/private/ringbuf" - "github.com/scionproto/scion/private/underlay/conn" -) - -const ( - // ReceiveBufferSize is the size of receive buffers used by the dispatcher. - ReceiveBufferSize = 1 << 20 - // SendBufferSize is the size of the send buffers used by the dispatcher. - SendBufferSize = 1 << 20 -) - -// Server is the main object allowing to create new SCION connections. -type Server struct { - // routingTable is used to register new connections. - routingTable *IATable - ipv4Conn net.PacketConn - ipv6Conn net.PacketConn -} - -// NewServer creates new instance of Server. Internally, it opens the dispatcher ports -// for both IPv4 and IPv6. Returns error if the ports can't be opened. -func NewServer(address string, ipv4Conn, ipv6Conn net.PacketConn) (*Server, error) { - if ipv4Conn == nil { - var err error - ipv4Conn, err = openConn("udp4", address) - if err != nil { - return nil, err - } - } - if ipv6Conn == nil { - var err error - ipv6Conn, err = openConn("udp6", address) - if err != nil { - ipv4Conn.Close() - return nil, err - } - } - return &Server{ - routingTable: NewIATable(32768, 65535), - ipv4Conn: ipv4Conn, - ipv6Conn: ipv6Conn, - }, nil -} - -// Serve starts reading packets from network and dispatching them to different connections. -// The function blocks and returns if there's an error or when Close has been called. -func (as *Server) Serve() error { - errChan := make(chan error) - go func() { - defer log.HandlePanic() - netToRingDataplane := &NetToRingDataplane{ - UnderlayConn: as.ipv4Conn, - RoutingTable: as.routingTable, - } - errChan <- netToRingDataplane.Run() - }() - go func() { - defer log.HandlePanic() - netToRingDataplane := &NetToRingDataplane{ - UnderlayConn: as.ipv6Conn, - RoutingTable: as.routingTable, - } - errChan <- netToRingDataplane.Run() - }() - return <-errChan -} - -// Register creates a new connection. -func (as *Server) Register(ctx context.Context, ia addr.IA, address *net.UDPAddr, - svc addr.HostSVC) (net.PacketConn, uint16, error) { - - tableEntry := newTableEntry() - ref, err := as.routingTable.Register(ia, address, nil, svc, tableEntry) - if err != nil { - return nil, 0, err - } - var ovConn net.PacketConn - if address.IP.To4() == nil { - ovConn = as.ipv6Conn - } else { - ovConn = as.ipv4Conn - } - conn := &Conn{ - conn: ovConn, - ring: tableEntry.appIngressRing, - regReference: ref, - } - return conn, uint16(ref.UDPAddr().Port), nil -} - -func (as *Server) Close() { - as.ipv4Conn.Close() - as.ipv6Conn.Close() -} - -// Conn represents a connection bound to a specific SCION port/SVC. -type Conn struct { - // conn is used to send packets. - conn net.PacketConn - // ring is used to retrieve incoming packets. - ring *ringbuf.Ring - // regReference is the reference to the registration in the routing table. - regReference registration.RegReference -} - -func (ac *Conn) WriteTo(p []byte, addr net.Addr) (int, error) { - panic("not implemented") -} - -// Write is optimized for the use by ConnHandler (avoids reparsing the packet). -func (ac *Conn) Write(pkt *respool.Packet) (int, error) { - // XXX(roosd): Ignore error since there is nothing we can do about it. - // Currently, the ID space is shared between all applications that register - // with the dispatcher. Likelihood that they overlap is very small. - // If this becomes ever a problem, we can namespace the ID per registered - // application. - _ = registerIfSCMPInfo(ac.regReference, pkt) - return pkt.SendOnConn(ac.conn, pkt.UnderlayRemote) -} - -func (ac *Conn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - pkt := ac.Read() - if pkt == nil { - return 0, nil, serrors.New("Connection closed") - } - n = pkt.CopyTo(p) - addr = pkt.UnderlayRemote - pkt.Free() - return -} - -// Read is optimized for the use by ConnHandler (avoids one copy). -func (ac *Conn) Read() *respool.Packet { - entries := make(ringbuf.EntryList, 1) - n, _ := ac.ring.Read(entries, true) - if n < 0 { - // Ring was closed because app shut down its data socket. - return nil - } - pkt := entries[0].(*respool.Packet) - return pkt -} - -func (ac *Conn) Close() error { - ac.regReference.Free() - ac.ring.Close() - return nil -} - -func (ac *Conn) LocalAddr() net.Addr { - return ac.regReference.UDPAddr() -} - -func (ac *Conn) SVCAddr() addr.HostSVC { - return ac.regReference.SVCAddr() -} - -func (ac *Conn) SetDeadline(t time.Time) error { - panic("not implemented") -} - -func (ac *Conn) SetReadDeadline(t time.Time) error { - panic("not implemented") -} - -func (ac *Conn) SetWriteDeadline(t time.Time) error { - panic("not implemented") -} - -// openConn opens an underlay socket that tracks additional socket information -// such as packets dropped due to buffer full. -// -// Note that Go-style dual-stacked IPv4/IPv6 connections are not supported. If -// network is udp, it will be treated as udp4. -func openConn(network, address string) (net.PacketConn, error) { - // We cannot allow the Go standard library to open both types of sockets - // because the socket options are specific to only one socket type, so we - // degrade udp to only udp4. - if network == "udp" { - network = "udp4" - } - listeningAddress, err := net.ResolveUDPAddr(network, address) - if err != nil { - return nil, serrors.WrapStr("unable to construct UDP addr", err) - } - if network == "udp4" && listeningAddress.IP == nil { - listeningAddress.IP = net.IPv4zero - } - if network == "udp6" && listeningAddress.IP == nil { - listeningAddress.IP = net.IPv6zero - } - - c, err := conn.New(listeningAddress, nil, &conn.Config{ - SendBufferSize: SendBufferSize, - ReceiveBufferSize: ReceiveBufferSize, - }) - if err != nil { - return nil, serrors.WrapStr("unable to open conn", err) - } - - return &underlayConnWrapper{Conn: c}, nil -} - -// registerIfSCMPInfo registers the ID of the SCMP request if it is an echo or -// traceroute message. -func registerIfSCMPInfo(ref registration.RegReference, pkt *respool.Packet) error { - if pkt.L4 != slayers.LayerTypeSCMP { - return nil - } - t := pkt.SCMP.TypeCode.Type() - if t != slayers.SCMPTypeEchoRequest && t != slayers.SCMPTypeTracerouteRequest { - return nil - } - id, err := extractSCMPIdentifier(&pkt.SCMP) - if err != nil { - return err - } - // FIXME(roosd): add metrics again. - return ref.RegisterID(uint64(id)) -} - -// underlayConnWrapper wraps a specialized underlay conn into a net.PacketConn -// implementation. Only *net.UDPAddr addressing is supported. -type underlayConnWrapper struct { - // Conn is the wrapped underlay connection object. - conn.Conn -} - -func (o *underlayConnWrapper) ReadFrom(p []byte) (int, net.Addr, error) { - return o.Conn.ReadFrom(p) -} - -func (o *underlayConnWrapper) WriteTo(p []byte, a net.Addr) (int, error) { - udpAddr, ok := a.(*net.UDPAddr) - if !ok { - return 0, serrors.New("address is not UDP", "addr", a) - } - return o.Conn.WriteTo(p, udpAddr) -} - -func (o *underlayConnWrapper) Close() error { - return o.Conn.Close() -} - -func (o *underlayConnWrapper) LocalAddr() net.Addr { - return o.Conn.LocalAddr() -} - -func (o *underlayConnWrapper) SetDeadline(t time.Time) error { - return o.Conn.SetDeadline(t) -} - -func (o *underlayConnWrapper) SetReadDeadline(t time.Time) error { - return o.Conn.SetReadDeadline(t) -} - -func (o *underlayConnWrapper) SetWriteDeadline(t time.Time) error { - return o.Conn.SetWriteDeadline(t) -} diff --git a/dispatcher/internal/registration/bench_test.go b/dispatcher/internal/registration/bench_test.go deleted file mode 100644 index 84d5e31909..0000000000 --- a/dispatcher/internal/registration/bench_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2018 ETH Zurich -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package registration - -import ( - "net" - "testing" - - "github.com/scionproto/scion/pkg/addr" -) - -type registerArgs struct { - ia addr.IA - public *net.UDPAddr - bind net.IP - svc addr.HostSVC - value interface{} -} - -func generateRegisterArgs(n int) []*registerArgs { - var data []*registerArgs - for i := 0; i < n; i++ { - newData := ®isterArgs{ - ia: getRandomIA(), - public: getRandomUDPAddress(), - bind: getRandomIPv4(), - svc: getRandomSVC(), - value: getRandomValue(), - } - data = append(data, newData) - } - return data -} - -func generateLookupPublicArgs(n int) []*net.UDPAddr { - var data []*net.UDPAddr - for i := 0; i < n; i++ { - data = append(data, getRandomUDPAddress()) - } - return data -} - -func BenchmarkRegister(b *testing.B) { - table := NewIATable(minPort, maxPort) - regData := generateRegisterArgs(b.N) - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, _ = table.Register(regData[n].ia, regData[n].public, nil, - addr.SvcNone, regData[n].value) - } -} - -func BenchmarkLookupPublicIPv4(b *testing.B) { - numEntries := 1000 - table := NewIATable(minPort, maxPort) - regData := generateRegisterArgs(numEntries) - for i := 0; i < numEntries; i++ { - _, _ = table.Register(regData[i].ia, regData[i].public, nil, - addr.SvcNone, regData[i].value) - } - lookupData := generateLookupPublicArgs(b.N) - b.ResetTimer() - for n := 0; n < b.N; n++ { - table.LookupPublic(addr.MustIAFrom(1, 1), lookupData[n]) - } -} - -type lookupServiceArgs struct { - svc addr.HostSVC - bind net.IP -} - -func generateLookupServiceArgs(n int) []*lookupServiceArgs { - var data []*lookupServiceArgs - for i := 0; i < n; i++ { - data = append(data, &lookupServiceArgs{ - svc: getRandomSVC(), - bind: getRandomIPv4(), - }) - } - return data -} - -func BenchmarkLookupServiceIPv4(b *testing.B) { - numEntries := 1000 - table := NewIATable(minPort, maxPort) - regData := generateRegisterArgs(numEntries) - for i := 0; i < numEntries; i++ { - _, _ = table.Register(regData[i].ia, regData[i].public, regData[i].bind, - regData[i].svc, regData[i].value) - } - lookupData := generateLookupServiceArgs(b.N) - b.ResetTimer() - for n := 0; n < b.N; n++ { - table.LookupService(addr.MustIAFrom(1, 1), lookupData[n].svc, lookupData[n].bind) - } -} diff --git a/dispatcher/internal/registration/iatable_test.go b/dispatcher/internal/registration/iatable_test.go deleted file mode 100644 index f60db2694b..0000000000 --- a/dispatcher/internal/registration/iatable_test.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2018 ETH Zurich -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package registration - -import ( - "net" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/scionproto/scion/pkg/addr" - "github.com/scionproto/scion/pkg/private/xtest" -) - -var ( - public = &net.UDPAddr{IP: net.IP{192, 0, 2, 1}, Port: 80} - value = "test value" - ia = xtest.MustParseIA("1-ff00:0:1") -) - -func TestIATable(t *testing.T) { - - t.Run("Given a table with one entry that is only public and no svc", func(t *testing.T) { - table := NewIATable(minPort, maxPort) - ref, err := table.Register(ia, public, nil, addr.SvcNone, value) - assert.NoError(t, err) - assert.NotNil(t, ref) - t.Run("lookups for the same AS", func(t *testing.T) { - retValue, ok := table.LookupPublic(ia, public) - assert.True(t, ok) - assert.Equal(t, retValue, value) - retValues := table.LookupService(ia, addr.SvcCS, net.IP{192, 0, 2, 1}) - assert.Empty(t, retValues) - }) - - t.Run("lookups for a different AS", func(t *testing.T) { - otherIA := xtest.MustParseIA("1-ff00:0:2") - retValue, ok := table.LookupPublic(otherIA, public) - assert.False(t, ok) - assert.Nil(t, retValue) - retValues := table.LookupService(otherIA, addr.SvcCS, net.IP{192, 0, 2, 1}) - assert.Empty(t, retValues) - }) - - t.Run("calling free twice panics", func(t *testing.T) { - ref.Free() - require.Panics(t, ref.Free) - }) - }) - - t.Run("Given a table with one entry that is only public and svc", func(t *testing.T) { - table := NewIATable(minPort, maxPort) - t.Run("lookups for the same AS works", func(t *testing.T) { - ref, err := table.Register(ia, public, nil, addr.SvcCS, value) - assert.NoError(t, err) - assert.NotNil(t, ref) - retValue, ok := table.LookupPublic(ia, public) - assert.True(t, ok) - assert.Equal(t, retValue, value) - retValues := table.LookupService(ia, addr.SvcCS, net.IP{192, 0, 2, 1}) - assert.Equal(t, retValues, []interface{}{value}) - }) - }) -} - -func TestIATableRegister(t *testing.T) { - t.Log("Given an empty table") - - t.Run("ISD zero is error", func(t *testing.T) { - table := NewIATable(minPort, maxPort) - ref, err := table.Register(addr.MustIAFrom(0, 1), public, nil, addr.SvcNone, value) - assert.EqualError(t, err, ErrBadISD.Error()) - assert.Nil(t, ref) - }) - - t.Run("AS zero is error", func(t *testing.T) { - table := NewIATable(minPort, maxPort) - ref, err := table.Register(addr.MustIAFrom(1, 0), public, nil, addr.SvcNone, value) - assert.EqualError(t, err, ErrBadAS.Error()) - assert.Nil(t, ref) - }) - - t.Run("for a good AS number", func(t *testing.T) { - ia := xtest.MustParseIA("1-ff00:0:1") - t.Run("already registered ports will cause error", func(t *testing.T) { - table := NewIATable(minPort, maxPort) - _, err := table.Register(ia, public, nil, addr.SvcNone, value) - require.NoError(t, err) - ref, err := table.Register(ia, public, nil, addr.SvcNone, value) - assert.Error(t, err) - assert.Nil(t, ref) - }) - - t.Run("good ports will return success", func(t *testing.T) { - table := NewIATable(minPort, maxPort) - ref, err := table.Register(ia, public, nil, addr.SvcNone, value) - assert.NoError(t, err) - assert.NotNil(t, ref) - }) - }) -} - -func TestIATableSCMPRegistration(t *testing.T) { - table := NewIATable(minPort, maxPort) - - t.Log("Given a reference to an IATable registration") - ref, err := table.Register(ia, public, nil, addr.SvcNone, value) - require.NoError(t, err) - v, ok := table.LookupID(ia, 42) - assert.False(t, ok, "Performing SCMP lookup fails") - assert.Nil(t, v) - err = ref.RegisterID(42) - assert.NoError(t, err, "Registering an SCMP ID on the reference succeeds") -} - -func TestIATableSCMPExistingRegistration(t *testing.T) { - - t.Run("Registering a second SCMP ID on the same reference succeeds", func(t *testing.T) { - table := NewIATable(minPort, maxPort) - ref, err := table.Register(ia, public, nil, addr.SvcNone, value) - require.NoError(t, err) - t.Log("Given an existing SCMP General ID registration") - err = ref.RegisterID(42) - require.NoError(t, err) - - t.Log("Performing an SCMP lookup on the same IA succeeds") - retValue, ok := table.LookupID(ia, 42) - assert.True(t, ok) - assert.Equal(t, retValue, value) - - t.Log("Performing an SCMP lookup on a different IA fails") - retValue, ok = table.LookupID(xtest.MustParseIA("1-ff00:0:2"), 42) - assert.False(t, ok) - assert.Nil(t, retValue) - - t.Log("Freeing the reference makes lookup fail") - ref.Free() - retValue, ok = table.LookupID(ia, 42) - assert.False(t, ok) - assert.Nil(t, retValue) - }) - - t.Run("Registering a second SCMP ID on the same reference succeeds", func(t *testing.T) { - table := NewIATable(minPort, maxPort) - ref, err := table.Register(ia, public, nil, addr.SvcNone, value) - require.NoError(t, err) - t.Log("Given an existing SCMP General ID registration") - err = ref.RegisterID(42) - require.NoError(t, err) - err = ref.RegisterID(43) - assert.NoError(t, err) - - t.Log("Freeing the reference makes lookup on first registered id fail") - ref.Free() - retValue, ok := table.LookupID(ia, 42) - assert.False(t, ok) - assert.Nil(t, retValue) - }) -} diff --git a/dispatcher/internal/registration/scmp_table_test.go b/dispatcher/internal/registration/scmp_table_test.go deleted file mode 100644 index 5c376615ca..0000000000 --- a/dispatcher/internal/registration/scmp_table_test.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019 ETH Zurich -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package registration - -import ( - "testing" - - . "github.com/smartystreets/goconvey/convey" - "github.com/stretchr/testify/require" -) - -func TestSCMPEmptyTable(t *testing.T) { - Convey("Given an empty table", t, func() { - table := NewSCMPTable() - - Convey("Lookup for an id fails", func() { - value, ok := table.Lookup(42) - SoMsg("ok", ok, ShouldBeFalse) - SoMsg("value", value, ShouldBeNil) - }) - Convey("Adding an item succeeds", func() { - value := "test value" - err := table.Register(42, value) - So(err, ShouldBeNil) - }) - Convey("Adding an item with nil value fails", func() { - err := table.Register(42, nil) - So(err, ShouldNotBeNil) - }) - }) -} - -func TestSCMPTableWithOneItem(t *testing.T) { - Convey("Given a table with one element", t, func() { - table := NewSCMPTable() - value := "test value" - err := table.Register(42, value) - require.NoError(t, err) - Convey("Lookup for the id succeeds", func() { - retValue, ok := table.Lookup(42) - SoMsg("ok", ok, ShouldBeTrue) - SoMsg("value", retValue, ShouldEqual, value) - }) - Convey("Adding the same id fails", func() { - err := table.Register(42, "some other value") - So(err, ShouldNotBeNil) - }) - Convey("After removing the ID, lookup fails", func() { - table.Remove(42) - value, ok := table.Lookup(42) - SoMsg("ok", ok, ShouldBeFalse) - SoMsg("value", value, ShouldBeNil) - }) - }) -} diff --git a/dispatcher/mgmtapi/BUILD.bazel b/dispatcher/mgmtapi/BUILD.bazel deleted file mode 100644 index d63ed1b5d8..0000000000 --- a/dispatcher/mgmtapi/BUILD.bazel +++ /dev/null @@ -1,36 +0,0 @@ -load("//tools/lint:go.bzl", "go_library") -load("//rules_openapi:defs.bzl", "openapi_build_docs", "openapi_generate_go") - -openapi_build_docs( - name = "doc", - src = "//spec:dispatcher", - out = "index.html", -) - -openapi_generate_go( - name = "api_generated", - src = "//spec:dispatcher", - package = "mgmtapi", -) - -# exclude the *.gen.go files in the workspace they are only for editor compatibility. -# gazelle:exclude *.gen.go -go_library( - name = "go_default_library", - srcs = [ - "api.go", - "spec.go", - ":api_generated", # keep - ], - embedsrcs = select({ - "//:mgmtapi_bundle_doc_build": [":doc"], - "//conditions:default": [":dummy.html"], - }), # keep - importpath = "github.com/scionproto/scion/dispatcher/mgmtapi", - visibility = ["//visibility:public"], - deps = [ - "//private/mgmtapi:go_default_library", - "@com_github_getkin_kin_openapi//openapi3:go_default_library", # keep - "@com_github_go_chi_chi_v5//:go_default_library", # keep - ], -) diff --git a/dispatcher/mgmtapi/client.gen.go b/dispatcher/mgmtapi/client.gen.go deleted file mode 100644 index d87b18ca40..0000000000 --- a/dispatcher/mgmtapi/client.gen.go +++ /dev/null @@ -1,594 +0,0 @@ -// Package mgmtapi provides primitives to interact with the openapi HTTP API. -// -// Code generated by unknown module path version unknown version DO NOT EDIT. -package mgmtapi - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strings" -) - -// RequestEditorFn is the function signature for the RequestEditor callback function -type RequestEditorFn func(ctx context.Context, req *http.Request) error - -// Doer performs HTTP requests. -// -// The standard http.Client implements this interface. -type HttpRequestDoer interface { - Do(req *http.Request) (*http.Response, error) -} - -// Client which conforms to the OpenAPI3 specification for this service. -type Client struct { - // The endpoint of the server conforming to this interface, with scheme, - // https://api.deepmap.com for example. This can contain a path relative - // to the server, such as https://api.deepmap.com/dev-test, and all the - // paths in the swagger spec will be appended to the server. - Server string - - // Doer for performing requests, typically a *http.Client with any - // customized settings, such as certificate chains. - Client HttpRequestDoer - - // A list of callbacks for modifying requests which are generated before sending over - // the network. - RequestEditors []RequestEditorFn -} - -// ClientOption allows setting custom parameters during construction -type ClientOption func(*Client) error - -// Creates a new Client, with reasonable defaults -func NewClient(server string, opts ...ClientOption) (*Client, error) { - // create a client with sane default values - client := Client{ - Server: server, - } - // mutate client and add all optional params - for _, o := range opts { - if err := o(&client); err != nil { - return nil, err - } - } - // ensure the server URL always has a trailing slash - if !strings.HasSuffix(client.Server, "/") { - client.Server += "/" - } - // create httpClient, if not already present - if client.Client == nil { - client.Client = &http.Client{} - } - return &client, nil -} - -// WithHTTPClient allows overriding the default Doer, which is -// automatically created using http.Client. This is useful for tests. -func WithHTTPClient(doer HttpRequestDoer) ClientOption { - return func(c *Client) error { - c.Client = doer - return nil - } -} - -// WithRequestEditorFn allows setting up a callback function, which will be -// called right before sending the request. This can be used to mutate the request. -func WithRequestEditorFn(fn RequestEditorFn) ClientOption { - return func(c *Client) error { - c.RequestEditors = append(c.RequestEditors, fn) - return nil - } -} - -// The interface specification for the client above. -type ClientInterface interface { - // GetConfig request - GetConfig(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetInfo request - GetInfo(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) - - // GetLogLevel request - GetLogLevel(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) - - // SetLogLevel request with any body - SetLogLevelWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) - - SetLogLevel(ctx context.Context, body SetLogLevelJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) -} - -func (c *Client) GetConfig(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetConfigRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetInfo(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetInfoRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) GetLogLevel(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewGetLogLevelRequest(c.Server) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) SetLogLevelWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewSetLogLevelRequestWithBody(c.Server, contentType, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -func (c *Client) SetLogLevel(ctx context.Context, body SetLogLevelJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewSetLogLevelRequest(c.Server, body) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if err := c.applyEditors(ctx, req, reqEditors); err != nil { - return nil, err - } - return c.Client.Do(req) -} - -// NewGetConfigRequest generates requests for GetConfig -func NewGetConfigRequest(server string) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/config") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetInfoRequest generates requests for GetInfo -func NewGetInfoRequest(server string) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/info") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewGetLogLevelRequest generates requests for GetLogLevel -func NewGetLogLevelRequest(server string) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/log/level") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", queryURL.String(), nil) - if err != nil { - return nil, err - } - - return req, nil -} - -// NewSetLogLevelRequest calls the generic SetLogLevel builder with application/json body -func NewSetLogLevelRequest(server string, body SetLogLevelJSONRequestBody) (*http.Request, error) { - var bodyReader io.Reader - buf, err := json.Marshal(body) - if err != nil { - return nil, err - } - bodyReader = bytes.NewReader(buf) - return NewSetLogLevelRequestWithBody(server, "application/json", bodyReader) -} - -// NewSetLogLevelRequestWithBody generates requests for SetLogLevel with any type of body -func NewSetLogLevelRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { - var err error - - serverURL, err := url.Parse(server) - if err != nil { - return nil, err - } - - operationPath := fmt.Sprintf("/log/level") - if operationPath[0] == '/' { - operationPath = "." + operationPath - } - - queryURL, err := serverURL.Parse(operationPath) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("PUT", queryURL.String(), body) - if err != nil { - return nil, err - } - - req.Header.Add("Content-Type", contentType) - - return req, nil -} - -func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { - for _, r := range c.RequestEditors { - if err := r(ctx, req); err != nil { - return err - } - } - for _, r := range additionalEditors { - if err := r(ctx, req); err != nil { - return err - } - } - return nil -} - -// ClientWithResponses builds on ClientInterface to offer response payloads -type ClientWithResponses struct { - ClientInterface -} - -// NewClientWithResponses creates a new ClientWithResponses, which wraps -// Client with return type handling -func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) { - client, err := NewClient(server, opts...) - if err != nil { - return nil, err - } - return &ClientWithResponses{client}, nil -} - -// WithBaseURL overrides the baseURL. -func WithBaseURL(baseURL string) ClientOption { - return func(c *Client) error { - newBaseURL, err := url.Parse(baseURL) - if err != nil { - return err - } - c.Server = newBaseURL.String() - return nil - } -} - -// ClientWithResponsesInterface is the interface specification for the client with responses above. -type ClientWithResponsesInterface interface { - // GetConfig request - GetConfigWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetConfigResponse, error) - - // GetInfo request - GetInfoWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetInfoResponse, error) - - // GetLogLevel request - GetLogLevelWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetLogLevelResponse, error) - - // SetLogLevel request with any body - SetLogLevelWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetLogLevelResponse, error) - - SetLogLevelWithResponse(ctx context.Context, body SetLogLevelJSONRequestBody, reqEditors ...RequestEditorFn) (*SetLogLevelResponse, error) -} - -type GetConfigResponse struct { - Body []byte - HTTPResponse *http.Response - JSON400 *StandardError -} - -// Status returns HTTPResponse.Status -func (r GetConfigResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetConfigResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetInfoResponse struct { - Body []byte - HTTPResponse *http.Response - JSON400 *StandardError -} - -// Status returns HTTPResponse.Status -func (r GetInfoResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetInfoResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type GetLogLevelResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *LogLevel - JSON400 *StandardError -} - -// Status returns HTTPResponse.Status -func (r GetLogLevelResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r GetLogLevelResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -type SetLogLevelResponse struct { - Body []byte - HTTPResponse *http.Response - JSON200 *LogLevel - JSON400 *StandardError -} - -// Status returns HTTPResponse.Status -func (r SetLogLevelResponse) Status() string { - if r.HTTPResponse != nil { - return r.HTTPResponse.Status - } - return http.StatusText(0) -} - -// StatusCode returns HTTPResponse.StatusCode -func (r SetLogLevelResponse) StatusCode() int { - if r.HTTPResponse != nil { - return r.HTTPResponse.StatusCode - } - return 0 -} - -// GetConfigWithResponse request returning *GetConfigResponse -func (c *ClientWithResponses) GetConfigWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetConfigResponse, error) { - rsp, err := c.GetConfig(ctx, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetConfigResponse(rsp) -} - -// GetInfoWithResponse request returning *GetInfoResponse -func (c *ClientWithResponses) GetInfoWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetInfoResponse, error) { - rsp, err := c.GetInfo(ctx, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetInfoResponse(rsp) -} - -// GetLogLevelWithResponse request returning *GetLogLevelResponse -func (c *ClientWithResponses) GetLogLevelWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetLogLevelResponse, error) { - rsp, err := c.GetLogLevel(ctx, reqEditors...) - if err != nil { - return nil, err - } - return ParseGetLogLevelResponse(rsp) -} - -// SetLogLevelWithBodyWithResponse request with arbitrary body returning *SetLogLevelResponse -func (c *ClientWithResponses) SetLogLevelWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetLogLevelResponse, error) { - rsp, err := c.SetLogLevelWithBody(ctx, contentType, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseSetLogLevelResponse(rsp) -} - -func (c *ClientWithResponses) SetLogLevelWithResponse(ctx context.Context, body SetLogLevelJSONRequestBody, reqEditors ...RequestEditorFn) (*SetLogLevelResponse, error) { - rsp, err := c.SetLogLevel(ctx, body, reqEditors...) - if err != nil { - return nil, err - } - return ParseSetLogLevelResponse(rsp) -} - -// ParseGetConfigResponse parses an HTTP response from a GetConfigWithResponse call -func ParseGetConfigResponse(rsp *http.Response) (*GetConfigResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetConfigResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest StandardError - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - } - - return response, nil -} - -// ParseGetInfoResponse parses an HTTP response from a GetInfoWithResponse call -func ParseGetInfoResponse(rsp *http.Response) (*GetInfoResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetInfoResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest StandardError - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - } - - return response, nil -} - -// ParseGetLogLevelResponse parses an HTTP response from a GetLogLevelWithResponse call -func ParseGetLogLevelResponse(rsp *http.Response) (*GetLogLevelResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &GetLogLevelResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest LogLevel - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest StandardError - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - } - - return response, nil -} - -// ParseSetLogLevelResponse parses an HTTP response from a SetLogLevelWithResponse call -func ParseSetLogLevelResponse(rsp *http.Response) (*SetLogLevelResponse, error) { - bodyBytes, err := io.ReadAll(rsp.Body) - defer func() { _ = rsp.Body.Close() }() - if err != nil { - return nil, err - } - - response := &SetLogLevelResponse{ - Body: bodyBytes, - HTTPResponse: rsp, - } - - switch { - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest LogLevel - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON200 = &dest - - case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: - var dest StandardError - if err := json.Unmarshal(bodyBytes, &dest); err != nil { - return nil, err - } - response.JSON400 = &dest - - } - - return response, nil -} diff --git a/dispatcher/mgmtapi/server.gen.go b/dispatcher/mgmtapi/server.gen.go deleted file mode 100644 index c6b1ffa8c4..0000000000 --- a/dispatcher/mgmtapi/server.gen.go +++ /dev/null @@ -1,225 +0,0 @@ -// Package mgmtapi provides primitives to interact with the openapi HTTP API. -// -// Code generated by unknown module path version unknown version DO NOT EDIT. -package mgmtapi - -import ( - "fmt" - "net/http" - - "github.com/go-chi/chi/v5" -) - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // Prints the TOML configuration file. - // (GET /config) - GetConfig(w http.ResponseWriter, r *http.Request) - // Basic information page about the control service process. - // (GET /info) - GetInfo(w http.ResponseWriter, r *http.Request) - // Get logging level - // (GET /log/level) - GetLogLevel(w http.ResponseWriter, r *http.Request) - // Set logging level - // (PUT /log/level) - SetLogLevel(w http.ResponseWriter, r *http.Request) -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -type MiddlewareFunc func(http.Handler) http.Handler - -// GetConfig operation middleware -func (siw *ServerInterfaceWrapper) GetConfig(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetConfig(w, r) - }) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r.WithContext(ctx)) -} - -// GetInfo operation middleware -func (siw *ServerInterfaceWrapper) GetInfo(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetInfo(w, r) - }) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r.WithContext(ctx)) -} - -// GetLogLevel operation middleware -func (siw *ServerInterfaceWrapper) GetLogLevel(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetLogLevel(w, r) - }) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r.WithContext(ctx)) -} - -// SetLogLevel operation middleware -func (siw *ServerInterfaceWrapper) SetLogLevel(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.SetLogLevel(w, r) - }) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r.WithContext(ctx)) -} - -type UnescapedCookieParamError struct { - ParamName string - Err error -} - -func (e *UnescapedCookieParamError) Error() string { - return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName) -} - -func (e *UnescapedCookieParamError) Unwrap() error { - return e.Err -} - -type UnmarshallingParamError struct { - ParamName string - Err error -} - -func (e *UnmarshallingParamError) Error() string { - return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error()) -} - -func (e *UnmarshallingParamError) Unwrap() error { - return e.Err -} - -type RequiredParamError struct { - ParamName string -} - -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} - -type RequiredHeaderError struct { - ParamName string - Err error -} - -func (e *RequiredHeaderError) Error() string { - return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName) -} - -func (e *RequiredHeaderError) Unwrap() error { - return e.Err -} - -type InvalidParamFormatError struct { - ParamName string - Err error -} - -func (e *InvalidParamFormatError) Error() string { - return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error()) -} - -func (e *InvalidParamFormatError) Unwrap() error { - return e.Err -} - -type TooManyValuesForParamError struct { - ParamName string - Count int -} - -func (e *TooManyValuesForParamError) Error() string { - return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count) -} - -// Handler creates http.Handler with routing matching OpenAPI spec. -func Handler(si ServerInterface) http.Handler { - return HandlerWithOptions(si, ChiServerOptions{}) -} - -type ChiServerOptions struct { - BaseURL string - BaseRouter chi.Router - Middlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} - -// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. -func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler { - return HandlerWithOptions(si, ChiServerOptions{ - BaseRouter: r, - }) -} - -func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler { - return HandlerWithOptions(si, ChiServerOptions{ - BaseURL: baseURL, - BaseRouter: r, - }) -} - -// HandlerWithOptions creates http.Handler with additional options -func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler { - r := options.BaseRouter - - if r == nil { - r = chi.NewRouter() - } - if options.ErrorHandlerFunc == nil { - options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) - } - } - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandlerFunc: options.ErrorHandlerFunc, - } - - r.Group(func(r chi.Router) { - r.Get(options.BaseURL+"/config", wrapper.GetConfig) - }) - r.Group(func(r chi.Router) { - r.Get(options.BaseURL+"/info", wrapper.GetInfo) - }) - r.Group(func(r chi.Router) { - r.Get(options.BaseURL+"/log/level", wrapper.GetLogLevel) - }) - r.Group(func(r chi.Router) { - r.Put(options.BaseURL+"/log/level", wrapper.SetLogLevel) - }) - - return r -} diff --git a/dispatcher/mgmtapi/spec.go b/dispatcher/mgmtapi/spec.go deleted file mode 100644 index 887633ba4d..0000000000 --- a/dispatcher/mgmtapi/spec.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2021 Anapaya Systems -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package mgmtapi - -import ( - "bytes" - "embed" - "net/http" - "time" - - "github.com/scionproto/scion/private/mgmtapi" -) - -//go:embed *.html -var f embed.FS - -var ( - index = mgmtapi.ResolveIndex(f) - - modtime = time.Now() - - spec = func() []byte { - raw, err := rawSpec() - if err != nil { - panic(err) - } - return raw - }() -) - -// ServeSpecInteractive serves the interactive redocly OpenAPI3 spec. -func ServeSpecInteractive(w http.ResponseWriter, r *http.Request) { - http.ServeContent(w, r, "index.html", modtime, bytes.NewReader(index)) -} - -// ServeSpecJSON serves the json encoded OpenAPI3 spec. -func ServeSpecJSON(w http.ResponseWriter, r *http.Request) { - http.ServeContent(w, r, "openapi.json", modtime, bytes.NewReader(spec)) -} diff --git a/dispatcher/mgmtapi/types.gen.go b/dispatcher/mgmtapi/types.gen.go deleted file mode 100644 index 2a16e00307..0000000000 --- a/dispatcher/mgmtapi/types.gen.go +++ /dev/null @@ -1,32 +0,0 @@ -// Package mgmtapi provides primitives to interact with the openapi HTTP API. -// -// Code generated by unknown module path version unknown version DO NOT EDIT. -package mgmtapi - -// Defines values for LogLevelLevel. -const ( - Debug LogLevelLevel = "debug" - Error LogLevelLevel = "error" - Info LogLevelLevel = "info" -) - -// LogLevel defines model for LogLevel. -type LogLevel struct { - // Level Logging level - Level LogLevelLevel `json:"level"` -} - -// LogLevelLevel Logging level -type LogLevelLevel string - -// StandardError defines model for StandardError. -type StandardError struct { - // Error Error message - Error string `json:"error"` -} - -// BadRequest defines model for BadRequest. -type BadRequest = StandardError - -// SetLogLevelJSONRequestBody defines body for SetLogLevel for application/json ContentType. -type SetLogLevelJSONRequestBody = LogLevel diff --git a/private/svc/resolver_test.go b/private/svc/resolver_test.go index 722947fc10..947030a277 100644 --- a/private/svc/resolver_test.go +++ b/private/svc/resolver_test.go @@ -68,6 +68,7 @@ func TestResolver(t *testing.T) { IP: net.IP{192, 0, 2, 1}, Port: 30001}) mockConnector.EXPECT().OpenUDP(&net.UDPAddr{ IP: net.IP{192, 0, 2, 1}}).Return(mockConn, nil) + mockConn.EXPECT().Close().Return(nil) mockRoundTripper := mock_svc.NewMockRoundTripper(ctrl) mockRoundTripper.EXPECT().RoundTrip(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Do(