/
process.go
139 lines (123 loc) · 4.36 KB
/
process.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Package tor035 implements process interfaces for statically linked
// Tor 0.3.5.x versions. See the process/embedded package for the generic
// abstraction
package tor035
import (
"context"
"fmt"
"net"
"os"
"github.com/cretz/bine/process"
)
/*
#cgo CFLAGS: -I${SRCDIR}/../../../../tor-static/tor/src/feature/api
// The libs below are generated via tor-static's show-libs
#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/tor/src/core -ltor-app
#cgo LDFLAGS: -L${SRCDIR}/../../../../tor-static/tor/src/lib -ltor-compress -ltor-evloop -ltor-tls -ltor-crypt-ops -lcurve25519_donna -ltor-geoip -ltor-process -ltor-time -ltor-fs -ltor-encoding -ltor-sandbox -ltor-container -ltor-net -ltor-thread -ltor-memarea -ltor-math -ltor-meminfo -ltor-osinfo -ltor-log -ltor-lock -ltor-fdio -ltor-string -ltor-term -ltor-smartlist-core -ltor-malloc -ltor-wallclock -ltor-err -ltor-intmath -ltor-ctime -ltor-trace
#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/tor/src/trunnel -lor-trunnel
#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 -liphlpapi -Wl,-Bstatic -lpthread
#cgo !windows LDFLAGS: -lm
#include <stdlib.h>
#ifdef _WIN32
#include <winsock2.h>
#endif
#include <tor_api.h>
// 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{}
// ProviderVersion returns the Tor provider name and version exposed from the
// Tor embedded API.
func ProviderVersion() string {
return C.GoString(C.tor_api_get_provider_version())
}
// 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
mainConf *C.struct_tor_main_configuration_t
args []string
doneCh chan int
}
// New implements process.Creator.New
func (embeddedCreator) New(ctx context.Context, args ...string) (process.Process, error) {
return &embeddedProcess{
ctx: ctx,
// TODO: mem leak if they never call Start; consider adding a Close()
mainConf: C.tor_main_configuration_new(),
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
if code := C.tor_main_configuration_set_command_line(e.mainConf, C.int(len(args)), charArray); code != 0 {
C.tor_main_configuration_free(e.mainConf)
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(e.mainConf)
e.doneCh <- int(C.tor_run_main(e.mainConf))
}()
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)
}
}
func (e *embeddedProcess) EmbeddedControlConn() (net.Conn, error) {
file := os.NewFile(uintptr(C.tor_main_configuration_setup_control_socket(e.mainConf)), "")
conn, err := net.FileConn(file)
if err != nil {
err = fmt.Errorf("Unable to create conn from control socket: %v", err)
}
return conn, err
}