summaryrefslogtreecommitdiff
path: root/exports
diff options
context:
space:
mode:
authorjwijenbergh <jeroenwijenbergh@protonmail.com>2022-09-14 13:56:49 +0200
committerjwijenbergh <jeroenwijenbergh@protonmail.com>2022-09-14 13:56:49 +0200
commitda83f54606c9c1d2786d87074ee17ed972d2e1b2 (patch)
tree0be57934f9f467c87576abb0b457fb54b2d25d52 /exports
parentfd34e72da8c604517050ada7e883ba982829d985 (diff)
Refactor: Return without json
Diffstat (limited to 'exports')
-rw-r--r--exports/Makefile12
-rw-r--r--exports/c/common.c6
-rw-r--r--exports/c/common.h3
-rw-r--r--exports/c/disco.h15
-rw-r--r--exports/c/servers.h43
-rw-r--r--exports/common.mk2
-rw-r--r--exports/disco.go97
-rw-r--r--exports/exports.go66
-rw-r--r--exports/servers.go273
9 files changed, 482 insertions, 35 deletions
diff --git a/exports/Makefile b/exports/Makefile
index b833228..46d17a9 100644
--- a/exports/Makefile
+++ b/exports/Makefile
@@ -2,6 +2,8 @@
include common.mk
+CLIBPATH=./c
+
ifeq ($(LIB_SUFFIX),.so)
# Add SONAME as cgo does not currently do this. Mostly for Android, see https://stackoverflow.com/a/48291044
export override CGO_LDFLAGS += -Wl,-soname,$(LIB_FILE)
@@ -13,12 +15,18 @@ ifdef COPY_LIB_TO
install $< -Dt $(COPY_LIB_TO)
endif
+${CLIBPATH}/libcommon$(LIB_SUFFIX): ${CLIBPATH}/common.c
+ $(CC) -c -Wall -Werror -fpic -o ${CLIBPATH}/common.o ${CLIBPATH}/common.c
+ $(CC) -shared -o $@ ${CLIBPATH}/common.o
+
# Build shared library and remove lib prefix (if any) from header name
# GOOS and GOARCH envvars are set by common.mk
# This extra target prevents unnecessary rebuild
-lib/$(GOOS)/$(GOARCH)/$(LIB_FILE): exports.go ..
- CGO_ENABLED=1 go build -o $@ -buildmode=c-shared $<
+lib/$(GOOS)/$(GOARCH)/$(LIB_FILE): ${CLIBPATH}/libcommon$(LIB_SUFFIX) exports.go servers.go ..
+ CGO_ENABLED=1 go build -o $@ -buildmode=c-shared .
mv lib/$(GOOS)/$(GOARCH)/$(LIB_PREFIX)$(LIB_NAME).h lib/$(GOOS)/$(GOARCH)/$(LIB_NAME).h || true # Normalize header name
clean:
rm -rf ../exports/lib/*
+ rm -rf ${CLIBPATH}/common.o
+ rm -rf ${CLIBPATH}/libcommon.so
diff --git a/exports/c/common.c b/exports/c/common.c
new file mode 100644
index 0000000..425a459
--- /dev/null
+++ b/exports/c/common.c
@@ -0,0 +1,6 @@
+#include "common.h"
+
+void call_callback(PythonCB callback, const char *name, int oldstate, int newstate, void* data)
+{
+ callback(name, oldstate, newstate, data);
+}
diff --git a/exports/c/common.h b/exports/c/common.h
new file mode 100644
index 0000000..068ad4c
--- /dev/null
+++ b/exports/c/common.h
@@ -0,0 +1,3 @@
+typedef void (*PythonCB)(const char* name, int oldstate, int newstate, void* data);
+
+void call_callback(PythonCB callback, const char *name, int oldstate, int newstate, void* data);
diff --git a/exports/c/disco.h b/exports/c/disco.h
new file mode 100644
index 0000000..41d59fa
--- /dev/null
+++ b/exports/c/disco.h
@@ -0,0 +1,15 @@
+// for size_t
+#include <stddef.h>
+
+typedef struct discoveryOrganization {
+ const char* display_name;
+ const char* org_id;
+ const char* secure_internet_home;
+ const char* keyword_list;
+} discoveryOrganization;
+
+typedef struct discoveryOrganizations {
+ unsigned long long int version;
+ discoveryOrganization** organizations;
+ size_t total_organizations;
+} discoveryOrganizations;
diff --git a/exports/c/servers.h b/exports/c/servers.h
new file mode 100644
index 0000000..39e52a2
--- /dev/null
+++ b/exports/c/servers.h
@@ -0,0 +1,43 @@
+// for size_t
+#include <stddef.h>
+
+// The struct for a single server profile
+typedef struct serverProfile {
+ const char* id;
+ const char* display_name;
+ //const char* proto_list;
+ int default_gateway;
+} serverProfile;
+
+// The struct for all server profiles
+typedef struct serverProfiles {
+ int current;
+ serverProfile** profiles;
+ size_t total_profiles;
+} serverProfiles;
+
+// The struct for server locations
+typedef struct serverLocations {
+ const char** locations;
+ size_t total_locations;
+} serverLocations;
+
+// The struct for a single server
+typedef struct server {
+ const char* identifier;
+ const char* display_name;
+ const char* country_code;
+ const char** support_contact;
+ size_t total_support_contact;
+ serverProfiles* profiles;
+ unsigned long long int expire_time;
+} server;
+
+// The struct for all servers
+typedef struct servers {
+ server** custom_servers;
+ size_t total_custom;
+ server** institute_servers;
+ size_t total_institute;
+ server* secure_internet_server;
+} servers;
diff --git a/exports/common.mk b/exports/common.mk
index c1e2a7e..211d460 100644
--- a/exports/common.mk
+++ b/exports/common.mk
@@ -7,6 +7,8 @@ ifndef GOARCH
export GOARCH := $(shell go env GOHOSTARCH)
endif
+CC = gcc
+
ifeq (windows,$(GOOS))
LIB_PREFIX ?=
LIB_SUFFIX ?= .dll
diff --git a/exports/disco.go b/exports/disco.go
new file mode 100644
index 0000000..9ee2af9
--- /dev/null
+++ b/exports/disco.go
@@ -0,0 +1,97 @@
+package main
+
+/*
+// for free
+#include <stdlib.h>
+#include "c/disco.h"
+*/
+import "C"
+
+import (
+ "unsafe"
+
+ "github.com/jwijenbergh/eduvpn-common"
+ "github.com/jwijenbergh/eduvpn-common/internal/types"
+)
+
+func getCPtrDiscoOrganization(
+ state *eduvpn.VPNState,
+ organization *types.DiscoveryOrganization,
+) *C.discoveryOrganization {
+ returnedStruct := (*C.discoveryOrganization)(
+ C.malloc(C.size_t(unsafe.Sizeof(C.discoveryOrganization{}))),
+ )
+ returnedStruct.display_name = C.CString(state.GetTranslated(organization.DisplayName))
+ returnedStruct.org_id = C.CString(organization.OrgId)
+ returnedStruct.secure_internet_home = C.CString(organization.SecureInternetHome)
+ returnedStruct.keyword_list = C.CString(state.GetTranslated(organization.KeywordList))
+ return returnedStruct
+}
+
+func getCPtrDiscoOrganizations(
+ state *eduvpn.VPNState,
+ organizations *types.DiscoveryOrganizations,
+) (C.size_t, **C.discoveryOrganization) {
+ totalOrganizations := C.size_t(len(organizations.List))
+ var organizationsPtr **C.discoveryOrganization
+ if totalOrganizations > 0 {
+ organizationsPtr = (**C.discoveryOrganization)(
+ C.malloc(totalOrganizations * C.size_t(unsafe.Sizeof(uintptr(0)))),
+ )
+ cOrganizations := (*[1<<30 - 1]*C.discoveryOrganization)(unsafe.Pointer(organizationsPtr))[:totalOrganizations:totalOrganizations]
+ index := 0
+ for _, organization := range organizations.List {
+ cOrganization := getCPtrDiscoOrganization(state, &organization)
+ cOrganizations[index] = cOrganization
+ index += 1
+ }
+ }
+ return totalOrganizations, organizationsPtr
+}
+
+func freeDiscoOrganization(cOrganization *C.discoveryOrganization) {
+ C.free(unsafe.Pointer(cOrganization.display_name))
+ C.free(unsafe.Pointer(cOrganization.org_id))
+ C.free(unsafe.Pointer(cOrganization.secure_internet_home))
+ C.free(unsafe.Pointer(cOrganization.keyword_list))
+ C.free(unsafe.Pointer(cOrganization))
+}
+
+//export FreeDiscoOrganizations
+func FreeDiscoOrganizations(cOrganizations *C.discoveryOrganizations) {
+ if cOrganizations.total_organizations > 0 {
+ organizations := (*[1<<30 - 1]*C.discoveryOrganization)(unsafe.Pointer(cOrganizations.organizations))[:cOrganizations.total_organizations:cOrganizations.total_organizations]
+ for i := C.size_t(0); i < cOrganizations.total_organizations; i++ {
+ freeDiscoOrganization(organizations[i])
+ }
+ C.free(unsafe.Pointer(cOrganizations.organizations))
+ }
+ C.free(unsafe.Pointer(cOrganizations))
+}
+
+//export GetDiscoOrganizations
+func GetDiscoOrganizations(name *C.char) *C.discoveryOrganizations {
+ nameStr := C.GoString(name)
+ state, stateErr := GetVPNState(nameStr)
+ // TODO
+ if stateErr != nil {
+ panic(stateErr)
+ }
+ organizations, organizationsErr := state.GetDiscoOrganizations()
+ // TODO
+ if organizationsErr != nil {
+ panic(organizationsErr)
+ }
+
+ returnedStruct := (*C.discoveryOrganizations)(
+ C.malloc(C.size_t(unsafe.Sizeof(C.discoveryOrganizations{}))),
+ )
+
+ returnedStruct.version = C.ulonglong(organizations.Version)
+ returnedStruct.total_organizations, returnedStruct.organizations = getCPtrDiscoOrganizations(
+ state,
+ organizations,
+ )
+
+ return returnedStruct
+}
diff --git a/exports/exports.go b/exports/exports.go
index b4eb909..797a192 100644
--- a/exports/exports.go
+++ b/exports/exports.go
@@ -1,15 +1,13 @@
package main
/*
-#include <stdlib.h>
-
-typedef void (*PythonCB)(const char* name, int oldstate, int newstate, const char* data);
+#cgo CFLAGS: -I${SRCDIR}/c
+#cgo LDFLAGS: -Wl,-rpath,${SRCDIR}/c
+#cgo LDFLAGS: -L${SRCDIR}/c
+#cgo LDFLAGS: -lcommon
-__attribute__((weak))
-void call_callback(PythonCB callback, const char *name, int oldstate, int newstate, const char* data)
-{
- callback(name, oldstate, newstate, data);
-}
+#include <stdlib.h>
+#include "c/common.h"
*/
import "C"
@@ -26,7 +24,28 @@ var P_StateCallbacks map[string]C.PythonCB
var VPNStates map[string]*eduvpn.VPNState
+func GetStateData(
+ state *eduvpn.VPNState,
+ stateID eduvpn.FSMStateID,
+ data interface{},
+) unsafe.Pointer {
+ switch stateID {
+ case eduvpn.STATE_NO_SERVER:
+ return (unsafe.Pointer)(getTransitionDataServers(state, data))
+ case eduvpn.STATE_OAUTH_STARTED:
+ if converted, ok := data.(string); ok {
+ return (unsafe.Pointer)(C.CString(converted))
+ }
+ case eduvpn.STATE_ASK_LOCATION:
+ return (unsafe.Pointer)(getTransitionSecureLocations(data))
+ default:
+ return nil
+ }
+ return nil
+}
+
func StateCallback(
+ state *eduvpn.VPNState,
name string,
old_state eduvpn.FSMStateID,
new_state eduvpn.FSMStateID,
@@ -39,18 +58,10 @@ func StateCallback(
name_c := C.CString(name)
oldState_c := C.int(old_state)
newState_c := C.int(new_state)
- data_json, jsonErr := json.Marshal(data)
- var dataJsonString string
- if jsonErr != nil {
- // TODO: How to handle error further? Log?
- dataJsonString = "{}"
- } else {
- dataJsonString = string(data_json)
- }
- data_c := C.CString(dataJsonString)
+ 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))
- C.free(unsafe.Pointer(data_c))
+ // data_c gets freed by the wrapper
}
func GetVPNState(name string) (*eduvpn.VPNState, error) {
@@ -87,7 +98,7 @@ func Register(
nameStr,
C.GoString(config_directory),
func(old eduvpn.FSMStateID, new eduvpn.FSMStateID, data interface{}) {
- StateCallback(nameStr, old, new, data)
+ StateCallback(state, nameStr, old, new, data)
},
debug != 0,
)
@@ -150,7 +161,7 @@ func getConfigJSON(config string, configType string) *C.char {
}
//export RemoveSecureInternet
-func RemoveSecureInternet(name *C.char) (*C.char) {
+func RemoveSecureInternet(name *C.char) *C.char {
nameStr := C.GoString(name)
state, stateErr := GetVPNState(nameStr)
if stateErr != nil {
@@ -161,7 +172,7 @@ func RemoveSecureInternet(name *C.char) (*C.char) {
}
//export RemoveInstituteAccess
-func RemoveInstituteAccess(name *C.char, url *C.char) (*C.char) {
+func RemoveInstituteAccess(name *C.char, url *C.char) *C.char {
nameStr := C.GoString(name)
state, stateErr := GetVPNState(nameStr)
if stateErr != nil {
@@ -172,7 +183,7 @@ func RemoveInstituteAccess(name *C.char, url *C.char) (*C.char) {
}
//export RemoveCustomServer
-func RemoveCustomServer(name *C.char, url *C.char) (*C.char) {
+func RemoveCustomServer(name *C.char, url *C.char) *C.char {
nameStr := C.GoString(name)
state, stateErr := GetVPNState(nameStr)
if stateErr != nil {
@@ -218,17 +229,6 @@ func GetConfigCustomServer(name *C.char, url *C.char, forceTCP C.int) (*C.char,
return getConfigJSON(config, configType), C.CString(ErrorToString(configErr))
}
-//export GetDiscoOrganizations
-func GetDiscoOrganizations(name *C.char) (*C.char, *C.char) {
- nameStr := C.GoString(name)
- state, stateErr := GetVPNState(nameStr)
- if stateErr != nil {
- return nil, C.CString(ErrorToString(stateErr))
- }
- organizations, organizationsErr := state.GetDiscoOrganizations()
- return C.CString(organizations), C.CString(ErrorToString(organizationsErr))
-}
-
//export GetDiscoServers
func GetDiscoServers(name *C.char) (*C.char, *C.char) {
nameStr := C.GoString(name)
diff --git a/exports/servers.go b/exports/servers.go
new file mode 100644
index 0000000..f92c08e
--- /dev/null
+++ b/exports/servers.go
@@ -0,0 +1,273 @@
+package main
+
+/*
+// for free
+#include <stdlib.h>
+#include "c/servers.h"
+*/
+import "C"
+
+import (
+ "unsafe"
+
+ "github.com/jwijenbergh/eduvpn-common"
+ "github.com/jwijenbergh/eduvpn-common/internal/server"
+)
+
+// Get the pointer to the C struct for the profile
+// We allocate the struct, the profile ID and the display name
+func getCPtrProfile(profile *server.ServerProfile) *C.serverProfile {
+ // Allocate the struct using malloc and the size of the struct
+ cProfile := (*C.serverProfile)(C.malloc(C.size_t(unsafe.Sizeof(C.serverProfile{}))))
+ cProfile.id = C.CString(profile.ID)
+ cProfile.display_name = C.CString(profile.DisplayName)
+ if profile.DefaultGateway {
+ cProfile.default_gateway = C.int(1)
+ } else {
+ cProfile.default_gateway = C.int(0)
+ }
+
+ return cProfile
+}
+
+// Get the pointer to the C struct for the profiles
+// We allocate the struct and the struct inside it for the profiles
+func getCPtrProfiles(serverProfiles *server.ServerProfileInfo) *C.serverProfiles {
+ goProfiles := serverProfiles.Info.ProfileList
+ // Allocate the profles struct using malloc and the size of a pointer
+ cProfiles := (*C.serverProfiles)(C.malloc(C.size_t(uintptr(0))))
+ totalProfiles := C.size_t(len(goProfiles))
+ // Defaults if we have no profiles
+ cProfiles.current = C.int(0)
+ cProfiles.profiles = nil
+ cProfiles.total_profiles = totalProfiles
+ // If we have profiles (which we should), we allocate the struct with malloc and the size of a pointer
+ // We then fill the struct by converting it to a go slice and get a C pointer for each profile
+ if totalProfiles > 0 {
+ profilesPtr := C.malloc(totalProfiles * C.size_t(unsafe.Sizeof(uintptr(0))))
+ profiles := (*[1<<30 - 1]*C.serverProfile)(unsafe.Pointer(profilesPtr))[:totalProfiles:totalProfiles]
+ index := 0
+ for _, profile := range goProfiles {
+ profiles[index] = getCPtrProfile(&profile)
+ index += 1
+ }
+ // TODO: DO CURRENT PROFILE
+ cProfiles.profiles = (**C.serverProfile)(profilesPtr)
+ }
+ return cProfiles
+}
+
+// Free the profiles by looping through them if there are any
+// Also free the pointer itself
+func freeCProfiles(profiles *C.serverProfiles) {
+ // We should only free the profiles if we have them (which we should)
+ if profiles.total_profiles > 0 {
+ // Convert it to a go slice
+ profilesSlice := (*[1<<30 - 1]*C.serverProfile)(unsafe.Pointer(profiles.profiles))[:profiles.total_profiles:profiles.total_profiles]
+ // Loop through the pointers and free th allocated strings and the struct itself
+ for i := C.size_t(0); i < profiles.total_profiles; i++ {
+ C.free(unsafe.Pointer(profilesSlice[i].id))
+ C.free(unsafe.Pointer(profilesSlice[i].display_name))
+ C.free(unsafe.Pointer(profilesSlice[i]))
+ }
+ // Free the inner profiles struct
+ C.free(unsafe.Pointer(profiles.profiles))
+ }
+ // Free the profiles struct itself
+ C.free(unsafe.Pointer(profiles))
+}
+
+// Get a list of strings with a size as a c structure
+// Returns the size in size_t and the list of strings as a double pointer char
+func getCPtrListStrings(allStrings []string) (C.size_t, **C.char) {
+ // Get the total strings in size_t
+ totalStrings := C.size_t(len(allStrings))
+
+ // If we have strings
+ // Allocate memory for the strings array
+ if totalStrings > 0 {
+ stringsPtr := C.malloc(totalStrings * C.size_t(unsafe.Sizeof(uintptr(0))))
+ // Go slice conversion
+ cStrings := (*[1<<30 - 1]*C.char)(unsafe.Pointer(stringsPtr))[:totalStrings:totalStrings]
+
+ // Loop through and allocate the string for each contact
+ for index, string := range allStrings {
+ cStrings[index] = C.CString(string)
+ }
+ return totalStrings, (**C.char)(stringsPtr)
+ }
+
+ // No strings then the length is zero and the char array is nil
+ return C.size_t(0), nil
+}
+
+// Function for freeing an array/list of strings
+// It takes the strings as a pointer to a string and the total strings in size_t
+func freeCListStrings(allStrings **C.char, totalStrings C.size_t) {
+ // If we have strings we should free them
+ // By converting to a Go slice, and freeing them ony by one
+ // At last free the pointer itself
+ if totalStrings > 0 {
+ stringsSlice := (*[1<<30 - 1]*C.char)(unsafe.Pointer(allStrings))[:totalStrings:totalStrings]
+ for i := C.size_t(0); i < totalStrings; i++ {
+ C.free(unsafe.Pointer(stringsSlice[i]))
+ }
+ C.free(unsafe.Pointer(allStrings))
+ }
+}
+
+// Function for getting the server,
+// It gets the main state as a pointer as we need to convert some string maps to localized strings
+// It gets the base information for a server as well
+func getServer(state *eduvpn.VPNState, base *eduvpn.VPNServerBase) *C.server {
+ // Allocation using malloc and the size of the struct
+ server := (*C.server)(C.malloc(C.size_t(unsafe.Sizeof(C.server{}))))
+ // String allocation and translate the display name
+ server.identifier = C.CString(base.URL)
+ server.display_name = C.CString(state.GetTranslated(base.DisplayName))
+ // Call the helper to get the list of support contacts
+ server.total_support_contact, server.support_contact = getCPtrListStrings(
+ base.SupportContact,
+ )
+ server.profiles = getCPtrProfiles(&base.Profiles)
+ // No endtime is given if we get servers when it has been partially initialised
+ if base.EndTime.IsZero() {
+ server.expire_time = C.ulonglong(0)
+ }
+ // The expire time should be stored as an unsigned long long in unix itme
+ server.expire_time = C.ulonglong(base.EndTime.Unix())
+ return server
+}
+
+// Function for freeing a single server
+// Gets the pointer to C struct
+func freeServer(info *C.server) {
+ // Free strings
+ C.free(unsafe.Pointer(info.identifier))
+ C.free(unsafe.Pointer(info.display_name))
+
+ // Free arrays
+ freeCListStrings(info.support_contact, info.total_support_contact)
+ freeCProfiles(info.profiles)
+
+ // Free the struct itself
+ C.free(unsafe.Pointer(info))
+}
+
+// Get the C ptr to the servers, returns the length in size_t and the double pointer to the struct
+func getCPtrServers(
+ state *eduvpn.VPNState,
+ serverMap map[string]*server.InstituteAccessServer,
+) (C.size_t, **C.server) {
+ totalServers := C.size_t(len(serverMap))
+ // If we have servers, which is not always the case
+ if totalServers > 0 {
+ serversPtr := (**C.server)(C.malloc(totalServers * C.size_t(unsafe.Sizeof(uintptr(0)))))
+ servers := (*[1<<30 - 1]*C.server)(unsafe.Pointer(serversPtr))[:totalServers:totalServers]
+ index := 0
+ for _, server := range serverMap {
+ cServer := getServer(state, &server.Base)
+ servers[index] = cServer
+ index += 1
+ }
+ }
+ return C.size_t(0), nil
+}
+
+//export FreeServers
+// This function takes the servers as a C struct pointer as input
+// It frees all allocated memory for the server
+func FreeServers(cServers *C.servers) {
+ // Free the custom servers if there are any
+ if cServers.total_custom > 0 {
+ customServers := (*[1<<30 - 1]*C.server)(unsafe.Pointer(cServers.custom_servers))[:cServers.total_custom:cServers.total_custom]
+ for i := C.size_t(0); i < cServers.total_custom; i++ {
+ freeServer(customServers[i])
+ }
+ C.free(unsafe.Pointer(cServers.custom_servers))
+ }
+ // Free the institute access servers if there are any
+ if cServers.total_institute > 0 {
+ instituteServers := (*[1<<30 - 1]*C.server)(unsafe.Pointer(cServers.institute_servers))[:cServers.total_institute:cServers.total_institute]
+
+ for i := C.size_t(0); i < cServers.total_institute; i++ {
+ freeServer(instituteServers[i])
+ }
+ C.free(unsafe.Pointer(cServers.institute_servers))
+ }
+ // Free the secure internet server if there is one
+ if cServers.secure_internet_server != nil {
+ C.free(unsafe.Pointer(cServers.secure_internet_server.country_code))
+ freeServer(cServers.secure_internet_server)
+ }
+ // Free the structure itself
+ C.free(unsafe.Pointer(cServers))
+}
+
+// Return the servers as a C struct pointer
+// It takes the state as a pointer as we need to translate some strings
+// It also takes the servers as a pointer that belongs to the main state or gathered from the callback
+func getSavedServersWithOptions(state *eduvpn.VPNState, servers *server.Servers) *C.servers {
+ // Allocate the struct that we will return
+ // With the size of the c struct
+ returnedStruct := (*C.servers)(C.malloc(C.size_t(unsafe.Sizeof(C.servers{}))))
+
+ // Get the different categories of servers
+ totalCustom, customPtr := getCPtrServers(state, servers.CustomServers.Map)
+ totalInstitute, institutePtr := getCPtrServers(state, servers.InstituteServers.Map)
+ var secureServerPtr *C.server = nil
+ secureInternetBase, secureInternetBaseErr := servers.SecureInternetHomeServer.GetBase()
+ if secureInternetBaseErr == nil && secureInternetBase != nil {
+ // FIXME: log error?
+ secureServerPtr = getServer(state, secureInternetBase)
+ // Give a new identifier
+ C.free(unsafe.Pointer(secureServerPtr.identifier))
+ secureServerPtr.identifier = C.CString(servers.SecureInternetHomeServer.HomeOrganizationID)
+ secureServerPtr.country_code = C.CString(servers.SecureInternetHomeServer.CurrentLocation)
+ }
+
+ // Fill the struct and return
+ returnedStruct.custom_servers = customPtr
+ returnedStruct.total_custom = totalCustom
+ returnedStruct.institute_servers = institutePtr
+ returnedStruct.total_institute = totalInstitute
+ returnedStruct.secure_internet_server = secureServerPtr
+ return returnedStruct
+}
+
+//export GetSavedServers
+// This function takes the name as input which is the name of the client
+// It gets the state by name and then returns the saved servers as a c struct belonging to it
+func GetSavedServers(name *C.char) *C.servers {
+ nameStr := C.GoString(name)
+ state, stateErr := GetVPNState(nameStr)
+ if stateErr != nil {
+ // TODO: Remove this panic
+ panic(stateErr)
+ }
+ return getSavedServersWithOptions(state, &state.Servers)
+}
+
+// This function takes the state as input which is the main state
+// It also takes the data as an interface and if it has the servers type gets the data as a c struct otherwise nil
+func getTransitionDataServers(state *eduvpn.VPNState, data interface{}) *C.servers {
+ if converted, ok := data.(server.Servers); ok {
+ return getSavedServersWithOptions(state, &converted)
+ }
+ return nil
+}
+
+//export FreeSecureLocations
+func FreeSecureLocations(locations *C.serverLocations) {
+ freeCListStrings(locations.locations, locations.total_locations);
+ C.free(unsafe.Pointer(locations))
+}
+
+func getTransitionSecureLocations(data interface{}) (*C.serverLocations) {
+ if locations, ok := data.([]string); ok {
+ returnedStruct := (*C.serverLocations)(C.malloc(C.size_t(unsafe.Sizeof(C.servers{}))))
+ returnedStruct.total_locations, returnedStruct.locations = getCPtrListStrings(locations)
+ return returnedStruct
+ }
+ return nil
+}