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

package sharedmem

import (
	"math"
	"syscall"

	"github.com/google/netstack/tcpip/link/sharedmem/queue"
)

const (
	nilID = math.MaxUint64
)

// tx holds all state associated with a tx queue.
type tx struct {
	data []byte
	q    queue.Tx
	ids  idManager
	bufs bufferManager
}

// init initializes all state needed by the tx queue based on the information
// provided.
//
// The caller always retains ownership of all file descriptors passed in. The
// queue implementation will duplicate any that it may need in the future.
func (t *tx) init(mtu uint32, c *QueueConfig) error {
	// Map in all buffers.
	txPipe, err := getBuffer(c.TxPipeFD)
	if err != nil {
		return err
	}

	rxPipe, err := getBuffer(c.RxPipeFD)
	if err != nil {
		syscall.Munmap(txPipe)
		return err
	}

	data, err := getBuffer(c.DataFD)
	if err != nil {
		syscall.Munmap(txPipe)
		syscall.Munmap(rxPipe)
		return err
	}

	// Initialize state based on buffers.
	t.q.Init(txPipe, rxPipe)
	t.ids.init()
	t.bufs.init(0, len(data), int(mtu))
	t.data = data

	return nil
}

// cleanup releases all resources allocated during init(). It must only be
// called if init() has previously succeeded.
func (t *tx) cleanup() {
	a, b := t.q.Bytes()
	syscall.Munmap(a)
	syscall.Munmap(b)
	syscall.Munmap(t.data)
}

// transmit sends a packet made up of up to two buffers. Returns a boolean that
// specifies whether the packet was successfully transmitted.
func (t *tx) transmit(a, b []byte) bool {
	// Pull completions from the tx queue and add their buffers back to the
	// pool so that we can reuse them.
	for {
		id, ok := t.q.CompletedPacket()
		if !ok {
			break
		}

		if buf := t.ids.remove(id); buf != nil {
			t.bufs.free(buf)
		}
	}

	bSize := t.bufs.entrySize
	total := uint32(len(a) + len(b))
	bufCount := (total + bSize - 1) / bSize

	// Allocate enough buffers to hold all the data.
	var buf *queue.TxBuffer
	for i := bufCount; i != 0; i-- {
		b := t.bufs.alloc()
		if b == nil {
			// Failed to get all buffers. Return to the pool
			// whatever we had managed to get.
			if buf != nil {
				t.bufs.free(buf)
			}
			return false
		}
		b.Next = buf
		buf = b
	}

	// Copy data into allocated buffers.
	nBuf := buf
	var dBuf []byte
	for _, data := range [][]byte{a, b} {
		for len(data) > 0 {
			if len(dBuf) == 0 {
				dBuf = t.data[nBuf.Offset:][:nBuf.Size]
				nBuf = nBuf.Next
			}
			n := copy(dBuf, data)
			data = data[n:]
			dBuf = dBuf[n:]
		}
	}

	// Get an id for this packet and send it out.
	id := t.ids.add(buf)
	if !t.q.Enqueue(id, total, bufCount, buf) {
		t.ids.remove(id)
		t.bufs.free(buf)
		return false
	}

	return true
}

// getBuffer returns a memory region mapped to the full contents of the given
// file descriptor.
func getBuffer(fd int) ([]byte, error) {
	var s syscall.Stat_t
	if err := syscall.Fstat(fd, &s); err != nil {
		return nil, err
	}

	// Check that size doesn't overflow an int.
	if s.Size > int64(^uint(0)>>1) {
		return nil, syscall.EDOM
	}

	return syscall.Mmap(fd, 0, int(s.Size), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED|syscall.MAP_FILE)
}

// idDescriptor is used by idManager to either point to a tx buffer (in case
// the ID is assigned) or to the next free element (if the id is not assigned).
type idDescriptor struct {
	buf      *queue.TxBuffer
	nextFree uint64
}

// idManager is a manager of tx buffer identifiers. It assigns unique IDs to
// tx buffers that are added to it; the IDs can only be reused after they have
// been removed.
//
// The ID assignments are stored so that the tx buffers can be retrieved from
// the IDs previously assigned to them.
type idManager struct {
	// ids is a slice containing all tx buffers. The ID is the index into
	// this slice.
	ids []idDescriptor

	// freeList a list of free IDs.
	freeList uint64
}

// init initializes the id manager.
func (m *idManager) init() {
	m.freeList = nilID
}

// add assigns an ID to the given tx buffer.
func (m *idManager) add(b *queue.TxBuffer) uint64 {
	if i := m.freeList; i != nilID {
		// There is an id available in the free list, just use it.
		m.ids[i].buf = b
		m.freeList = m.ids[i].nextFree
		return i
	}

	// We need to expand the id descriptor.
	m.ids = append(m.ids, idDescriptor{buf: b})
	return uint64(len(m.ids) - 1)
}

// remove retrieves the tx buffer associated with the given ID, and removes the
// ID from the assigned table so that it can be reused in the future.
func (m *idManager) remove(i uint64) *queue.TxBuffer {
	if i >= uint64(len(m.ids)) {
		return nil
	}

	desc := &m.ids[i]
	b := desc.buf
	if b == nil {
		// The provided id is not currently assigned.
		return nil
	}

	desc.buf = nil
	desc.nextFree = m.freeList
	m.freeList = i

	return b
}

// bufferManager manages a buffer region broken up into smaller, equally sized
// buffers. Smaller buffers can be allocated and freed.
type bufferManager struct {
	freeList  *queue.TxBuffer
	curOffset uint64
	limit     uint64
	entrySize uint32
}

// init initializes the buffer manager.
func (b *bufferManager) init(initialOffset, size, entrySize int) {
	b.freeList = nil
	b.curOffset = uint64(initialOffset)
	b.limit = uint64(initialOffset + size/entrySize*entrySize)
	b.entrySize = uint32(entrySize)
}

// alloc allocates a buffer from the manager, if one is available.
func (b *bufferManager) alloc() *queue.TxBuffer {
	if b.freeList != nil {
		// There is a descriptor ready for reuse in the free list.
		d := b.freeList
		b.freeList = d.Next
		d.Next = nil
		return d
	}

	if b.curOffset < b.limit {
		// There is room available in the never-used range, so create
		// a new descriptor for it.
		d := &queue.TxBuffer{
			Offset: b.curOffset,
			Size:   b.entrySize,
		}
		b.curOffset += uint64(b.entrySize)
		return d
	}

	return nil
}

// free returns all buffers in the list to the buffer manager so that they can
// be reused.
func (b *bufferManager) free(d *queue.TxBuffer) {
	// Find the last buffer in the list.
	last := d
	for last.Next != nil {
		last = last.Next
	}

	// Push list onto free list.
	last.Next = b.freeList
	b.freeList = d
}
