From 1ddd5da865c1a06b997769b03339ecf60c49e84d Mon Sep 17 00:00:00 2001 From: Chad Retz Date: Thu, 20 Sep 2018 11:47:42 -0500 Subject: [PATCH] Abstracted embedded part to specific versions, fixes #14 --- process/embedded/embeddedtest/main.go | 25 ++++++ process/embedded/process.go | 105 ++---------------------- process/embedded/tor-0.3.3/process.go | 112 ++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 99 deletions(-) create mode 100644 process/embedded/embeddedtest/main.go create mode 100644 process/embedded/tor-0.3.3/process.go diff --git a/process/embedded/embeddedtest/main.go b/process/embedded/embeddedtest/main.go new file mode 100644 index 0000000..5dc45b5 --- /dev/null +++ b/process/embedded/embeddedtest/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/cretz/bine/process/embedded" +) + +// Simply calls Tor will the same parameters +func main() { + if err := runTor(os.Args[1:]...); err != nil { + log.Fatal(err) + } +} + +func runTor(args ...string) error { + process, err := embedded.NewCreator().New(context.Background(), args...) + if err == nil { + process.Start() + err = process.Wait() + } + return err +} diff --git a/process/embedded/process.go b/process/embedded/process.go index 3f05ea6..27c13bf 100644 --- a/process/embedded/process.go +++ b/process/embedded/process.go @@ -12,112 +12,19 @@ // Windows this means something like http://www.msys2.org/ needs to be // installed with gcc.exe on the PATH (i.e. the same gcc that was used to build // the static Tor lib). +// +// The default in here is currently for Tor 0.3.3.x which uses the tor-0.3.3 +// subdirectory. A different subdirectory can be used for a different version. package embedded import ( - "context" - "fmt" - "github.com/cretz/bine/process" + + tor033 "github.com/cretz/bine/process/embedded/tor-0.3.3" ) -/* -#cgo CFLAGS: -I${SRCDIR}/../../../tor-static/tor/src/or -#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/or -ltor -#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/common -lor -lor-crypto -lcurve25519_donna -lor-ctime -lor-event -#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/trunnel -lor-trunnel -#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/ext/keccak-tiny -lkeccak-tiny -#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/ext/ed25519/ref10 -led25519_ref10 -#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/ext/ed25519/donna -led25519_donna -#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/libevent/dist/lib -levent -#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/xz/dist/lib -llzma -#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/zlib/dist/lib -lz -#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/openssl/dist/lib -lssl -lcrypto -#cgo windows LDFLAGS: -lws2_32 -lcrypt32 -lgdi32 -#cgo !windows LDFLAGS: -lm - -#include -#include - -// Ref: https://stackoverflow.com/questions/45997786/passing-array-of-string-as-parameter-from-go-to-c-function - -static char** makeCharArray(int size) { - return calloc(sizeof(char*), size); -} - -static void setArrayString(char **a, char *s, int n) { - a[n] = s; -} - -static void freeCharArray(char **a, int size) { - int i; - for (i = 0; i < size; i++) - free(a[i]); - free(a); -} -*/ -import "C" - -type embeddedCreator struct{} - // NewCreator creates a process.Creator for statically-linked Tor embedded in // the binary. func NewCreator() process.Creator { - return embeddedCreator{} -} - -type embeddedProcess struct { - ctx context.Context - args []string - doneCh chan int -} - -func (embeddedCreator) New(ctx context.Context, args ...string) (process.Process, error) { - return &embeddedProcess{ctx: ctx, args: args}, nil -} - -func (e *embeddedProcess) Start() error { - if e.doneCh != nil { - return fmt.Errorf("Already started") - } - // Create the char array for the args - args := append([]string{"tor"}, e.args...) - charArray := C.makeCharArray(C.int(len(args))) - for i, a := range args { - C.setArrayString(charArray, C.CString(a), C.int(i)) - } - // Build the conf - conf := C.tor_main_configuration_new() - if code := C.tor_main_configuration_set_command_line(conf, C.int(len(args)), charArray); code != 0 { - C.tor_main_configuration_free(conf) - C.freeCharArray(charArray, C.int(len(args))) - return fmt.Errorf("Failed to set command line args, code: %v", int(code)) - } - // Run it async - e.doneCh = make(chan int, 1) - go func() { - defer C.freeCharArray(charArray, C.int(len(args))) - defer C.tor_main_configuration_free(conf) - e.doneCh <- int(C.tor_run_main(conf)) - }() - return nil -} - -func (e *embeddedProcess) Wait() error { - if e.doneCh == nil { - return fmt.Errorf("Not started") - } - ctx := e.ctx - if ctx == nil { - ctx = context.Background() - } - select { - case <-ctx.Done(): - return ctx.Err() - case code := <-e.doneCh: - if code == 0 { - return nil - } - return fmt.Errorf("Command completed with error exit code: %v", code) - } + return tor033.NewCreator() } diff --git a/process/embedded/tor-0.3.3/process.go b/process/embedded/tor-0.3.3/process.go new file mode 100644 index 0000000..2954c7a --- /dev/null +++ b/process/embedded/tor-0.3.3/process.go @@ -0,0 +1,112 @@ +// Package tor033 implements process interfaces for statically linked +// Tor 0.3.3x versions. See the process/embedded package for the generic +// abstraction +package embedded + +import ( + "context" + "fmt" + + "github.com/cretz/bine/process" +) + +/* +#cgo CFLAGS: -I${SRCDIR}/../../../../tor-static/tor/src/or +#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/tor/src/or -ltor +#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/tor/src/common -lor -lor-crypto -lcurve25519_donna -lor-ctime -lor-event +#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/tor/src/trunnel -lor-trunnel +#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/tor/src/ext/keccak-tiny -lkeccak-tiny +#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/tor/src/ext/ed25519/ref10 -led25519_ref10 +#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/tor/src/ext/ed25519/donna -led25519_donna +#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/libevent/dist/lib -levent +#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/xz/dist/lib -llzma +#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/zlib/dist/lib -lz +#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/openssl/dist/lib -lssl -lcrypto +#cgo windows LDFLAGS: -lws2_32 -lcrypt32 -lgdi32 +#cgo !windows LDFLAGS: -lm + +#include +#include + +// Ref: https://stackoverflow.com/questions/45997786/passing-array-of-string-as-parameter-from-go-to-c-function + +static char** makeCharArray(int size) { + return calloc(sizeof(char*), size); +} + +static void setArrayString(char **a, char *s, int n) { + a[n] = s; +} + +static void freeCharArray(char **a, int size) { + int i; + for (i = 0; i < size; i++) + free(a[i]); + free(a); +} +*/ +import "C" + +type embeddedCreator struct{} + +// NewCreator creates a process.Creator for statically-linked Tor embedded in +// the binary. +func NewCreator() process.Creator { + return embeddedCreator{} +} + +type embeddedProcess struct { + ctx context.Context + args []string + doneCh chan int +} + +func (embeddedCreator) New(ctx context.Context, args ...string) (process.Process, error) { + return &embeddedProcess{ctx: ctx, args: args}, nil +} + +func (e *embeddedProcess) Start() error { + if e.doneCh != nil { + return fmt.Errorf("Already started") + } + // Create the char array for the args + args := append([]string{"tor"}, e.args...) + charArray := C.makeCharArray(C.int(len(args))) + for i, a := range args { + C.setArrayString(charArray, C.CString(a), C.int(i)) + } + // Build the conf + conf := C.tor_main_configuration_new() + if code := C.tor_main_configuration_set_command_line(conf, C.int(len(args)), charArray); code != 0 { + C.tor_main_configuration_free(conf) + C.freeCharArray(charArray, C.int(len(args))) + return fmt.Errorf("Failed to set command line args, code: %v", int(code)) + } + // Run it async + e.doneCh = make(chan int, 1) + go func() { + defer C.freeCharArray(charArray, C.int(len(args))) + defer C.tor_main_configuration_free(conf) + e.doneCh <- int(C.tor_run_main(conf)) + }() + return nil +} + +func (e *embeddedProcess) Wait() error { + if e.doneCh == nil { + return fmt.Errorf("Not started") + } + ctx := e.ctx + if ctx == nil { + ctx = context.Background() + } + select { + case <-ctx.Done(): + return ctx.Err() + case code := <-e.doneCh: + if code == 0 { + return nil + } + return fmt.Errorf("Command completed with error exit code: %v", code) + } +}