// Copyright 2021 The gVisor Authors.
//
// 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 noop contains an endpoint that implements all tcpip.Endpoint
// functions as noops.
package noop

import (
	"fmt"
	"io"

	"gvisor.dev/gvisor/pkg/tcpip"
	"gvisor.dev/gvisor/pkg/tcpip/stack"
	"gvisor.dev/gvisor/pkg/waiter"
)

// endpoint can be created, but all interactions have no effect or
// return errors.
//
// +stateify savable
type endpoint struct {
	tcpip.DefaultSocketOptionsHandler
	ops tcpip.SocketOptions
}

// New returns an initialized noop endpoint.
func New(stk *stack.Stack) tcpip.Endpoint {
	// ep.ops must be in a valid, initialized state for callers of
	// ep.SocketOptions.
	var ep endpoint
	ep.ops.InitHandler(&ep, stk, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits)
	return &ep
}

// Abort implements stack.TransportEndpoint.Abort.
func (*endpoint) Abort() {
	// No-op.
}

// Close implements tcpip.Endpoint.Close.
func (*endpoint) Close() {
	// No-op.
}

// ModerateRecvBuf implements tcpip.Endpoint.ModerateRecvBuf.
func (*endpoint) ModerateRecvBuf(int) {
	// No-op.
}

func (*endpoint) SetOwner(tcpip.PacketOwner) {
	// No-op.
}

// Read implements tcpip.Endpoint.Read.
func (*endpoint) Read(io.Writer, tcpip.ReadOptions) (tcpip.ReadResult, tcpip.Error) {
	return tcpip.ReadResult{}, &tcpip.ErrNotPermitted{}
}

// Write implements tcpip.Endpoint.Write.
func (*endpoint) Write(tcpip.Payloader, tcpip.WriteOptions) (int64, tcpip.Error) {
	return 0, &tcpip.ErrNotPermitted{}
}

// Disconnect implements tcpip.Endpoint.Disconnect.
func (*endpoint) Disconnect() tcpip.Error {
	return &tcpip.ErrNotSupported{}
}

// Connect implements tcpip.Endpoint.Connect.
func (*endpoint) Connect(tcpip.FullAddress) tcpip.Error {
	return &tcpip.ErrNotPermitted{}
}

// Shutdown implements tcpip.Endpoint.Shutdown.
func (*endpoint) Shutdown(tcpip.ShutdownFlags) tcpip.Error {
	return &tcpip.ErrNotPermitted{}
}

// Listen implements tcpip.Endpoint.Listen.
func (*endpoint) Listen(int) tcpip.Error {
	return &tcpip.ErrNotSupported{}
}

// Accept implements tcpip.Endpoint.Accept.
func (*endpoint) Accept(*tcpip.FullAddress) (tcpip.Endpoint, *waiter.Queue, tcpip.Error) {
	return nil, nil, &tcpip.ErrNotSupported{}
}

// Bind implements tcpip.Endpoint.Bind.
func (*endpoint) Bind(tcpip.FullAddress) tcpip.Error {
	return &tcpip.ErrNotPermitted{}
}

// GetLocalAddress implements tcpip.Endpoint.GetLocalAddress.
func (*endpoint) GetLocalAddress() (tcpip.FullAddress, tcpip.Error) {
	return tcpip.FullAddress{}, &tcpip.ErrNotSupported{}
}

// GetRemoteAddress implements tcpip.Endpoint.GetRemoteAddress.
func (*endpoint) GetRemoteAddress() (tcpip.FullAddress, tcpip.Error) {
	return tcpip.FullAddress{}, &tcpip.ErrNotConnected{}
}

// Readiness implements tcpip.Endpoint.Readiness.
func (*endpoint) Readiness(waiter.EventMask) waiter.EventMask {
	return 0
}

// SetSockOpt implements tcpip.Endpoint.SetSockOpt.
func (*endpoint) SetSockOpt(tcpip.SettableSocketOption) tcpip.Error {
	return &tcpip.ErrUnknownProtocolOption{}
}

func (*endpoint) SetSockOptInt(tcpip.SockOptInt, int) tcpip.Error {
	return &tcpip.ErrUnknownProtocolOption{}
}

// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
func (*endpoint) GetSockOpt(tcpip.GettableSocketOption) tcpip.Error {
	return &tcpip.ErrUnknownProtocolOption{}
}

// GetSockOptInt implements tcpip.Endpoint.GetSockOptInt.
func (*endpoint) GetSockOptInt(tcpip.SockOptInt) (int, tcpip.Error) {
	return 0, &tcpip.ErrUnknownProtocolOption{}
}

// HandlePacket implements stack.RawTransportEndpoint.HandlePacket.
func (*endpoint) HandlePacket(pkt stack.PacketBufferPtr) {
	panic(fmt.Sprintf("unreachable: noop.endpoint should never be registered, but got packet: %+v", pkt))
}

// State implements socket.Socket.State.
func (*endpoint) State() uint32 {
	return 0
}

// Wait implements stack.TransportEndpoint.Wait.
func (*endpoint) Wait() {
	// No-op.
}

// Release implements stack.TransportEndpoint.Release.
func (*endpoint) Release() {
	// No-op.
}

// LastError implements tcpip.Endpoint.LastError.
func (*endpoint) LastError() tcpip.Error {
	return nil
}

// SocketOptions implements tcpip.Endpoint.SocketOptions.
func (ep *endpoint) SocketOptions() *tcpip.SocketOptions {
	return &ep.ops
}

// Info implements tcpip.Endpoint.Info.
func (*endpoint) Info() tcpip.EndpointInfo {
	return &stack.TransportEndpointInfo{}
}

// Stats returns a pointer to the endpoint stats.
func (*endpoint) Stats() tcpip.EndpointStats {
	return &tcpip.TransportEndpointStats{}
}
