Parcourir la source

Update C measurement lib and add example

mirokuratczyk il y a 7 ans
Parent
commit
7f591512c3

+ 1 - 0
.gitignore

@@ -16,6 +16,7 @@ AndroidLibrary/psi.aar
 *.o
 *.a
 *.so
+*.dylib
 
 # Folders
 _obj

+ 0 - 5
Bindings/CXX/.gitignore

@@ -1,5 +0,0 @@
-psi.a
-main
-psiphon.boltdb
-server_list_compressed
-psiphon-config.json

+ 0 - 8
Bindings/CXX/Makefile

@@ -1,8 +0,0 @@
-shared:
-	go build -buildmode=c-shared -o psi.dylib main.go
-.PHONY: shared
-
-static:
-	go build -buildmode=c-archive -o psi.a main.go
-
-.PHONY: static

+ 8 - 0
MeasurementClient/Makefile

@@ -0,0 +1,8 @@
+shared:
+	go build -buildmode=c-shared -o PsiphonTunnel.dylib PsiphonTunnel.go
+.PHONY: shared
+
+static:
+	go build -buildmode=c-archive -o PsiphonTunnel.a PsiphonTunnel.go
+
+.PHONY: static

+ 53 - 46
Bindings/CXX/main.go → MeasurementClient/PsiphonTunnel.go

@@ -1,15 +1,11 @@
 package main
 
