package main //#include "bridge.h" import "C" import ( "context" "io" "sync" "unsafe" "golang.org/x/sync/semaphore" "cfa/native/app" "cfa/native/tun" ) var rTunLock sync.Mutex var rTun *remoteTun type remoteTun struct { closer io.Closer callback unsafe.Pointer closed bool limit *semaphore.Weighted } func (t *remoteTun) markSocket(fd int) { _ = t.limit.Acquire(context.Background(), 1) defer t.limit.Release(1) if t.closed { return } C.mark_socket(t.callback, C.int(fd)) } func (t *remoteTun) querySocketUid(protocol int, source, target string) int { _ = t.limit.Acquire(context.Background(), 1) defer t.limit.Release(1) if t.closed { return -1 } return int(C.query_socket_uid(t.callback, C.int(protocol), C.CString(source), C.CString(target))) } func (t *remoteTun) close() { _ = t.limit.Acquire(context.TODO(), 4) defer t.limit.Release(4) t.closed = true if t.closer != nil { _ = t.closer.Close() } app.ApplyTunContext(nil, nil) C.release_object(t.callback) } //export startTun func startTun(fd C.int, gateway, portal, dns C.c_string, callback unsafe.Pointer) C.int { rTunLock.Lock() defer rTunLock.Unlock() if rTun != nil { rTun.close() rTun = nil } f := int(fd) g := C.GoString(gateway) p := C.GoString(portal) d := C.GoString(dns) remote := &remoteTun{callback: callback, closed: false, limit: semaphore.NewWeighted(4)} app.ApplyTunContext(remote.markSocket, remote.querySocketUid) closer, err := tun.Start(f, g, p, d) if err != nil { remote.close() return 1 } remote.closer = closer rTun = remote return 0 } //export stopTun func stopTun() { rTunLock.Lock() defer rTunLock.Unlock() if rTun != nil { rTun.close() rTun = nil } }