// SPDX-FileCopyrightText: 2022 Free Mobile
// SPDX-License-Identifier: AGPL-3.0-only

//go:build linux

package udp

import (
	"syscall"
	"time"
	"unsafe"

	"golang.org/x/sys/unix"
)

var (
	oobLength        = syscall.CmsgLen(4) + syscall.CmsgLen(16) // uint32 + 2*int64
	udpSocketOptions = append(commonUDPSocketOptions, socketOption{
		// Get the number of dropped packets
		Name:   "SO_RXQ_OVFL",
		Level:  unix.SOL_SOCKET,
		Option: unix.SO_RXQ_OVFL,
	}, socketOption{
		// Ask the kernel to timestamp incoming packets
		Name:   "SO_TIMESTAMP_NEW",
		Level:  unix.SOL_SOCKET,
		Option: unix.SO_TIMESTAMP_NEW | unix.SOF_TIMESTAMPING_RX_SOFTWARE,
	})
)

// parseSocketControlMessage parses b and extract the number of drops
// returned (SO_RXQ_OVFL).
func parseSocketControlMessage(b []byte) (oobMessage, error) {
	result := oobMessage{}

	cmsgs, err := syscall.ParseSocketControlMessage(b)
	if err != nil {
		return result, err
	}

	for _, cmsg := range cmsgs {
		// We know that cmsg.Data is correctly aligned for the data it contains, so we can cast it.
		if cmsg.Header.Level == unix.SOL_SOCKET && cmsg.Header.Type == unix.SO_RXQ_OVFL {
			result.Drops = *(*uint32)(unsafe.Pointer(&cmsg.Data[0]))
		} else if cmsg.Header.Level == unix.SOL_SOCKET && cmsg.Header.Type == unix.SO_TIMESTAMP_NEW {
			// We only are interested in the current second.
			result.Received = time.Unix(*(*int64)(unsafe.Pointer(&cmsg.Data[0])), 0)
		}
	}
	return result, nil
}
