|
|
@@ -1,314 +0,0 @@
|
|
|
-package psi
|
|
|
-
|
|
|
-// This package is a shim between Java/Obj-C and the "psiphon" package. Due to limitations
|
|
|
-// on what Go types may be exposed (http://godoc.org/golang.org/x/mobile/cmd/gobind),
|
|
|
-// a psiphon.Controller cannot be directly used by Java. This shim exposes a trivial
|
|
|
-// Start/Stop interface on top of a single Controller instance.
|
|
|
-
|
|
|
-import (
|
|
|
- "context"
|
|
|
- "encoding/json"
|
|
|
- "fmt"
|
|
|
- "os"
|
|
|
- "strings"
|
|
|
- "sync"
|
|
|
-
|
|
|
- "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
|
|
|
- "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
|
|
|
- "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
|
|
|
- "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/tun"
|
|
|
-)
|
|
|
-
|
|
|
-type PsiphonProvider interface {
|
|
|
- Notice(noticeJSON string)
|
|
|
- HasNetworkConnectivity() int
|
|
|
- BindToDevice(fileDescriptor int) (string, error)
|
|
|
- IPv6Synthesize(IPv4Addr string) string
|
|
|
- GetPrimaryDnsServer() string
|
|
|
- GetSecondaryDnsServer() string
|
|
|
- GetNetworkID() string
|
|
|
-}
|
|
|
-
|
|
|
-func SetNoticeFiles(
|
|
|
- homepageFilename,
|
|
|
- rotatingFilename string,
|
|
|
- rotatingFileSize,
|
|
|
- rotatingSyncFrequency int) error {
|
|
|
-
|
|
|
- return psiphon.SetNoticeFiles(
|
|
|
- homepageFilename,
|
|
|
- rotatingFilename,
|
|
|
- rotatingFileSize,
|
|
|
- rotatingSyncFrequency)
|
|
|
-}
|
|
|
-
|
|
|
-func NoticeUserLog(message string) {
|
|
|
- psiphon.NoticeUserLog(message)
|
|
|
-}
|
|
|
-
|
|
|
-var controllerMutex sync.Mutex
|
|
|
-var controller *psiphon.Controller
|
|
|
-var controllerCtx context.Context
|
|
|
-var stopController context.CancelFunc
|
|
|
-var controllerWaitGroup *sync.WaitGroup
|
|
|
-
|
|
|
-func Start(
|
|
|
- configJson,
|
|
|
- embeddedServerEntryList,
|
|
|
- embeddedServerEntryListFilename string,
|
|
|
- provider PsiphonProvider,
|
|
|
- useDeviceBinder,
|
|
|
- useIPv6Synthesizer bool) error {
|
|
|
-
|
|
|
- controllerMutex.Lock()
|
|
|
- defer controllerMutex.Unlock()
|
|
|
-
|
|
|
- if controller != nil {
|
|
|
- return fmt.Errorf("already started")
|
|
|
- }
|
|
|
-
|
|
|
- // Clients may toggle Stop/Start immediately to apply new config settings
|
|
|
- // such as EgressRegion or Authorizations. When this restart is within the
|
|
|
- // same process and in a memory contrained environment, it is useful to
|
|
|
- // force garbage collection here to reclaim memory used by the previous
|
|
|
- // Controller.
|
|
|
- psiphon.DoGarbageCollection()
|
|
|
-
|
|
|
- // Wrap the provider in a layer that locks a mutex before calling a provider function.
|
|
|
- // The the provider callbacks are Java/Obj-C via gomobile, they are cgo calls that
|
|
|
- // can cause OS threads to be spawned. The mutex prevents many calling goroutines from
|
|
|
- // causing unbounded numbers of OS threads to be spawned.
|
|
|
- // TODO: replace the mutex with a semaphore, to allow a larger but still bounded concurrent
|
|
|
- // number of calls to the provider?
|
|
|
- provider = newMutexPsiphonProvider(provider)
|
|
|
-
|
|
|
- config, err := psiphon.LoadConfig([]byte(configJson))
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("error loading configuration file: %s", err)
|
|
|
- }
|
|
|
-
|
|
|
- config.NetworkConnectivityChecker = provider
|
|
|
-
|
|
|
- config.NetworkIDGetter = provider
|
|
|
-
|
|
|
- if useDeviceBinder {
|
|
|
- config.DeviceBinder = provider
|
|
|
- config.DnsServerGetter = provider
|
|
|
- }
|
|
|
-
|
|
|
- if useIPv6Synthesizer {
|
|
|
- config.IPv6Synthesizer = provider
|
|
|
- }
|
|
|
-
|
|
|
- // All config fields should be set before calling Commit.
|
|
|
-
|
|
|
- err = config.Commit()
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("error committing configuration file: %s", err)
|
|
|
- }
|
|
|
-
|
|
|
- psiphon.SetNoticeWriter(psiphon.NewNoticeReceiver(
|
|
|
- func(notice []byte) {
|
|
|
- provider.Notice(string(notice))
|
|
|
- }))
|
|
|
-
|
|
|
- // BuildInfo is a diagnostic notice, so emit only after config.Commit
|
|
|
- // sets EmitDiagnosticNotices.
|
|
|
-
|
|
|
- psiphon.NoticeBuildInfo()
|
|
|
-
|
|
|
- err = psiphon.InitDataStore(config)
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("error initializing datastore: %s", err)
|
|
|
- }
|
|
|
-
|
|
|
- // Stores list of server entries.
|
|
|
- err = storeServerEntries(
|
|
|
- config,
|
|
|
- embeddedServerEntryListFilename,
|
|
|
- embeddedServerEntryList)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- controller, err = psiphon.NewController(config)
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("error initializing controller: %s", err)
|
|
|
- }
|
|
|
-
|
|
|
- controllerCtx, stopController = context.WithCancel(context.Background())
|
|
|
-
|
|
|
- controllerWaitGroup = new(sync.WaitGroup)
|
|
|
- controllerWaitGroup.Add(1)
|
|
|
- go func() {
|
|
|
- defer controllerWaitGroup.Done()
|
|
|
- controller.Run(controllerCtx)
|
|
|
- }()
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func Stop() {
|
|
|
-
|
|
|
- controllerMutex.Lock()
|
|
|
- defer controllerMutex.Unlock()
|
|
|
-
|
|
|
- if controller != nil {
|
|
|
- stopController()
|
|
|
- controllerWaitGroup.Wait()
|
|
|
- controller = nil
|
|
|
- controllerCtx = nil
|
|
|
- stopController = nil
|
|
|
- controllerWaitGroup = nil
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// ReconnectTunnel initiates a reconnect of the current tunnel, if one is
|
|
|
-// running.
|
|
|
-func ReconnectTunnel() {
|
|
|
-
|
|
|
- controllerMutex.Lock()
|
|
|
- defer controllerMutex.Unlock()
|
|
|
-
|
|
|
- if controller != nil {
|
|
|
- controller.TerminateNextActiveTunnel()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// SetDynamicConfig overrides the sponsor ID and authorizations fields set in
|
|
|
-// the config passed to Start. SetDynamicConfig has no effect if no Controller
|
|
|
-// is started.
|
|
|
-//
|
|
|
-// The input newAuthorizationsList is a space-delimited list of base64
|
|
|
-// authorizations. This is a workaround for gobind type limitations.
|
|
|
-func SetDynamicConfig(newSponsorID, newAuthorizationsList string) {
|
|
|
-
|
|
|
- controllerMutex.Lock()
|
|
|
- defer controllerMutex.Unlock()
|
|
|
-
|
|
|
- if controller != nil {
|
|
|
- controller.SetDynamicConfig(
|
|
|
- newSponsorID,
|
|
|
- strings.Split(newAuthorizationsList, " "))
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// Encrypt and upload feedback.
|
|
|
-func SendFeedback(configJson, diagnosticsJson, b64EncodedPublicKey, uploadServer, uploadPath, uploadServerHeaders string) error {
|
|
|
- return psiphon.SendFeedback(configJson, diagnosticsJson, b64EncodedPublicKey, uploadServer, uploadPath, uploadServerHeaders)
|
|
|
-}
|
|
|
-
|
|
|
-// Get build info from tunnel-core
|
|
|
-func GetBuildInfo() string {
|
|
|
- buildInfo, err := json.Marshal(common.GetBuildInfo())
|
|
|
- if err != nil {
|
|
|
- return ""
|
|
|
- }
|
|
|
- return string(buildInfo)
|
|
|
-}
|
|
|
-
|
|
|
-func GetPacketTunnelMTU() int {
|
|
|
- return tun.DEFAULT_MTU
|
|
|
-}
|
|
|
-
|
|
|
-func GetPacketTunnelDNSResolverIPv4Address() string {
|
|
|
- return tun.GetTransparentDNSResolverIPv4Address().String()
|
|
|
-}
|
|
|
-
|
|
|
-func GetPacketTunnelDNSResolverIPv6Address() string {
|
|
|
- return tun.GetTransparentDNSResolverIPv6Address().String()
|
|
|
-}
|
|
|
-
|
|
|
-// Helper function to store a list of server entries.
|
|
|
-// if embeddedServerEntryListFilename is not empty, embeddedServerEntryList will be ignored.
|
|
|
-func storeServerEntries(
|
|
|
- config *psiphon.Config,
|
|
|
- embeddedServerEntryListFilename, embeddedServerEntryList string) error {
|
|
|
-
|
|
|
- if embeddedServerEntryListFilename != "" {
|
|
|
-
|
|
|
- file, err := os.Open(embeddedServerEntryListFilename)
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("error reading embedded server list file: %s", common.ContextError(err))
|
|
|
- }
|
|
|
- defer file.Close()
|
|
|
-
|
|
|
- err = psiphon.StreamingStoreServerEntries(
|
|
|
- config,
|
|
|
- protocol.NewStreamingServerEntryDecoder(
|
|
|
- file,
|
|
|
- common.GetCurrentTimestamp(),
|
|
|
- protocol.SERVER_ENTRY_SOURCE_EMBEDDED),
|
|
|
- false)
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("error storing embedded server list: %s", common.ContextError(err))
|
|
|
- }
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- serverEntries, err := protocol.DecodeServerEntryList(
|
|
|
- embeddedServerEntryList,
|
|
|
- common.GetCurrentTimestamp(),
|
|
|
- protocol.SERVER_ENTRY_SOURCE_EMBEDDED)
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("error decoding embedded server list: %s", err)
|
|
|
- }
|
|
|
- err = psiphon.StoreServerEntries(config, serverEntries, false)
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("error storing embedded server list: %s", err)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-type mutexPsiphonProvider struct {
|
|
|
- sync.Mutex
|
|
|
- p PsiphonProvider
|
|
|
-}
|
|
|
-
|
|
|
-func newMutexPsiphonProvider(p PsiphonProvider) *mutexPsiphonProvider {
|
|
|
- return &mutexPsiphonProvider{p: p}
|
|
|
-}
|
|
|
-
|
|
|
-func (p *mutexPsiphonProvider) Notice(noticeJSON string) {
|
|
|
- p.Lock()
|
|
|
- defer p.Unlock()
|
|
|
- p.p.Notice(noticeJSON)
|
|
|
-}
|
|
|
-
|
|
|
-func (p *mutexPsiphonProvider) HasNetworkConnectivity() int {
|
|
|
- p.Lock()
|
|
|
- defer p.Unlock()
|
|
|
- return p.p.HasNetworkConnectivity()
|
|
|
-}
|
|
|
-
|
|
|
-func (p *mutexPsiphonProvider) BindToDevice(fileDescriptor int) (string, error) {
|
|
|
- p.Lock()
|
|
|
- defer p.Unlock()
|
|
|
- return p.p.BindToDevice(fileDescriptor)
|
|
|
-}
|
|
|
-
|
|
|
-func (p *mutexPsiphonProvider) IPv6Synthesize(IPv4Addr string) string {
|
|
|
- p.Lock()
|
|
|
- defer p.Unlock()
|
|
|
- return p.p.IPv6Synthesize(IPv4Addr)
|
|
|
-}
|
|
|
-
|
|
|
-func (p *mutexPsiphonProvider) GetPrimaryDnsServer() string {
|
|
|
- p.Lock()
|
|
|
- defer p.Unlock()
|
|
|
- return p.p.GetPrimaryDnsServer()
|
|
|
-}
|
|
|
-
|
|
|
-func (p *mutexPsiphonProvider) GetSecondaryDnsServer() string {
|
|
|
- p.Lock()
|
|
|
- defer p.Unlock()
|
|
|
- return p.p.GetSecondaryDnsServer()
|
|
|
-}
|
|
|
-
|
|
|
-func (p *mutexPsiphonProvider) GetNetworkID() string {
|
|
|
- p.Lock()
|
|
|
- defer p.Unlock()
|
|
|
- return p.p.GetNetworkID()
|
|
|
-}
|