blob: 68e3e817a99a6e69a54b0075767fc82204e7195f [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// +build !build_with_native_toolchain
// Ad-hoc unsafe encoding/decoding of C data types used by the
// protocol libc talks to netstack.
package netstack
import (
"fmt"
"reflect"
"unsafe"
)
// TODO(fxbug.dev/44347) We shouldn't need any of this includes after we remove
// C structs from the wire.
// #cgo CFLAGS: -D_GNU_SOURCE
// #cgo CFLAGS: -I${SRCDIR}/../../../../zircon/third_party/ulib/musl/include/
// #include <netinet/in.h>
import "C"
// copyAsBytes exists because of a combination of issues:
//
// 1: cgo omits bitfields of sizes that don't have a corresponding Go type.
// Note that padding is still consistent with C, which is why reflect.Type.Size
// produces the correct result.
//
// 2: encoding/binary.{Size,Write} ignores padding.
//
// Therefore, since we know our endianness is the same as the decoder's, we can
// do a terrible thing and just interpret the struct as a byte array.
func copyAsBytes(b []byte, val interface{}) int {
l := int(reflect.TypeOf(val).Size())
v := reflect.Indirect(reflect.ValueOf(&val))
return copy(b, *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Data: v.InterfaceData()[1],
Len: l,
Cap: l,
})))
}
func (v *C.struct_linger) Unmarshal(data []byte) error {
const size = C.sizeof_struct_linger
if n := copy((*[size]byte)(unsafe.Pointer(v))[:], data); n < size {
return fmt.Errorf("short %T: %d/%d", v, n, size)
}
return nil
}
func (v *C.struct_ip_mreq) Unmarshal(data []byte) error {
const size = C.sizeof_struct_ip_mreq
if n := copy((*[size]byte)(unsafe.Pointer(v))[:], data); n < size {
return fmt.Errorf("short %T: %d/%d", v, n, size)
}
return nil
}
func (v *C.struct_ip_mreqn) Unmarshal(data []byte) error {
const size = C.sizeof_struct_ip_mreqn
if n := copy((*[size]byte)(unsafe.Pointer(v))[:], data); n < size {
return fmt.Errorf("short %T: %d/%d", v, n, size)
}
return nil
}
func (v *C.struct_ipv6_mreq) Unmarshal(data []byte) error {
const size = C.sizeof_struct_ipv6_mreq
if n := copy((*[size]byte)(unsafe.Pointer(v))[:], data); n < size {
return fmt.Errorf("short %T: %d/%d", v, n, size)
}
return nil
}
func (v *C.struct_in_addr) Bytes() []byte {
return (*[C.sizeof_struct_in_addr]byte)(unsafe.Pointer(v))[:]
}
func (v *C.struct_in6_addr) Bytes() []byte {
return (*[C.sizeof_struct_in6_addr]byte)(unsafe.Pointer(v))[:]
}
func isZeros(b []byte) bool {
for _, b := range b {
if b != 0 {
return false
}
}
return true
}