package main /* #include #include "error.h" typedef void (*PythonCB)(const char* name, int oldstate, int newstate, void* data); static void call_callback(PythonCB callback, const char *name, int oldstate, int newstate, void* data) { callback(name, oldstate, newstate, data); } */ import "C" import ( "fmt" "unsafe" "github.com/eduvpn/eduvpn-common/client" "github.com/eduvpn/eduvpn-common/types" ) var P_StateCallbacks map[string]C.PythonCB var VPNStates map[string]*client.Client func GetStateData( state *client.Client, stateID client.FSMStateID, data interface{}, ) unsafe.Pointer { switch stateID { case client.STATE_NO_SERVER: return (unsafe.Pointer)(getTransitionDataServers(state, data)) case client.STATE_OAUTH_STARTED: if converted, ok := data.(string); ok { return (unsafe.Pointer)(C.CString(converted)) } case client.STATE_ASK_LOCATION: return (unsafe.Pointer)(getTransitionSecureLocations(data)) case client.STATE_ASK_PROFILE: return (unsafe.Pointer)(getTransitionProfiles(data)) case client.STATE_DISCONNECTED: return (unsafe.Pointer)(getTransitionServer(state, data)) case client.STATE_DISCONNECTING: return (unsafe.Pointer)(getTransitionServer(state, data)) case client.STATE_CONNECTING: return (unsafe.Pointer)(getTransitionServer(state, data)) case client.STATE_CONNECTED: return (unsafe.Pointer)(getTransitionServer(state, data)) default: return nil } return nil } func StateCallback( state *client.Client, name string, old_state client.FSMStateID, new_state client.FSMStateID, data interface{}, ) { P_StateCallback, exists := P_StateCallbacks[name] if !exists || P_StateCallback == nil { return } name_c := C.CString(name) oldState_c := C.int(old_state) newState_c := C.int(new_state) data_c := GetStateData(state, new_state, data) C.call_callback(P_StateCallback, name_c, oldState_c, newState_c, data_c) C.free(unsafe.Pointer(name_c)) // data_c gets freed by the wrapper } func GetVPNState(name string) (*client.Client, error) { state, exists := VPNStates[name] if !exists || state == nil { return nil, fmt.Errorf("State with name %s not found", name) } return state, nil } //export Register func Register( name *C.char, config_directory *C.char, language *C.char, stateCallback C.PythonCB, debug C.int, ) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { state = &client.Client{} } if VPNStates == nil { VPNStates = make(map[string]*client.Client) } if P_StateCallbacks == nil { P_StateCallbacks = make(map[string]C.PythonCB) } VPNStates[nameStr] = state P_StateCallbacks[nameStr] = stateCallback registerErr := state.Register( nameStr, C.GoString(config_directory), C.GoString(language), func(old client.FSMStateID, new client.FSMStateID, data interface{}) { StateCallback(state, nameStr, old, new, data) }, debug != 0, ) if registerErr != nil { delete(VPNStates, nameStr) } return getError(registerErr) } //export Deregister func Deregister(name *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } state.Deregister() return nil } func getError(err error) *C.error { if err == nil { return nil } errorStruct := (*C.error)( C.malloc(C.size_t(unsafe.Sizeof(C.error{}))), ) errorStruct.level = C.errorLevel(types.GetErrorLevel(err)) errorStruct.traceback = C.CString(types.GetErrorTraceback(err)) errorStruct.cause = C.CString(types.GetErrorCause(err).Error()) return errorStruct } //export FreeError func FreeError(err *C.error) { C.free(unsafe.Pointer(err.traceback)) C.free(unsafe.Pointer(err.cause)) C.free(unsafe.Pointer(err)) } //export CancelOAuth func CancelOAuth(name *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } cancelErr := state.CancelOAuth() return getError(cancelErr) } //export RemoveSecureInternet func RemoveSecureInternet(name *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } removeErr := state.RemoveSecureInternet() return getError(removeErr) } //export AddInstituteAccess func AddInstituteAccess(name *C.char, url *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } // FIXME: Return server result _, addErr := state.AddInstituteServer(C.GoString(url)) return getError(addErr) } //export AddSecureInternetHomeServer func AddSecureInternetHomeServer(name *C.char, orgID *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } // FIXME: Return server result _, addErr := state.AddSecureInternetHomeServer(C.GoString(orgID)) return getError(addErr) } //export AddCustomServer func AddCustomServer(name *C.char, url *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } // FIXME: Return server result _, addErr := state.AddCustomServer(C.GoString(url)) return getError(addErr) } //export RemoveInstituteAccess func RemoveInstituteAccess(name *C.char, url *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } removeErr := state.RemoveInstituteAccess(C.GoString(url)) return getError(removeErr) } //export RemoveCustomServer func RemoveCustomServer(name *C.char, url *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } removeErr := state.RemoveCustomServer(C.GoString(url)) return getError(removeErr) } //export GetConfigSecureInternet func GetConfigSecureInternet(name *C.char, orgID *C.char, preferTCP C.int) (*C.char, *C.char, *C.error) { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return nil, nil, getError(stateErr) } preferTCPBool := preferTCP == 1 config, configType, configErr := state.GetConfigSecureInternet(C.GoString(orgID), preferTCPBool) return C.CString(config), C.CString(configType), getError(configErr) } //export GetConfigInstituteAccess func GetConfigInstituteAccess(name *C.char, url *C.char, preferTCP C.int) (*C.char, *C.char, *C.error) { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return nil, nil, getError(stateErr) } preferTCPBool := preferTCP == 1 config, configType, configErr := state.GetConfigInstituteAccess(C.GoString(url), preferTCPBool) return C.CString(config), C.CString(configType), getError(configErr) } //export GetConfigCustomServer func GetConfigCustomServer(name *C.char, url *C.char, preferTCP C.int) (*C.char, *C.char, *C.error) { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return nil, nil, getError(stateErr) } preferTCPBool := preferTCP == 1 config, configType, configErr := state.GetConfigCustomServer(C.GoString(url), preferTCPBool) return C.CString(config), C.CString(configType), getError(configErr) } //export SetProfileID func SetProfileID(name *C.char, data *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } profileErr := state.SetProfileID(C.GoString(data)) return getError(profileErr) } //export ChangeSecureLocation func ChangeSecureLocation(name *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } locationErr := state.ChangeSecureLocation() return getError(locationErr) } //export SetSecureLocation func SetSecureLocation(name *C.char, data *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } locationErr := state.SetSecureLocation(C.GoString(data)) return getError(locationErr) } //export GoBack func GoBack(name *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } goBackErr := state.GoBack() return getError(goBackErr) } //export SetSearchServer func SetSearchServer(name *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } setSearchErr := state.SetSearchServer() return getError(setSearchErr) } //export SetDisconnected func SetDisconnected(name *C.char, cleanup C.int) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } setDisconnectedErr := state.SetDisconnected(int(cleanup) == 1) return getError(setDisconnectedErr) } //export SetDisconnecting func SetDisconnecting(name *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } setDisconnectingErr := state.SetDisconnecting() return getError(setDisconnectingErr) } //export SetConnecting func SetConnecting(name *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } setConnectingErr := state.SetConnecting() return getError(setConnectingErr) } //export SetConnected func SetConnected(name *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } setConnectedErr := state.SetConnected() return getError(setConnectedErr) } //export RenewSession func RenewSession(name *C.char) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } renewSessionErr := state.RenewSession() return getError(renewSessionErr) } //export ShouldRenewButton func ShouldRenewButton(name *C.char) C.int { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return C.int(0) } shouldRenewBool := state.ShouldRenewButton() if shouldRenewBool { return C.int(1) } return C.int(0) } //export InFSMState func InFSMState(name *C.char, checkState C.int) C.int { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return C.int(0) } inStateBool := state.InFSMState(client.FSMStateID(checkState)) if inStateBool { return C.int(1) } return C.int(0) } //export SetSupportWireguard func SetSupportWireguard(name *C.char, support C.int) *C.error { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { return getError(stateErr) } state.SupportsWireguard = support == 1 return nil } //export FreeString func FreeString(addr *C.char) { C.free(unsafe.Pointer(addr)) } // Not used in library, but needed to compile. func main() { panic("compile with -buildmode=c-shared") }