package main
import "C"
import (
"context"
"encoding/binary"
"errors"
"fmt"
"net"
"net/netip"
"os"
"runtime/cgo"
"sync"
"time"
"unsafe"
"github.com/netsec-ethz/scion-apps/pkg/pan"
"github.com/scionproto/scion/pkg/daemon"
"github.com/scionproto/scion/private/app"
"github.com/scionproto/scion/private/app/flag"
)
const STREAM_HDR_SIZE = 4
const ADDR_HDR_SIZE = 32
func PanDuplicateHandle(handle C.uintptr_t) C.uintptr_t {
return C.uintptr_t(cgo.NewHandle(cgo.Handle(handle).Value()))
}
func PanDeleteHandle(handle C.uintptr_t) {
h := cgo.Handle(handle)
h.Delete()
}
func PanResolveUDPAddr(address *C.cchar_t, resolved *C.PanUDPAddr) C.PanError {
var add = C.GoString(address)
addr, err := pan.ResolveUDPAddr(context.Background(), add)
if err != nil {
if _, ok := err.(pan.HostNotFoundError); ok {
return C.PAN_ERR_HOSTNOTFOUND
}
return C.PAN_ERR_ADDR_RESOLUTION
}
ptr := (*C.PanUDPAddr)(unsafe.Pointer(resolved))
*ptr = C.PanUDPAddr(cgo.NewHandle(addr))
return C.PAN_ERR_OK
}
func PanResolveUDPAddrN(address *C.cchar_t, len C.int, resolved *C.PanUDPAddr) C.PanError {
var add = C.GoBytes(unsafe.Pointer(address), len)
addr, err := pan.ResolveUDPAddr(context.Background(), string(add))
if err != nil {
if _, ok := err.(pan.HostNotFoundError); ok {
return C.PAN_ERR_HOSTNOTFOUND
}
return C.PAN_ERR_ADDR_RESOLUTION
}
ptr := (*C.PanUDPAddr)(unsafe.Pointer(resolved))
*ptr = C.PanUDPAddr(cgo.NewHandle(addr))
return C.PAN_ERR_OK
}
func PanUDPAddrNew(ia *C.cuint64_t, ip *C.cuint8_t, ip_len C.int, port C.uint16_t) C.PanUDPAddr {
var addr pan.UDPAddr
addr.IA = (pan.IA)(binary.BigEndian.Uint64((*[8]byte)(unsafe.Pointer(ia))[:]))
if ip_len == 4 {
b := (*[4]byte)(unsafe.Pointer(ip))
addr.IP = netip.AddrFrom4(*b)
} else if ip_len == 16 {
b := (*[16]byte)(unsafe.Pointer(ip))
addr.IP = netip.AddrFrom16(*b)
} else {
return 0
}
addr.Port = uint16(port)
return C.PanUDPAddr(cgo.NewHandle(addr))
}
func PanUDPAddrGetIA(addr C.PanUDPAddr, ia *C.uint64_t) {
var buf = make([]byte, 8)
if ia != nil {
address := cgo.Handle(addr).Value().(pan.UDPAddr)
binary.BigEndian.PutUint64(buf, (uint64)(address.IA))
ptr := (*[8]C.uint8_t)(unsafe.Pointer(ia))
for i, b := range buf[:8] {
ptr[i] = C.uint8_t(b)
}
}
}
func PanUDPAddrIsIPv6(addr C.PanUDPAddr) C.int {
address := cgo.Handle(addr).Value().(pan.UDPAddr)
if address.IP.Is6() {
return 1
} else {
return 0
}
}
func PanUDPAddrGetIPv4(addr C.PanUDPAddr, ip4 *C.uint8_t) C.PanError {
if ip4 != nil {
address := cgo.Handle(addr).Value().(pan.UDPAddr)
if !address.IP.Is4() && !address.IP.Is4In6() {
return C.PAN_ERR_FAILED
}
ptr := (*[4]C.uint8_t)(unsafe.Pointer(ip4))
for i, b := range address.IP.As4() {
ptr[i] = C.uint8_t(b)
}
}
return C.PAN_ERR_OK
}
func PanUDPAddrGetIPv6(addr C.PanUDPAddr, ip6 *C.uint8_t) C.PanError {
if ip6 != nil {
address := cgo.Handle(addr).Value().(pan.UDPAddr)
ptr := (*[16]C.uint8_t)(unsafe.Pointer(ip6))
for i, b := range address.IP.As16() {
ptr[i] = C.uint8_t(b)
}
}
return C.PAN_ERR_OK
}
func PanUDPAddrGetPort(addr C.PanUDPAddr) C.uint16_t {
address := cgo.Handle(addr).Value().(pan.UDPAddr)
return C.uint16_t(address.Port)
}
func PanUDPAddrToString(addr C.PanUDPAddr) *C.char {
address := cgo.Handle(addr).Value().(pan.UDPAddr)
return C.CString(address.String())
}
func PanPathToString(path C.PanPath) *C.char {
p := cgo.Handle(path).Value().(*pan.Path)
return C.CString(p.String())
}
func PanPathGetFingerprint(path C.PanPath) C.PanPathFingerprint {
p := cgo.Handle(path).Value().(*pan.Path)
return (C.PanPathFingerprint)(cgo.NewHandle(p.Fingerprint))
}
func PanPathContainsInterface(path C.PanPath, iface C.PanPathInterface) C.int {
p := cgo.Handle(path).Value().(*pan.Path)
pi := cgo.Handle(iface).Value().(pan.PathInterface)
for _, c := range p.Metadata.Interfaces {
if c == pi {
return 1
}
}
return 0
}
func getPathHandles(paths []*pan.Path) []C.PanPath {
path_handles := make([]C.PanPath, len(paths))
for i, path := range paths {
path_handles[i] = (C.PanPath)(cgo.NewHandle(path))
}
return path_handles
}
func deletePathHandles(paths []C.PanPath) {
for _, path := range paths {
cgo.Handle(path).Delete()
}
}
func PanPathFingerprintAreEqual(
fp_a C.PanPathFingerprint, fp_b C.PanPathFingerprint) C.int {
a := cgo.Handle(fp_a).Value().(pan.PathFingerprint)
b := cgo.Handle(fp_b).Value().(pan.PathFingerprint)
if a == b {
return 1
} else {
return 0
}
}
type CPolicy struct {
filter_cb C.PanPolicyFilterFn
user_data C.uintptr_t
}
func NewCPolicy(filter C.PanPolicyFilterFn, user C.uintptr_t) *CPolicy {
return &CPolicy{
filter_cb: filter,
user_data: user,
}
}
func (p *CPolicy) Filter(paths []*pan.Path) []*pan.Path {
if len(paths) == 0 {
return paths
}
path_handles := getPathHandles(paths)
all_path_handles := make([]C.PanPath, len(path_handles))
copy(all_path_handles, path_handles)
defer deletePathHandles(all_path_handles)
count := len(path_handles)
newCount := int(
C.panCallPolicyFilter(p.filter_cb, &path_handles[0], C.size_t(count), p.user_data))
if newCount > 0 && newCount <= count {
filtered := make([]*pan.Path, 0, newCount)
for _, path := range path_handles[0:newCount] {
filtered = append(filtered, cgo.Handle(path).Value().(*pan.Path))
}
return filtered
}
return nil
}
func PanNewCPolicy(filter C.PanPolicyFilterFn, user C.uintptr_t) C.PanPolicy {
return (C.PanPolicy)(cgo.NewHandle(NewCPolicy(filter, user)))
}
func PanCPolicyTest(policy C.PanPolicy) {
var pol pan.Policy
if policy != 0 {
pol = cgo.Handle(policy).Value().(pan.Policy)
}
var test_paths []*pan.Path = TestPaths()
filtered_paths := pol.Filter(test_paths)
fmt.Printf("len filtered_paths: %v\n", len(filtered_paths))
}
func TestPaths() []*pan.Path {
unknown := time.Duration(0)
asA := pan.MustParseIA("1-0:0:1")
asB := pan.MustParseIA("1-0:0:2")
asC := pan.MustParseIA("1-0:0:3")
ifA1 := pan.PathInterface{IA: asA, IfID: 1}
ifB1 := pan.PathInterface{IA: asB, IfID: 1}
ifB2 := pan.PathInterface{IA: asB, IfID: 2}
ifC2 := pan.PathInterface{IA: asC, IfID: 2}
ifA3 := pan.PathInterface{IA: asA, IfID: 3}
ifC3 := pan.PathInterface{IA: asC, IfID: 3}
ifB4 := pan.PathInterface{IA: asB, IfID: 4}
ifC4 := pan.PathInterface{IA: asC, IfID: 4}
ifseqAC := []pan.PathInterface{ifA3, ifC3}
ifseqABC := []pan.PathInterface{ifA1, ifB1, ifB2, ifC2}
ifseqAB4C := []pan.PathInterface{ifA1, ifB1, ifB4, ifC4}
var paths []*pan.Path = []*pan.Path{
&pan.Path{
Source: asA,
Destination: asC,
Metadata: &pan.PathMetadata{
Interfaces: ifseqAC,
Latency: []time.Duration{1},
MTU: 2304,
},
},
&pan.Path{
Source: asA,
Destination: asC,
Metadata: &pan.PathMetadata{
Interfaces: ifseqABC,
Latency: []time.Duration{1, 1, 1},
MTU: 1500,
},
},
&pan.Path{
Source: asA,
Destination: asC,
Metadata: &pan.PathMetadata{
Interfaces: ifseqAB4C,
Latency: []time.Duration{unknown, 1, 2},
MTU: 1500,
},
},
}
return paths
}
type CSelector struct {
local_ia pan.IA
callbacks C.struct_PanSelectorCallbacks
user_data C.uintptr_t
}
func NewCSelector(callbacks *C.struct_PanSelectorCallbacks, user C.uintptr_t) *CSelector {
return &CSelector{
callbacks: *callbacks,
user_data: user,
}
}
func (s *CSelector) NewRemote(remote pan.UDPAddr) error {
return nil
}
func (s *CSelector) GetIA() pan.IA {
return s.local_ia
}
func (s *CSelector) Path(remote pan.UDPAddr) (*pan.Path, error) {
path := C.panCallSelectorPath(s.callbacks.path, s.user_data)
return cgo.Handle(path).Value().(*pan.Path), nil
}
func (s *CSelector) Initialize(local, remote pan.UDPAddr, paths []*pan.Path) {
s.local_ia = local.IA
loc := cgo.NewHandle(local)
rem := cgo.NewHandle(remote)
path_handles := getPathHandles(paths)
count := (C.size_t)(len(path_handles))
C.panCallSelectorInitialize(
s.callbacks.initialize, C.PanUDPAddr(loc), C.PanUDPAddr(rem),
&path_handles[0], count, s.user_data)
}
func (s *CSelector) Refresh(paths []*pan.Path) {
path_handles := getPathHandles(paths)
count := (C.size_t)(len(path_handles))
C.panCallSelectorRefresh(s.callbacks.refresh, &path_handles[0], count, s.user_data)
}
func (s *CSelector) PathDown(pf pan.PathFingerprint, pi pan.PathInterface) {
fingerprint := cgo.NewHandle(pf)
iface := cgo.NewHandle(pf)
C.panCallSelectorPathDown(s.callbacks.pathDown,
(C.PanPathFingerprint)(fingerprint),
(C.PanPathInterface)(iface),
s.user_data)
}
func (s *CSelector) Close() error {
C.panCallSelectorClose(s.callbacks.close, s.user_data)
return nil
}
func PanNewCSelector(callbacks *C.struct_PanSelectorCallbacks, user C.uintptr_t) C.PanSelector {
return (C.PanSelector)(cgo.NewHandle(NewCSelector(callbacks, user)))
}
type CReplySelector struct {
callbacks C.struct_PanReplySelCallbacks
user_data C.uintptr_t
}
func NewCReplySelector(callbacks *C.struct_PanReplySelCallbacks, user C.uintptr_t) *CReplySelector {
return &CReplySelector{
callbacks: *callbacks,
user_data: user,
}
}
func (s *CReplySelector) Path(remote pan.UDPAddr) (*pan.Path, error) {
rem := cgo.NewHandle(remote)
path := C.panCallReplySelPath(s.callbacks.path, C.PanUDPAddr(rem), s.user_data)
return cgo.Handle(path).Value().(*pan.Path), nil
}
func (s *CReplySelector) Initialize(local pan.IA) {
C.panCallReplySelInitialize(s.callbacks.initialize, C.cuint64_t(local), s.user_data)
}
func (s *CReplySelector) LocalAddrChanged(pan.UDPAddr) {
}
func (s *CReplySelector) Record(remote pan.UDPAddr, path *pan.Path) {
rem := cgo.NewHandle(remote)
handle := cgo.NewHandle(path)
C.panCallReplySelRecord(s.callbacks.record, C.PanUDPAddr(rem), C.PanPath(handle), s.user_data)
}
func (s *CReplySelector) PathDown(pf pan.PathFingerprint, pi pan.PathInterface) {
fingerprint := cgo.NewHandle(pf)
iface := cgo.NewHandle(pf)
C.panCallReplySelPathDown(s.callbacks.pathDown,
(C.PanPathFingerprint)(fingerprint),
(C.PanPathInterface)(iface),
s.user_data)
}
func (s *CReplySelector) Close() error {
C.panCallReplySelClose(s.callbacks.close, s.user_data)
return nil
}
func PanNewCReplySelector(
callbacks *C.struct_PanReplySelCallbacks, user C.uintptr_t) C.PanReplySelector {
return (C.PanReplySelector)(cgo.NewHandle(NewCReplySelector(callbacks, user)))
}
type SocketLike interface {
ReadFromVia(b []byte) (int, pan.UDPAddr, *pan.Path, error)
WriteToVia(b []byte, dst pan.UDPAddr, path *pan.Path) (int, error)
WriteTo(p []byte, addr net.Addr) (n int, err error)
ReadFrom(p []byte) (n int, addr net.Addr, err error)
SetReadDeadline(t time.Time) error
Close() error
}
func PanNewScionSocket(listen *C.cchar_t, n C.int) C.PanScionSocket {
addr := string(C.GoBytes(unsafe.Pointer(listen), n))
local, err := netip.ParseAddrPort(addr)
if err != nil {
l, e := pan.ParseUDPAddr(addr)
if e != nil {
panic(fmt.Sprintf("PanNewScionSocket error: %v", err))
} else {
local = netip.AddrPortFrom(l.IP, l.Port)
}
}
sock, err := pan.NewScionSocket(context.Background(), local)
if err != nil {
panic(fmt.Sprintf("%v", err))
}
if sock == nil {
fmt.Println("PanNewScionSocket: socket was nil!")
}
p := C.PanScionSocket(cgo.NewHandle(sock))
{
mu00.Lock()
cch := make(chan tuple00, 1)
chann00s[uintptr(p)] = cch
go fcn00(cch)
mu00.Unlock()
}
{
mu01.Lock()
cch := make(chan tuple01, 1)
chann01s[uintptr(p)] = cch
go fcn01(cch)
mu01.Unlock()
}
return p
}
func PanNewScionSocket2() C.PanScionSocket {
sock, err := pan.NewScionSocket2()
if err != nil {
panic(fmt.Sprintf("%v", err))
}
p := C.PanScionSocket(cgo.NewHandle(sock))
{
mu00.Lock()
cch := make(chan tuple00, 1)
chann00s[uintptr(p)] = cch
go fcn00(cch)
mu00.Unlock()
}
{
mu01.Lock()
cch := make(chan tuple01, 1)
chann01s[uintptr(p)] = cch
go fcn01(cch)
mu01.Unlock()
}
return p
}
func PanScionSocketBind(socket C.PanScionSocket, listen *C.cchar_t) C.PanError {
s := cgo.Handle(socket).Value().(pan.ScionSocket)
local := C.GoString(listen)
addr, err := netip.ParseAddrPort(local)
if err != nil {
return C.PAN_ERR_ADDR_SYNTAX
}
if err = s.Bind(context.Background(), addr); err != nil {
return C.PAN_ERR_FAILED
}
return C.PAN_ERR_OK
}
func PanScionSocketGetLocalAddr(socket C.PanScionSocket) *C.char {
s := cgo.Handle(socket).Value().(pan.ScionSocket)
return C.CString(s.LocalAddr().String())
}
func PanSocketLikeReadFromAsyncImpl(ch cgo.Handle, buffer *C.void, len C.int, from *C.PanUDPAddr, n *C.int, timeout_duration C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := ch.Value().(SocketLike)
p := unsafe.Slice((*byte)(unsafe.Pointer(buffer)), len)
if err := c.SetReadDeadline(time.Now()); err != nil {
return C.PAN_ERR_FAILED
}
read, add, err := c.ReadFrom(p)
if err != nil {
var t interface{ Timeout() bool }
if errors.As(err, &t) {
if t.Timeout() {
var chann01 chan tuple01
{
mu01.Lock()
conn := C.PanScionSocket(ch)
chann01 = chann01s[uintptr(conn)]
mu01.Unlock()
}
chann01 <- tuple01{p, c, from, nil, n, waker, arc_conn}
return C.PAN_ERR_WOULDBLOCK
} } else {
return C.PAN_ERR_FAILED
}
} else {
if add != nil {
*(*C.PanUDPAddr)(unsafe.Pointer(from)) = C.PanUDPAddr(cgo.NewHandle(add))
}
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(read)
}
return C.PAN_ERR_OK
}
return C.PAN_ERR_OK
}
func PanScionSocketReadFromAsync(conn C.PanScionSocket, buffer *C.void, len C.int, from *C.PanUDPAddr, n *C.int, timeout_duration C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn)
return PanSocketLikeReadFromAsyncImpl(c, buffer, len, from, n, timeout_duration, waker, arc_conn)
}
func PanScionSocketWriteToAsync(
conn C.PanScionSocket, buffer *C.cvoid_t, len C.int, to C.PanUDPAddr, n *C.int, timeout C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn)
return PanSocketLikeWriteToAsyncImpl(c, buffer, len, to, n, timeout, waker, arc_conn)
}
func PanScionSocketWriteToViaAsync(
conn C.PanScionSocket, buffer *C.cvoid_t, len C.int, to C.PanUDPAddr, path C.PanPath, n *C.int, timeout C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn)
return PanSocketLikeWriteToViaAsyncImpl(c, buffer, len, to, path, n, timeout, waker, arc_conn)
}
func PanSocketLikeReadFromAsyncViaImpl(ch cgo.Handle, buffer *C.void, len C.int, from *C.PanUDPAddr, path *C.PanPath, n *C.int, timeout_duration C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := ch.Value().(SocketLike)
p := unsafe.Slice((*byte)(unsafe.Pointer(buffer)), len)
if err := c.SetReadDeadline(time.Now()); err != nil {
return C.PAN_ERR_FAILED
}
read, add, from_path, err := c.ReadFromVia(p)
if err != nil {
var t interface{ Timeout() bool }
if errors.As(err, &t) {
if t.Timeout() {
var chann01 chan tuple01
{
mu01.Lock()
conn := C.PanScionSocket(ch)
chann01 = chann01s[uintptr(conn)]
mu01.Unlock()
}
chann01 <- tuple01{p, c, from, path, n, waker, arc_conn}
return C.PAN_ERR_WOULDBLOCK
} } else {
return C.PAN_ERR_FAILED
}
} else {
if from != nil {
*(*C.PanUDPAddr)(unsafe.Pointer(from)) = C.PanUDPAddr(cgo.NewHandle(add))
}
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(read)
}
if path != nil {
*(*C.PanPath)(unsafe.Pointer(path)) = C.PanPath(cgo.NewHandle(from_path))
}
return C.PAN_ERR_OK
}
panic("unreachable")
}
func PanScionSocketReadFromAsyncVia(conn C.PanScionSocket, buffer *C.void, len C.int, from *C.PanUDPAddr, path *C.PanPath, n *C.int, timeout_duration C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn)
return PanSocketLikeReadFromAsyncViaImpl(c, buffer, len, from, path, n, timeout_duration, waker, arc_conn)
}
func PanScionSocketClose(conn C.PanScionSocket) C.PanError {
handle := cgo.Handle(conn)
return SocketLikeCloseImpl(handle)
}
func PanScionSocketSetDeadline(conn C.PanScionSocket, t C.uint32_t) C.PanError {
c := cgo.Handle(conn).Value().(pan.ScionSocket)
c.SetDeadline(time.Now().Add(time.Duration(t) * time.Millisecond))
return C.PAN_ERR_OK
}
func PanScionSocketSetReadDeadline(conn C.PanScionSocket, t C.uint32_t) C.PanError {
c := cgo.Handle(conn).Value().(pan.ListenConn)
c.SetReadDeadline(time.Now().Add(time.Duration(t) * time.Millisecond))
return C.PAN_ERR_OK
}
func PanScionSocketSetWriteDeadline(conn C.PanScionSocket, t C.uint32_t) C.PanError {
c := cgo.Handle(conn).Value().(pan.ListenConn)
c.SetWriteDeadline(time.Now().Add(time.Duration(t) * time.Millisecond))
return C.PAN_ERR_OK
}
func PanListenUDP(
listen *C.cchar_t, selector C.PanReplySelector, conn *C.PanListenConn) C.PanError {
var sel pan.ReplySelector = nil
local, err := netip.ParseAddrPort(C.GoString(listen))
if err != nil {
return C.PAN_ERR_ADDR_SYNTAX
}
if selector != 0 {
sel = cgo.Handle(selector).Value().(pan.ReplySelector)
}
c, err := pan.ListenUDP(context.Background(), local, sel)
if err != nil {
return C.PAN_ERR_FAILED
}
ptr := (*C.PanListenConn)(unsafe.Pointer(conn))
p := C.PanListenConn(cgo.NewHandle(c))
*ptr = p
{
mu00.Lock()
cch := make(chan tuple00, 1)
chann00s[uintptr(p)] = cch
go fcn00(cch)
mu00.Unlock()
}
{
mu01.Lock()
cch := make(chan tuple01, 1)
chann01s[uintptr(p)] = cch
go fcn01(cch)
mu01.Unlock()
}
return C.PAN_ERR_OK
}
func PanListenConnReadFrom(
conn C.PanListenConn, buffer *C.void, len C.int, from *C.PanUDPAddr, n *C.int) C.PanError {
c := cgo.Handle(conn).Value().(pan.ListenConn)
p := unsafe.Slice((*byte)(unsafe.Pointer(buffer)), len)
read, addr, err := c.ReadFrom(p)
if err != nil {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else {
return C.PAN_ERR_FAILED
}
}
if from != nil {
*(*C.PanUDPAddr)(unsafe.Pointer(from)) = C.PanUDPAddr(cgo.NewHandle(addr))
}
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(read)
}
return C.PAN_ERR_OK
}
func PanListenConnReadFromAsync(conn C.PanListenConn, buffer *C.void, len C.int, from *C.PanUDPAddr, n *C.int, timeout_duration C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn)
return PanSocketLikeReadFromAsyncImpl(c, buffer, len, from, n, timeout_duration, waker, arc_conn)
}
type tuple01 struct {
buffer_out []byte
conn SocketLike from_out *C.PanUDPAddr path_out *C.PanPath bytes_read_out *C.int completion_waker C.OnCompletionWaker arc_conn *C.void
}
var chann01 chan tuple01
func fcn01(chann01 chan tuple01) {
for {
recv_op := <-chann01
buffer_out := recv_op.buffer_out
conn := recv_op.conn
from_out := recv_op.from_out
path_out := recv_op.path_out
bytes_read_out := recv_op.bytes_read_out
completion_waker := recv_op.completion_waker
arc_conn := recv_op.arc_conn
if errr := conn.SetReadDeadline(time.Time{}); errr != nil {
C.InvokeCompletionWaker(completion_waker, unsafe.Pointer(arc_conn), C.PAN_ERR_FAILED)
continue
}
var nn int
var addr pan.UDPAddr
var path_ *pan.Path
var errrr error
if path_out != nil {
nn, addr, path_, errrr = conn.ReadFromVia(buffer_out) } else {
n, a, e := conn.ReadFrom(buffer_out)
nn, addr, errrr = n, a.(pan.UDPAddr), e
}
if errrr == nil {
if from_out != nil {
*(*C.PanUDPAddr)(unsafe.Pointer(from_out)) = C.PanUDPAddr(cgo.NewHandle(addr))
}
if bytes_read_out != nil {
*(*C.int)(unsafe.Pointer(bytes_read_out)) = C.int(nn)
}
if path_out != nil {
*(*C.PanPath)(unsafe.Pointer(path_out)) = C.PanPath(cgo.NewHandle(path_))
}
C.InvokeCompletionWaker(completion_waker, unsafe.Pointer(arc_conn), C.PAN_ERR_OK)
continue
} else {
var tt interface{ Timeout() bool }
if errors.As(errrr, &tt) {
if tt.Timeout() {
C.InvokeCompletionWaker(completion_waker, unsafe.Pointer(arc_conn), C.PAN_ERR_DEADLINE)
continue
}
}
C.InvokeCompletionWaker(completion_waker, unsafe.Pointer(arc_conn), C.PAN_ERR_FAILED)
}
}
}
func PanListenConnReadFromAsyncVia(conn C.PanListenConn, buffer *C.void, len C.int, from *C.PanUDPAddr, path *C.PanPath, n *C.int, timeout_duration C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn)
return PanSocketLikeReadFromAsyncViaImpl(c, buffer, len, from, path, n, timeout_duration, waker, arc_conn)
}
func PanListenConnReadFromVia(
conn C.PanListenConn, buffer *C.void, len C.int,
from *C.PanUDPAddr, path *C.PanPath, n *C.int) C.PanError {
c := cgo.Handle(conn).Value().(pan.ListenConn)
p := unsafe.Slice((*byte)(unsafe.Pointer(buffer)), len)
read, addr, via, err := c.ReadFromVia(p)
if err != nil {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else {
return C.PAN_ERR_FAILED
}
}
if from != nil {
*(*C.PanUDPAddr)(unsafe.Pointer(from)) = C.PanUDPAddr(cgo.NewHandle(addr))
}
if path != nil {
*(*C.PanPath)(unsafe.Pointer(path)) = C.PanPath(cgo.NewHandle(via))
}
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(read)
}
return C.PAN_ERR_OK
}
func PanListenConnWriteTo(
conn C.PanListenConn, buffer *C.cvoid_t, len C.int, to C.PanUDPAddr, n *C.int) C.PanError {
c := cgo.Handle(conn).Value().(pan.ListenConn)
p := C.GoBytes(unsafe.Pointer(buffer), len)
addr := cgo.Handle(to).Value().(pan.UDPAddr)
written, err := c.WriteTo(p, addr)
if err != nil {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else if errors.Is(err, pan.ErrNoPath) {
return C.PAN_ERR_NO_PATH
} else {
return C.PAN_ERR_FAILED
}
}
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(written)
}
return C.PAN_ERR_OK
}
func PanSocketLikeWriteToViaAsyncImpl(
ch cgo.Handle, buffer *C.cvoid_t, len C.int, to C.PanUDPAddr, path C.PanPath, n *C.int, timeout C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := ch.Value().(SocketLike)
p := C.GoBytes(unsafe.Pointer(buffer), len)
addr := cgo.Handle(to).Value().(pan.UDPAddr)
via := cgo.Handle(path).Value().(*pan.Path)
var err error
var written = 0
if true {
if true {
if true {
var chann00 chan tuple00
{
mu00.Lock()
conn := C.PanScionSocket(ch)
chann00 = chann00s[uintptr(conn)]
mu00.Unlock()
}
chann00 <- tuple00{p, addr, via, n, waker, c, arc_conn}
return C.PAN_ERR_WOULDBLOCK
} else {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else if errors.Is(err, pan.ErrNoPath) {
return C.PAN_ERR_NO_PATH
} else {
return C.PAN_ERR_FAILED
}
}
} else {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else if errors.Is(err, pan.ErrNoPath) {
return C.PAN_ERR_NO_PATH
} else {
return C.PAN_ERR_FAILED
}
}
} else {
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(written)
}
return C.PAN_ERR_OK
}
panic("unreachable")
}
func PanSocketLikeWriteToAsyncImpl(
ch cgo.Handle, buffer *C.cvoid_t, len C.int, to C.PanUDPAddr, n *C.int, timeout C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := ch.Value().(SocketLike)
p := C.GoBytes(unsafe.Pointer(buffer), len)
addr := cgo.Handle(to).Value().(pan.UDPAddr)
var err error
var written = 0
if true {
if true {
if true {
var chann00 chan tuple00
{
mu00.Lock()
conn := C.PanScionSocket(ch)
chann00 = chann00s[uintptr(conn)]
mu00.Unlock()
}
chann00 <- tuple00{p, addr, nil, n, waker, c, arc_conn}
return C.PAN_ERR_WOULDBLOCK
} else {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else if errors.Is(err, pan.ErrNoPath) {
return C.PAN_ERR_NO_PATH
} else {
return C.PAN_ERR_FAILED
}
}
} else {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else if errors.Is(err, pan.ErrNoPath) {
return C.PAN_ERR_NO_PATH
} else {
return C.PAN_ERR_FAILED
}
}
} else {
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(written)
}
return C.PAN_ERR_OK
}
panic("unreachable")
}
func PanListenConnWriteToAsync(
conn C.PanListenConn, buffer *C.cvoid_t, len C.int, to C.PanUDPAddr, n *C.int, timeout C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn)
return PanSocketLikeWriteToAsyncImpl(c, buffer, len, to, n, timeout, waker, arc_conn)
}
type tuple00 struct {
send_buff []byte
to_addr pan.UDPAddr to_path *pan.Path
written *C.int
completer C.OnCompletionWaker
conn SocketLike arc_conn *C.void
}
func fcn00(chann00 chan tuple00) {
for {
recv_operation := <-chann00
send_buff := recv_operation.send_buff
to_addr := recv_operation.to_addr
to_path := recv_operation.to_path
written := recv_operation.written
completer := recv_operation.completer
conn := recv_operation.conn
arc_conn := recv_operation.arc_conn
var out int = 0
var e error
if to_path != nil {
out, e = conn.WriteToVia(send_buff, to_addr, to_path)
} else {
out, e = conn.WriteTo(send_buff, to_addr)
}
if e == nil {
if written != nil {
*(*C.int)(unsafe.Pointer(written)) = C.int(out)
}
C.InvokeCompletionWaker(completer, unsafe.Pointer(arc_conn), C.PAN_ERR_OK)
} else {
var tt interface{ Timeout() bool }
if errors.As(e, &tt) {
if tt.Timeout() { C.InvokeCompletionWaker(completer, unsafe.Pointer(arc_conn), C.PAN_ERR_DEADLINE)
continue
}
}
C.InvokeCompletionWaker(completer, unsafe.Pointer(arc_conn), C.PAN_ERR_FAILED)
}
}
}
func PanListenConnWriteToViaAsync(
conn C.PanListenConn, buffer *C.cvoid_t, len C.int, to C.PanUDPAddr, path C.PanPath, n *C.int, timeout C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn)
return PanSocketLikeWriteToViaAsyncImpl(c, buffer, len, to, path, n, timeout, waker, arc_conn)
}
func PanListenConnWriteToVia(
conn C.PanListenConn, buffer *C.cvoid_t, len C.int,
to C.PanUDPAddr, path C.PanPath, n *C.int) C.PanError {
c := cgo.Handle(conn).Value().(pan.ListenConn)
p := C.GoBytes(unsafe.Pointer(buffer), len)
addr := cgo.Handle(to).Value().(pan.UDPAddr)
via := cgo.Handle(path).Value().(*pan.Path)
written, err := c.WriteToVia(p, addr, via)
if err != nil {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else {
return C.PAN_ERR_FAILED
}
}
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(written)
}
return C.PAN_ERR_OK
}
func PanListenConnLocalAddr(conn C.PanListenConn) C.PanUDPAddr {
c := cgo.Handle(conn).Value().(pan.ListenConn)
return C.PanUDPAddr(cgo.NewHandle(c.LocalAddr()))
}
func PanListenConnSetDeadline(conn C.PanListenConn, t C.uint32_t) C.PanError {
c := cgo.Handle(conn).Value().(pan.ListenConn)
c.SetDeadline(time.Now().Add(time.Duration(t) * time.Millisecond))
return C.PAN_ERR_OK
}
func PanListenConnSetReadDeadline(conn C.PanListenConn, t C.uint32_t) C.PanError {
c := cgo.Handle(conn).Value().(pan.ListenConn)
c.SetReadDeadline(time.Now().Add(time.Duration(t) * time.Millisecond))
return C.PAN_ERR_OK
}
func PanListenConnSetWriteDeadline(conn C.PanListenConn, t C.uint32_t) C.PanError {
c := cgo.Handle(conn).Value().(pan.ListenConn)
c.SetWriteDeadline(time.Now().Add(time.Duration(t) * time.Millisecond))
return C.PAN_ERR_OK
}
func PanListenConnClose(conn C.PanListenConn) C.PanError {
handle := cgo.Handle(conn)
return SocketLikeCloseImpl(handle)
}
func SocketLikeCloseImpl(handle cgo.Handle) C.PanError {
conn := C.PanScionSocket(handle)
err := handle.Value().(SocketLike).Close()
{
mu00.Lock()
close(chann00s[uintptr(conn)])
delete(chann00s, uintptr(conn))
mu00.Unlock()
}
{
mu01.Lock()
close(chann01s[uintptr(conn)])
delete(chann01s, uintptr(conn))
mu01.Unlock()
}
if err != nil {
return C.PAN_ERR_FAILED
}
return C.PAN_ERR_OK
}
func PanDialUDP(
local *C.cchar_t, remote C.PanUDPAddr,
policy C.PanPolicy,
selector C.PanSelector,
conn *C.PanConn) C.PanError {
var loc netip.AddrPort = netip.AddrPort{}
var pol pan.Policy = nil
var sel pan.Selector = nil
var err error
if local != nil {
loc, err = netip.ParseAddrPort(C.GoString(local))
if err != nil {
return C.PAN_ERR_ADDR_SYNTAX
}
}
rem := cgo.Handle(remote).Value().(pan.UDPAddr)
if policy != 0 {
pol = cgo.Handle(policy).Value().(pan.Policy)
}
if selector != 0 {
sel = cgo.Handle(selector).Value().(pan.Selector)
}
c, err := pan.DialUDP(context.Background(), loc, rem, pol, sel)
if err != nil {
return C.PAN_ERR_FAILED
}
ptr := (*C.PanConn)(unsafe.Pointer(conn))
p := C.PanConn(cgo.NewHandle(c))
*ptr = p
{
mu02.Lock()
cch := make(chan tuple02, 1)
chann02s[uintptr(p)] = cch
go fcn02(cch)
mu02.Unlock()
}
{
mu03.Lock()
cch := make(chan tuple03, 1)
chann03s[uintptr(p)] = cch
go fcn03(cch)
mu03.Unlock()
}
return C.PAN_ERR_OK
}
func PanConnRead(conn C.PanConn, buffer *C.void, len C.int, n *C.int) C.PanError {
c := cgo.Handle(conn).Value().(pan.Conn)
p := unsafe.Slice((*byte)(unsafe.Pointer(buffer)), len)
read, err := c.Read(p)
if err != nil {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else {
return C.PAN_ERR_FAILED
}
}
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(read)
}
return C.PAN_ERR_OK
}
func PanConnReadVia(
conn C.PanConn, buffer *C.void, len C.int, path *C.PanPath, n *C.int) C.PanError {
c := cgo.Handle(conn).Value().(pan.Conn)
p := unsafe.Slice((*byte)(unsafe.Pointer(buffer)), len)
read, via, err := c.ReadVia(p)
if err != nil {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else {
return C.PAN_ERR_FAILED
}
}
if path != nil {
*(*C.PanPath)(unsafe.Pointer(path)) = C.PanPath(cgo.NewHandle(via))
}
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(read)
}
return C.PAN_ERR_OK
}
type tuple02 struct {
buffer_out []byte
conn pan.Conn path_out *C.PanPath
bytes_read_out *C.int
completion_waker C.OnCompletionWaker
arc_conn *C.void
}
func fcn02(chann02 chan tuple02) {
for {
recv_op := <-chann02
buffer_out := recv_op.buffer_out
conn := recv_op.conn
path_out := recv_op.path_out
bytes_read_out := recv_op.bytes_read_out
completion_waker := recv_op.completion_waker
arc_conn := recv_op.arc_conn
if errr := conn.SetReadDeadline(time.Time{}); errr != nil {
C.InvokeCompletionWaker(completion_waker, unsafe.Pointer(arc_conn), C.PAN_ERR_FAILED)
continue
}
var nn int
var path_ *pan.Path
var errrr error
if path_out != nil {
nn, path_, errrr = conn.ReadVia(buffer_out) } else {
nn, errrr = conn.Read(buffer_out)
}
if errrr == nil {
if bytes_read_out != nil {
*(*C.int)(unsafe.Pointer(bytes_read_out)) = C.int(nn)
}
if path_ != nil {
*(*C.PanPath)(unsafe.Pointer(path_out)) = C.PanPath(cgo.NewHandle(path_))
}
C.InvokeCompletionWaker(completion_waker, unsafe.Pointer(arc_conn), C.PAN_ERR_OK)
continue
} else {
var tt interface{ Timeout() bool }
if errors.As(errrr, &tt) {
if tt.Timeout() {
C.InvokeCompletionWaker(completion_waker, unsafe.Pointer(arc_conn), C.PAN_ERR_DEADLINE)
continue
}
}
C.InvokeCompletionWaker(completion_waker, unsafe.Pointer(arc_conn), C.PAN_ERR_FAILED)
}
}
}
func PanConnReadViaAsync(
conn C.PanConn, buffer *C.void, len C.int, path *C.PanPath, n *C.int, timeout C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn).Value().(pan.Conn)
p := unsafe.Slice((*byte)(unsafe.Pointer(buffer)), len)
if erer := c.SetReadDeadline(time.Now()); erer != nil {
return C.PAN_ERR_FAILED
}
read, from_path, err := c.ReadVia(p)
if err != nil {
var t interface{ Timeout() bool }
if errors.As(err, &t) {
if t.Timeout() {
var chann02 chan tuple02
{
mu02.Lock()
chann02 = chann02s[uintptr(conn)]
mu02.Unlock()
}
chann02 <- tuple02{p, c, path, n, waker, arc_conn}
return C.PAN_ERR_WOULDBLOCK
} } else {
return C.PAN_ERR_FAILED
}
} else {
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(read)
}
if path != nil {
*(*C.PanPath)(unsafe.Pointer(path)) = C.PanPath(cgo.NewHandle(from_path))
}
return C.PAN_ERR_OK
}
panic("unreachable")
}
func PanConnWrite(conn C.PanListenConn, buffer *C.cvoid_t, len C.int, n *C.int) C.PanError {
c := cgo.Handle(conn).Value().(pan.Conn)
p := C.GoBytes(unsafe.Pointer(buffer), len)
written, err := c.Write(p)
if err != nil {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else if errors.Is(err, pan.ErrNoPath) {
return C.PAN_ERR_NO_PATH
} else {
return C.PAN_ERR_FAILED
}
}
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(written)
}
return C.PAN_ERR_OK
}
type tuple03 struct {
send_buff []byte
written *C.int
to_path *pan.Path
completer C.OnCompletionWaker
conn pan.Conn
arc_conn *C.void
}
func fcn03(chann03 chan tuple03) {
for {
recv_op := <-chann03
send_buff := recv_op.send_buff
written := recv_op.written
to_path := recv_op.to_path
completer := recv_op.completer
conn := recv_op.conn
arc_conn := recv_op.arc_conn
var out int = 0
var e error
if to_path == nil {
out, e = conn.Write(send_buff)
} else {
out, e = conn.WriteVia(to_path, send_buff)
}
if e == nil {
if written != nil {
*(*C.int)(unsafe.Pointer(written)) = C.int(out)
}
C.InvokeCompletionWaker(completer, unsafe.Pointer(arc_conn), C.PAN_ERR_OK)
} else {
var tt interface{ Timeout() bool }
if errors.As(e, &tt) {
if tt.Timeout() {
C.InvokeCompletionWaker(completer, unsafe.Pointer(arc_conn), C.PAN_ERR_DEADLINE)
continue
}
}
C.InvokeCompletionWaker(completer, unsafe.Pointer(arc_conn), C.PAN_ERR_FAILED)
continue
}
}
}
func PanConnWriteAsync(conn C.PanListenConn, buffer *C.cvoid_t, len C.int, n *C.int, timeout C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn).Value().(pan.Conn)
p := C.GoBytes(unsafe.Pointer(buffer), len)
var err error
var written = 0
if true {
if true {
if true { var chann03 chan tuple03
{
mu03.Lock()
chann03 = chann03s[uintptr(conn)]
mu03.Unlock()
}
chann03 <- tuple03{p, n, nil, waker, c, arc_conn}
return C.PAN_ERR_WOULDBLOCK
} else {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else if errors.Is(err, pan.ErrNoPath) {
return C.PAN_ERR_NO_PATH
} else {
return C.PAN_ERR_FAILED
}
}
} else {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else if errors.Is(err, pan.ErrNoPath) {
return C.PAN_ERR_NO_PATH
} else {
return C.PAN_ERR_FAILED
}
}
} else {
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(written)
}
return C.PAN_ERR_OK
}
panic("unreachable")
}
var envFlags flag.SCIONEnvironment
var service daemon.Service
var mu00 sync.Mutex
var mu01 sync.Mutex
var mu02 sync.Mutex
var mu03 sync.Mutex
var chann00s map[uintptr]chan tuple00
var chann01s map[uintptr]chan tuple01
var chann02s map[uintptr]chan tuple02
var chann03s map[uintptr]chan tuple03
func init() {
if err := envFlags.LoadExternalVars(); err != nil {
panic(fmt.Sprintf("pan initialization failed: %v", err))
}
daemonAddr := envFlags.Daemon()
service = daemon.NewService(daemonAddr)
chann00s = make(map[uintptr]chan tuple00)
chann01s = make(map[uintptr]chan tuple01)
chann02s = make(map[uintptr]chan tuple02)
chann03s = make(map[uintptr]chan tuple03)
}
func GetLocalIA() uint64 {
ctx, cancelF := context.WithTimeout(context.Background(), time.Second)
defer cancelF()
conn, err := service.Connect(ctx)
if err != nil {
panic(fmt.Sprintf("connecting to SCION Daemon: %v", err))
}
defer conn.Close()
info, err := app.QueryASInfo(ctx, conn)
if err != nil {
panic(fmt.Sprintf("%v", err))
}
return uint64(info.IA)
}
func PanConnWriteVia(
conn C.PanListenConn, buffer *C.cvoid_t, len C.int, path C.PanPath, n *C.int) C.PanError {
c := cgo.Handle(conn).Value().(pan.Conn)
p := C.GoBytes(unsafe.Pointer(buffer), len)
via := cgo.Handle(path).Value().(*pan.Path)
written, err := c.WriteVia(via, p)
if err != nil {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else {
return C.PAN_ERR_FAILED
}
}
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(written)
}
return C.PAN_ERR_OK
}
func PanConnWriteViaAsync(
conn C.PanListenConn, buffer *C.cvoid_t, len C.int, path C.PanPath, n *C.int, timeout C.int, waker C.OnCompletionWaker, arc_conn *C.void) C.PanError {
c := cgo.Handle(conn).Value().(pan.Conn)
p := C.GoBytes(unsafe.Pointer(buffer), len)
via := cgo.Handle(path).Value().(*pan.Path)
var err error
var written = 0
if true {
if true {
if true {
var chann03 chan tuple03
{
mu03.Lock()
chann03 = chann03s[uintptr(conn)]
mu03.Unlock()
}
chann03 <- tuple03{p, n, via, waker, c, arc_conn}
return C.PAN_ERR_WOULDBLOCK
} else {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else if errors.Is(err, pan.ErrNoPath) {
return C.PAN_ERR_NO_PATH
} else {
return C.PAN_ERR_FAILED
}
}
} else {
if errors.Is(err, os.ErrDeadlineExceeded) {
return C.PAN_ERR_DEADLINE
} else if errors.Is(err, pan.ErrNoPath) {
return C.PAN_ERR_NO_PATH
} else {
return C.PAN_ERR_FAILED
}
}
} else {
if n != nil {
*(*C.int)(unsafe.Pointer(n)) = C.int(written)
}
return C.PAN_ERR_OK
}
panic("unreachable")
}
func PanConnLocalAddr(conn C.PanConn) C.PanUDPAddr {
c := cgo.Handle(conn).Value().(pan.Conn)
return C.PanUDPAddr(cgo.NewHandle(c.LocalAddr()))
}
func PanConnRemoteAddr(conn C.PanConn) C.PanUDPAddr {
c := cgo.Handle(conn).Value().(pan.Conn)
return C.PanUDPAddr(cgo.NewHandle(c.RemoteAddr()))
}
func PanConnSetDeadline(conn C.PanConn, t C.uint32_t) C.PanError {
c := cgo.Handle(conn).Value().(pan.Conn)
c.SetDeadline(time.Now().Add(time.Duration(t) * time.Millisecond))
return C.PAN_ERR_OK
}
func PanConnSetReadDeadline(conn C.PanConn, t C.uint32_t) C.PanError {
c := cgo.Handle(conn).Value().(pan.Conn)
c.SetReadDeadline(time.Now().Add(time.Duration(t) * time.Millisecond))
return C.PAN_ERR_OK
}
func PanConnSetWriteDeadline(conn C.PanConn, t C.uint32_t) C.PanError {
c := cgo.Handle(conn).Value().(pan.Conn)
c.SetWriteDeadline(time.Now().Add(time.Duration(t) * time.Millisecond))
return C.PAN_ERR_OK
}
func PanConnClose(conn C.PanConn) C.PanError {
handle := cgo.Handle(conn)
err := handle.Value().(pan.Conn).Close()
{
mu02.Lock()
close(chann02s[uintptr(conn)])
delete(chann02s, uintptr(conn))
mu02.Unlock()
}
{
mu03.Lock()
close(chann03s[uintptr(conn)])
delete(chann03s, uintptr(conn))
mu03.Unlock()
}
if err != nil {
return C.PAN_ERR_FAILED
}
return C.PAN_ERR_OK
}
func PanNewListenSockAdapter(
pan_conn C.PanListenConn, listen_addr *C.cchar_t, client_addr *C.cchar_t,
adapter *C.PanListenSockAdapter) C.PanError {
ls, err := NewListenSockAdapter(
cgo.Handle(pan_conn).Value().(SocketLike),
C.GoString(listen_addr),
C.GoString(client_addr))
if err != nil {
fmt.Println("PanNewListenSockAdapter failed")
return C.PAN_ERR_FAILED
}
ptr := (*C.PanListenSockAdapter)(unsafe.Pointer(adapter))
*ptr = C.PanListenSockAdapter(cgo.NewHandle(ls))
return C.PAN_ERR_OK
}
func PanNewListenSockAdapter2(
pan_conn C.PanListenConn, listen_addr *C.cchar_t, len1 C.int, client_addr *C.cchar_t, len2 C.int,
adapter *C.PanListenSockAdapter) C.PanError {
var listen = C.GoBytes(unsafe.Pointer(listen_addr), len1)
var client = C.GoBytes(unsafe.Pointer(client_addr), len2)
ls, err := NewListenSockAdapter(
cgo.Handle(pan_conn).Value().(SocketLike),
string(listen),
string(client))
if err != nil {
fmt.Println("PanNewListenSockAdapter failed")
return C.PAN_ERR_FAILED
}
ptr := (*C.PanListenSockAdapter)(unsafe.Pointer(adapter))
*ptr = C.PanListenSockAdapter(cgo.NewHandle(ls))
return C.PAN_ERR_OK
}
func PanListenSockAdapterClose(adapter C.PanListenSockAdapter) C.PanError {
ls := cgo.Handle(adapter).Value().(*ListenSockAdapter)
ls.Close()
return C.PAN_ERR_OK
}
type ListenSockAdapter struct {
pan_conn SocketLike
unix_conn *net.UnixConn
unix_remote *net.UnixAddr
listen_addr string
}
func NewListenSockAdapter(
pan_conn SocketLike, listen_addr string, client_addr string) (*ListenSockAdapter, error) {
listen, err := net.ResolveUnixAddr("unixgram", listen_addr)
if err != nil {
fmt.Printf("NewListenSockAdapter failed to resolv listen: %v\n", err)
return nil, err
}
remote, err := net.ResolveUnixAddr("unixgram", client_addr)
if err != nil {
fmt.Printf("NewListenSockAdapter failed to resolv client: %v\n", err)
return nil, err
}
os.Remove(listen_addr)
unix_conn, err := net.ListenUnixgram("unixgram", listen)
if err != nil {
fmt.Printf("NewListenSockAdapter failed to listen: %v\n", err)
return nil, err
}
adapter := &ListenSockAdapter{
pan_conn: pan_conn,
unix_conn: unix_conn,
unix_remote: remote,
listen_addr: listen_addr,
}
go adapter.panToUnix()
go adapter.unixToPan()
return adapter, nil
}
func (ls *ListenSockAdapter) Close() error {
ls.pan_conn.Close()
ls.unix_conn.Close()
os.Remove(ls.listen_addr)
return nil
}
func (ls *ListenSockAdapter) panToUnix() {
var buffer = make([]byte, 4096)
for {
read, from, err := ls.pan_conn.ReadFrom(buffer[ADDR_HDR_SIZE:])
if err != nil {
fmt.Printf("failed to read from pan: %v\n", err)
return
}
pan_from, ok := from.(pan.UDPAddr)
if !ok {
panic("logic error")
}
binary.BigEndian.PutUint64(buffer, (uint64)(pan_from.IA))
if pan_from.IP.Is4() {
buffer[8] = 4
for i, b := range pan_from.IP.As4() {
buffer[12+i] = b
}
} else {
buffer[8] = 16
for i, b := range pan_from.IP.As16() {
buffer[12+i] = b
}
}
binary.LittleEndian.PutUint16(buffer[28:30], pan_from.Port)
message := buffer[:ADDR_HDR_SIZE+read]
_, err = ls.unix_conn.WriteToUnix(message, ls.unix_remote)
if err != nil {
fmt.Printf("failed to write to unix: %v", err)
return
}
}
}
func (ls *ListenSockAdapter) unixToPan() {
var buffer = make([]byte, 4096)
for {
read, _, err := ls.unix_conn.ReadFromUnix(buffer)
if err != nil {
fmt.Printf("failed to read from unix: %v\n", err)
return
}
if read < ADDR_HDR_SIZE {
fmt.Println("WARNING: received less than proxy header from unix")
continue
}
var to pan.UDPAddr
to.IA = (pan.IA)(binary.BigEndian.Uint64(buffer[:8]))
addr_len := binary.LittleEndian.Uint32(buffer[8:12])
if addr_len == 4 {
to.IP = netip.AddrFrom4(*(*[4]byte)(buffer[12:16]))
} else if addr_len == 16 {
to.IP = netip.AddrFrom16(*(*[16]byte)(buffer[12:28]))
} else {
fmt.Println("WARNING: invalid proxy header read from unix")
continue
}
to.Port = binary.LittleEndian.Uint16(buffer[28:30])
_, err = ls.pan_conn.WriteTo(buffer[ADDR_HDR_SIZE:read], to)
if err != nil {
fmt.Printf("failed to write to pan: %v\n", err)
return
}
}
}
func PanNewConnSockAdapter(
pan_conn C.PanConn, listen_addr *C.cchar_t, client_addr *C.cchar_t,
adapter *C.PanConnSockAdapter) C.PanError {
ls, err := NewConnSockAdapter(
cgo.Handle(pan_conn).Value().(pan.Conn),
C.GoString(listen_addr),
C.GoString(client_addr))
if err != nil {
return C.PAN_ERR_FAILED
}
ptr := (*C.PanConnSockAdapter)(unsafe.Pointer(adapter))
*ptr = C.PanConnSockAdapter(cgo.NewHandle(ls))
return C.PAN_ERR_OK
}
func PanConnSockAdapterClose(adapter C.PanConnSockAdapter) C.PanError {
ls := cgo.Handle(adapter).Value().(*ConnSockAdapter)
ls.Close()
return C.PAN_ERR_OK
}
type ConnSockAdapter struct {
pan_conn pan.Conn
unix_conn *net.UnixConn
unix_remote *net.UnixAddr
listen_addr string
}
func NewConnSockAdapter(
pan_conn pan.Conn, listen_addr string, client_addr string) (*ConnSockAdapter, error) {
listen, err := net.ResolveUnixAddr("unixgram", listen_addr)
if err != nil {
return nil, err
}
remote, err := net.ResolveUnixAddr("unixgram", client_addr)
if err != nil {
return nil, err
}
os.Remove(listen_addr)
unix_conn, err := net.ListenUnixgram("unixgram", listen)
if err != nil {
return nil, err
}
adapter := &ConnSockAdapter{
pan_conn: pan_conn,
unix_conn: unix_conn,
unix_remote: remote,
listen_addr: listen_addr,
}
go adapter.panToUnix()
go adapter.unixToPan()
return adapter, nil
}
func (cs *ConnSockAdapter) Close() error {
cs.pan_conn.Close()
cs.unix_conn.Close()
os.Remove(cs.listen_addr)
return nil
}
func (cs *ConnSockAdapter) panToUnix() {
var buffer = make([]byte, 4096)
for {
read, err := cs.pan_conn.Read(buffer)
if err != nil {
return
}
_, err = cs.unix_conn.WriteToUnix(buffer[:read], cs.unix_remote)
if err != nil {
return
}
}
}
func (cs *ConnSockAdapter) unixToPan() {
var buffer = make([]byte, 4096)
for {
read, _, err := cs.unix_conn.ReadFromUnix(buffer)
if err != nil {
return
}
_, err = cs.pan_conn.Write(buffer[:read])
if err != nil {
return
}
}
}
func PanNewListenSSockAdapter(
pan_conn C.PanListenConn, listen_addr *C.cchar_t,
adapter *C.PanListenSSockAdapter) C.PanError {
ls, err := NewListenSSockAdapter(
cgo.Handle(pan_conn).Value().(pan.ListenConn),
C.GoString(listen_addr))
if err != nil {
return C.PAN_ERR_FAILED
}
ptr := (*C.PanListenSSockAdapter)(unsafe.Pointer(adapter))
*ptr = C.PanListenSSockAdapter(cgo.NewHandle(ls))
return C.PAN_ERR_OK
}
func PanListenSSockAdapterClose(adapter C.PanListenSSockAdapter) C.PanError {
ls := cgo.Handle(adapter).Value().(*ListenSSockAdapter)
ls.Close()
return C.PAN_ERR_OK
}
type ListenSSockAdapter struct {
pan_conn SocketLike
unix_listener *net.UnixListener
unix_conn *net.UnixConn
}
func NewListenSSockAdapter(
pan_conn SocketLike, listen_addr string) (*ListenSSockAdapter, error) {
listen, err := net.ResolveUnixAddr("unix", listen_addr)
if err != nil {
return nil, err
}
os.Remove(listen_addr)
unix_listener, err := net.ListenUnix("unix", listen)
if err != nil {
return nil, err
}
unix_listener.SetUnlinkOnClose(true)
adapter := &ListenSSockAdapter{
pan_conn: pan_conn,
unix_listener: unix_listener,
unix_conn: nil,
}
go adapter.waitForConn()
return adapter, nil
}
func (ls *ListenSSockAdapter) waitForConn() {
conn, err := ls.unix_listener.AcceptUnix()
defer ls.unix_listener.Close()
if err != nil {
return
}
ls.unix_conn = conn
go ls.panToUnix()
go ls.unixToPan()
}
func (ls *ListenSSockAdapter) Close() error {
ls.pan_conn.Close()
ls.unix_conn.Close()
return nil
}
func (ls *ListenSSockAdapter) panToUnix() {
var buffer = make([]byte, 4096)
for {
read, from, err := ls.pan_conn.ReadFrom(buffer[STREAM_HDR_SIZE+ADDR_HDR_SIZE:])
if err != nil {
return
}
binary.LittleEndian.PutUint32(buffer[0:4], uint32(read+ADDR_HDR_SIZE))
pan_from, ok := from.(pan.UDPAddr)
if !ok {
continue
}
binary.BigEndian.PutUint64(buffer[4:12], (uint64)(pan_from.IA))
if pan_from.IP.Is4() {
buffer[12] = 4
for i, b := range pan_from.IP.As4() {
buffer[16+i] = b
}
} else {
buffer[12] = 16
for i, b := range pan_from.IP.As16() {
buffer[16+i] = b
}
}
binary.LittleEndian.PutUint16(buffer[32:34], pan_from.Port)
message := buffer[:STREAM_HDR_SIZE+ADDR_HDR_SIZE+read]
_, err = ls.unix_conn.Write(message)
if err != nil {
return
}
}
}
func (ls *ListenSSockAdapter) unixToPan() {
var buffer = make([]byte, 4096)
for {
read, err := ls.unix_conn.Read(buffer[:STREAM_HDR_SIZE])
if err != nil || read < STREAM_HDR_SIZE {
return
}
msglen := uint(binary.LittleEndian.Uint32(buffer[0:4]))
if msglen > uint(len(buffer)) {
return
}
read, err = ls.unix_conn.Read(buffer[:msglen])
if err != nil || read < ADDR_HDR_SIZE {
continue
}
var to pan.UDPAddr
to.IA = (pan.IA)(binary.BigEndian.Uint64(buffer[:8]))
addr_len := binary.LittleEndian.Uint32(buffer[8:12])
if addr_len == 4 {
to.IP = netip.AddrFrom4(*(*[4]byte)(buffer[12:16]))
} else if addr_len == 16 {
to.IP = netip.AddrFrom16(*(*[16]byte)(buffer[12:28]))
} else {
continue
}
to.Port = binary.LittleEndian.Uint16(buffer[28:30])
_, err = ls.pan_conn.WriteTo(buffer[ADDR_HDR_SIZE:read], to)
if err != nil {
return
}
}
}
func PanNewConnSSockAdapter(
pan_conn C.PanConn, listen_addr *C.cchar_t,
adapter *C.PanConnSSockAdapter) C.PanError {
ls, err := NewConnSSockAdapter(
cgo.Handle(pan_conn).Value().(pan.Conn),
C.GoString(listen_addr))
if err != nil {
return C.PAN_ERR_FAILED
}
ptr := (*C.PanConnSSockAdapter)(unsafe.Pointer(adapter))
*ptr = C.PanConnSSockAdapter(cgo.NewHandle(ls))
return C.PAN_ERR_OK
}
func PanConnSSockAdapterClose(adapter C.PanConnSSockAdapter) C.PanError {
ls := cgo.Handle(adapter).Value().(*ConnSSockAdapter)
ls.Close()
return C.PAN_ERR_OK
}
type ConnSSockAdapter struct {
pan_conn pan.Conn
unix_listener *net.UnixListener
unix_conn *net.UnixConn
}
func NewConnSSockAdapter(
pan_conn pan.Conn, listen_addr string) (*ConnSSockAdapter, error) {
listen, err := net.ResolveUnixAddr("unix", listen_addr)
if err != nil {
return nil, err
}
os.Remove(listen_addr)
unix_listener, err := net.ListenUnix("unix", listen)
if err != nil {
return nil, err
}
unix_listener.SetUnlinkOnClose(true)
adapter := &ConnSSockAdapter{
pan_conn: pan_conn,
unix_listener: unix_listener,
unix_conn: nil,
}
go adapter.waitForConn()
return adapter, nil
}
func (cs *ConnSSockAdapter) waitForConn() {
conn, err := cs.unix_listener.AcceptUnix()
defer cs.unix_listener.Close()
if err != nil {
return
}
cs.unix_conn = conn
go cs.panToUnix()
go cs.unixToPan()
}
func (cs *ConnSSockAdapter) Close() error {
cs.pan_conn.Close()
cs.unix_conn.Close()
return nil
}
func (cs *ConnSSockAdapter) panToUnix() {
var buffer = make([]byte, 4096)
for {
read, err := cs.pan_conn.Read(buffer[STREAM_HDR_SIZE:])
if err != nil {
return
}
binary.LittleEndian.PutUint32(buffer[0:4], uint32(read))
_, err = cs.unix_conn.Write(buffer[:STREAM_HDR_SIZE+read])
if err != nil {
return
}
}
}
func (cs *ConnSSockAdapter) unixToPan() {
var buffer = make([]byte, 4096)
for {
read, err := cs.unix_conn.Read(buffer[:STREAM_HDR_SIZE])
if err != nil || read < STREAM_HDR_SIZE {
return
}
msglen := uint(binary.LittleEndian.Uint32(buffer[0:4]))
if msglen > uint(len(buffer)) {
return
}
read, err = cs.unix_conn.Read(buffer[:msglen])
if err != nil {
return
}
_, err = cs.pan_conn.Write(buffer[:read])
if err != nil {
return
}
}
}
func main() {
}