-
 import "C"
 
 import (
 	"context"
 	"encoding/json"
-	"flag"
 	"fmt"
-	"io/ioutil"
-	"os"
 	"time"
 
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/MobileLibrary/psi"
@@ -22,21 +18,32 @@ type NoticeEvent struct {
 
 type PsiphonProvider struct {
 	connected chan bool
+	err       chan error
+	stopped   chan bool
+	networkID string
 }
 
 func (pp PsiphonProvider) Notice(noticeJSON string) {
 	var event NoticeEvent
+
 	err := json.Unmarshal([]byte(noticeJSON), &event)
 	if err != nil {
-		fmt.Printf("Failed to unmarshal: %v", err)
+		select {
+		case pp.err <- err:
+		default:
+		}
+		return
 	}
+
 	if event.NoticeType == "Tunnels" {
 		count := event.Data["count"].(float64)
 		if count > 0 {
-			pp.connected <- true
+			select {
+			case pp.connected <- true:
+			default:
+			}
 		}
 	}
-	fmt.Printf("notice: %s\n", noticeJSON)
 }
 
 func (pp PsiphonProvider) HasNetworkConnectivity() int {
@@ -60,83 +67,83 @@ func (pp PsiphonProvider) GetSecondaryDnsServer() string {
 }
 
 func (pp PsiphonProvider) GetNetworkID() string {
-	return ""
+	return pp.networkID
 }
 
-const runtimeTimeout = 90 * time.Second
-
 var provider PsiphonProvider
 
 type StartResult struct {
 	BootstrapTime float64 `json:"bootstrap_time"`
-	ErrorString   string  `json:"error"`
+	ErrorString   string  `json:"error,omitempty"`
 }
 
 //export Start
 func Start(configJSON,
-	embeddedServerEntryList string) *C.char {
-
-	provider.connected = make(chan bool)
+	embeddedServerEntryList, networkID string, timeout int64) *C.char {
 
 	var result StartResult
 
+	provider.connected = make(chan bool)
+	provider.stopped = make(chan bool)
+	provider.err = make(chan error)
+
+	runtimeTimeout := time.Duration(timeout) * time.Second
 	startTime := time.Now().UTC()
+
 	connectedCtx, cancel := context.WithTimeout(context.Background(), runtimeTimeout)
 	defer cancel()
 
-	fmt.Printf("Passing: %s\n", configJSON)
-
 	err := psi.Start(configJSON, embeddedServerEntryList, "", provider, false, false)
 	if err != nil {
-		fmt.Println(err)
+		return errorJsonForC(err)
 	}
 
 	select {
 	case <-connectedCtx.Done():
+		result.BootstrapTime = bootstrapTime(startTime)
 		err = connectedCtx.Err()
 		if err != nil {
 			result.ErrorString = err.Error()
-			Stop()
 		}
-		delta := time.Now().UTC().Sub(startTime)
-		result.BootstrapTime = delta.Seconds()
 	case <-provider.connected:
-		delta := time.Now().UTC().Sub(startTime)
-		result.BootstrapTime = delta.Seconds()
+		result.BootstrapTime = bootstrapTime(startTime)
+		cancel()
+	case <-provider.stopped:
+		result.BootstrapTime = bootstrapTime(startTime)
+		result.ErrorString = "stop signalled before client connected"
+		cancel()
+	case err := <-provider.err:
+		result.BootstrapTime = bootstrapTime(startTime)
+		result.ErrorString = err.Error()
 		cancel()
 	}
 
-	b, err := json.Marshal(result)
+	resultJSON, err := json.Marshal(result)
 	if err != nil {
-		fmt.Printf("Error in marshal: %s", err.Error())
-		return C.CString("error")
+		return errorJsonForC(err)
 	}
-	retStr := string(b)
-	fmt.Printf("retStr: %s\n", retStr)
-	return C.CString(retStr)
-}
 
-//export Stop
-func Stop() bool {
-	psi.Stop()
-	return true
+	return C.CString(string(resultJSON))
 }
 
-func main() {
-	var configFilename string
-	flag.StringVar(&configFilename, "config", "", "configuration input file")
-	flag.Parse()
+func bootstrapTime(startTime time.Time) float64 {
+	delta := time.Now().UTC().Sub(startTime)
+	return delta.Seconds()
+}
 
-	if configFilename == "" {
-		fmt.Println("A config file is required")
-		os.Exit(1)
-	}
+func errorJsonForC(err error) *C.char {
+	return C.CString(fmt.Sprintf("{\"error\": \"%s\"}", err.Error()))
+}
 
-	configFileContents, err := ioutil.ReadFile(configFilename)
-	if err != nil {
-		fmt.Printf("Invalid config file: %s\n", err.Error())
-		os.Exit(1)
+//export Stop
+func Stop() bool {
+	psi.Stop()
+	select {
+	case provider.stopped <- true:
+	default:
 	}
 
-	Start(string(configFileContents), "")
+	return true
 }
+
+func main() {} // stub required by cgo

+ 1 - 0
MeasurementClient/example/.gitignore

@@ -0,0 +1 @@
+main

+ 12 - 0
MeasurementClient/example/Makefile

@@ -0,0 +1,12 @@
+main: main.o PsiphonTunnel.dylib
+	gcc PsiphonTunnel.dylib -o main main.o
+
+main.o: main.c
+	gcc -I.. -c main.c
+
+PsiphonTunnel.dylib: ../PsiphonTunnel.go
+	go build -buildmode=c-shared -o PsiphonTunnel.dylib ../PsiphonTunnel.go
+
+clean:
+	rm PsiphonTunnel.dylib PsiphonTunnel.h main main.o
+

+ 1 - 1
Bindings/CXX/psi.h → MeasurementClient/example/PsiphonTunnel.h

@@ -53,7 +53,7 @@ extern "C" {
 #endif
 
 
-extern char* Start(GoString p0, GoString p1);
+extern char* Start(GoString p0, GoString p1, GoString p2, GoInt64 p3);
 
 extern GoUint8 Stop();
 

+ 68 - 0
MeasurementClient/example/main.c

@@ -0,0 +1,68 @@
+#include "PsiphonTunnel.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *read_file(char *filename) {
+    char *buffer = NULL;
+    size_t size = 0;
+
+    FILE *fp = fopen(filename, "r");
+
+    if (!fp) {
+        return NULL;
+    }
+
+    fseek(fp, 0, SEEK_END);
+    size = ftell(fp); 
+
+    rewind(fp);
+    buffer = malloc((size + 1) * sizeof(*buffer));
+
+    fread(buffer, size, 1, fp);
+    buffer[size] = '\0';
+
+    return buffer;
+}
+
+int main(int argc, char *argv[]) {
+    
+    // load config
+    char * const default_config = "psiphon_config";
+
+    char * config = argv[1];
+
+    if (!config) {
+        config = default_config;
+        printf("Using default config file: %s\n", default_config);
+    }
+
+    char *file_contents = read_file(config);
+    if (!file_contents) {
+        printf("Could not find config file: %s\n", config);
+        return 1;
+    }
+
+    GoString psiphon_config = {file_contents, strlen(file_contents)};
+
+    // set server list
+    GoString serverList = {};
+
+    // set timout
+    long long timeout = 10;
+
+    // set network ID
+    char * const test_network_id = "TEST";
+    GoString network_id = {test_network_id, strlen(test_network_id)};
+
+    // start will return once Psiphon connects or does not connect for timeout seconds
+    char *result = Start(psiphon_config, serverList, network_id, timeout);
+    Stop();
+
+    // print results
+    printf("Result: %s\n", result);
+
+    // cleanup
+    free(result);
+}
+