// Copyright 2019 The Go 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 linux package unix import ( "reflect" "testing" "unsafe" ) func Test_anyToSockaddr(t *testing.T) { tests := []struct { name string rsa *RawSockaddrAny sa Sockaddr err error }{ { name: "AF_TIPC bad addrtype", rsa: &RawSockaddrAny{ Addr: RawSockaddr{ Family: AF_TIPC, }, }, err: EINVAL, }, { name: "AF_TIPC NameSeq", rsa: sockaddrTIPCToAny(RawSockaddrTIPC{ Family: AF_TIPC, Addrtype: TIPC_SERVICE_RANGE, Scope: 1, Addr: (&TIPCServiceRange{ Type: 1, Lower: 2, Upper: 3, }).tipcAddr(), }), sa: &SockaddrTIPC{ Scope: 1, Addr: &TIPCServiceRange{ Type: 1, Lower: 2, Upper: 3, }, }, }, { name: "AF_TIPC Name", rsa: sockaddrTIPCToAny(RawSockaddrTIPC{ Family: AF_TIPC, Addrtype: TIPC_SERVICE_ADDR, Scope: 2, Addr: (&TIPCServiceName{ Type: 1, Instance: 2, Domain: 3, }).tipcAddr(), }), sa: &SockaddrTIPC{ Scope: 2, Addr: &TIPCServiceName{ Type: 1, Instance: 2, Domain: 3, }, }, }, { name: "AF_TIPC ID", rsa: sockaddrTIPCToAny(RawSockaddrTIPC{ Family: AF_TIPC, Addrtype: TIPC_SOCKET_ADDR, Scope: 3, Addr: (&TIPCSocketAddr{ Ref: 1, Node: 2, }).tipcAddr(), }), sa: &SockaddrTIPC{ Scope: 3, Addr: &TIPCSocketAddr{ Ref: 1, Node: 2, }, }, }, { name: "AF_MAX EAFNOSUPPORT", rsa: &RawSockaddrAny{ Addr: RawSockaddr{ Family: AF_MAX, }, }, err: EAFNOSUPPORT, }, // TODO: expand to support other families. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // TODO: parameterize fd (and its setup) when needed. sa, err := anyToSockaddr(0, tt.rsa) if err != tt.err { t.Fatalf("unexpected error: %v, want: %v", err, tt.err) } if !reflect.DeepEqual(sa, tt.sa) { t.Fatalf("unexpected Sockaddr:\n got: %#v\nwant: %#v", sa, tt.sa) } }) } } func TestSockaddrTIPC_sockaddr(t *testing.T) { tests := []struct { name string sa *SockaddrTIPC raw *RawSockaddrTIPC err error }{ { name: "no fields set", sa: &SockaddrTIPC{}, err: EINVAL, }, { name: "ID", sa: &SockaddrTIPC{ Scope: 1, Addr: &TIPCSocketAddr{ Ref: 1, Node: 2, }, }, raw: &RawSockaddrTIPC{ Family: AF_TIPC, Addrtype: TIPC_SOCKET_ADDR, Scope: 1, Addr: (&TIPCSocketAddr{ Ref: 1, Node: 2, }).tipcAddr(), }, }, { name: "NameSeq", sa: &SockaddrTIPC{ Scope: 2, Addr: &TIPCServiceRange{ Type: 1, Lower: 2, Upper: 3, }, }, raw: &RawSockaddrTIPC{ Family: AF_TIPC, Addrtype: TIPC_SERVICE_RANGE, Scope: 2, Addr: (&TIPCServiceRange{ Type: 1, Lower: 2, Upper: 3, }).tipcAddr(), }, }, { name: "Name", sa: &SockaddrTIPC{ Scope: 3, Addr: &TIPCServiceName{ Type: 1, Instance: 2, Domain: 3, }, }, raw: &RawSockaddrTIPC{ Family: AF_TIPC, Addrtype: TIPC_SERVICE_ADDR, Scope: 3, Addr: (&TIPCServiceName{ Type: 1, Instance: 2, Domain: 3, }).tipcAddr(), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { out, l, err := tt.sa.sockaddr() if err != tt.err { t.Fatalf("unexpected error: %v, want: %v", err, tt.err) } // Must be 0 on error or a fixed size otherwise. if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrTIPC) { t.Fatalf("unexpected Socklen: %d", l) } if out == nil { // No pointer to cast, return early. return } raw := (*RawSockaddrTIPC)(out) if !reflect.DeepEqual(raw, tt.raw) { t.Fatalf("unexpected RawSockaddrTIPC:\n got: %#v\nwant: %#v", raw, tt.raw) } }) } } func sockaddrTIPCToAny(in RawSockaddrTIPC) *RawSockaddrAny { var out RawSockaddrAny // Explicitly copy the contents of in into out to produce the correct // sockaddr structure, without relying on unsafe casting to a type of a // larger size. copy( (*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:], (*(*[SizeofSockaddrTIPC]byte)(unsafe.Pointer(&in)))[:], ) return &out }