Adam Pritchard 11 лет назад
Родитель
Сommit
1ff77a8070
5 измененных файлов с 58 добавлено и 29 удалено
  1. 22 17
      ConsoleClient/psiphonClient.go
  2. 3 2
      psiphon/controller.go
  3. 33 5
      psiphon/dataStore.go
  4. 0 1
      psiphon/notice.go
  5. 0 4
      psiphon/serverApi.go

+ 22 - 17
ConsoleClient/psiphonClient.go

@@ -60,6 +60,17 @@ func main() {
 		log.Fatalf("error processing configuration file: %s", err)
 	}
 
+	// Set logfile, if configured
+
+	if config.LogFilename != "" {
+		logFile, err := os.OpenFile(config.LogFilename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
+		if err != nil {
+			log.Fatalf("error opening log file: %s", err)
+		}
+		defer logFile.Close()
+		log.SetOutput(logFile)
+	}
+
 	// Handle optional profiling parameter
 
 	if profileFilename != "" {
@@ -100,35 +111,29 @@ func main() {
 		}
 	}
 
-	// Set logfile, if configured
-
-	if config.LogFilename != "" {
-		logFile, err := os.OpenFile(config.LogFilename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
-		if err != nil {
-			log.Fatalf("error opening log file: %s", err)
-		}
-		defer logFile.Close()
-		log.SetOutput(logFile)
-	}
-
 	// Run Psiphon
 
 	controller := psiphon.NewController(config)
+	controllerStopSignal := make(chan struct{}, 1)
 	shutdownBroadcast := make(chan struct{})
 	controllerWaitGroup := new(sync.WaitGroup)
 	controllerWaitGroup.Add(1)
 	go func() {
 		defer controllerWaitGroup.Done()
 		controller.Run(shutdownBroadcast)
+		controllerStopSignal <- *new(struct{})
 	}()
 
-	// Wait for an OS signal, then stop Psiphon and exit
+	// Wait for an OS signal or a Run stop signal, then stop Psiphon and exit
 
 	systemStopSignal := make(chan os.Signal, 1)
 	signal.Notify(systemStopSignal, os.Interrupt, os.Kill)
-	<-systemStopSignal
-
-	psiphon.Notice(psiphon.NOTICE_INFO, "shutdown by system")
-	close(shutdownBroadcast)
-	controllerWaitGroup.Wait()
+	select {
+	case <-systemStopSignal:
+		psiphon.Notice(psiphon.NOTICE_INFO, "shutdown by system")
+		close(shutdownBroadcast)
+		controllerWaitGroup.Wait()
+	case <-controllerStopSignal:
+		psiphon.Notice(psiphon.NOTICE_INFO, "shutdown by controller")
+	}
 }

+ 3 - 2
psiphon/controller.go

@@ -89,9 +89,10 @@ func (controller *Controller) Run(shutdownBroadcast <-chan struct{}) {
 		return
 	}
 	defer socksProxy.Close()
+
 	httpProxy, err := NewHttpProxy(controller.config, controller)
 	if err != nil {
-		Notice(NOTICE_ALERT, "error initializing local SOCKS proxy: %s", err)
+		Notice(NOTICE_ALERT, "error initializing local HTTP proxy: %s", err)
 		return
 	}
 	defer httpProxy.Close()
@@ -228,7 +229,7 @@ loop:
 	Notice(NOTICE_INFO, "exiting run tunnels")
 }
 
-// HandleFailedTunnel implements the TunnelOwner interface. This function
+// SignalTunnelFailure implements the TunnelOwner interface. This function
 // is called by Tunnel.operateTunnel when the tunnel has detected that it
 // has failed. The Controller will signal runTunnels to create a new
 // tunnel and/or remove the tunnel from the list of active tunnels.

+ 33 - 5
psiphon/dataStore.go

@@ -24,6 +24,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"math/rand"
 	"path/filepath"
 	"strings"
 	"sync"
@@ -221,10 +222,17 @@ func StoreServerEntry(serverEntry *ServerEntry, replaceIfExists bool) error {
 	})
 }
 
-// StoreServerEntries stores a list of server entries. This is simply a
-// helper which calls StoreServerEntry on each entry in the list -- so there
-// is an independent transaction for each entry -- and stops on first error.
+// StoreServerEntries shuffles and stores a list of server entries.
+// Shuffling is performed on imported server entrues as part of client-side
+// load balancing.
+// There is an independent transaction for each entry insert/update.
 func StoreServerEntries(serverEntries []*ServerEntry, replaceIfExists bool) error {
+
+	for index := len(serverEntries) - 1; index > 0; index-- {
+		swapIndex := rand.Intn(index + 1)
+		serverEntries[index], serverEntries[swapIndex] = serverEntries[swapIndex], serverEntries[index]
+	}
+
 	for _, serverEntry := range serverEntries {
 		err := StoreServerEntry(serverEntry, replaceIfExists)
 		if err != nil {
@@ -286,10 +294,30 @@ func (iterator *ServerEntryIterator) Reset() error {
 		return ContextError(err)
 	}
 	var cursor *sql.Rows
+
+	// This query implements the Psiphon server candidate selection
+	// algorithm: the first set of server candidates are in rank (priority)
+	// order, to favor previously successful servers; then the remaining
+	// long tail is shuffled to raise up less recent candidates.
+
 	whereClause, whereParams := makeServerEntryWhereClause(
 		iterator.region, iterator.protocol, nil)
-	query := "select data from serverEntry" + whereClause + " order by rank desc;"
-	cursor, err = transaction.Query(query, whereParams...)
+	headLength := CONNECTION_WORKER_POOL_SIZE
+	queryFormat := `
+		select data from serverEntry %s
+		order by case
+		when rank > coalesce((select rank from serverEntry %s order by rank desc limit ?, 1), -1) then rank
+		else abs(random())%%((select rank from serverEntry %s order by rank desc limit ?, 1))
+		end desc;`
+	query := fmt.Sprintf(queryFormat, whereClause, whereClause, whereClause)
+	params := make([]interface{}, 0)
+	params = append(params, whereParams...)
+	params = append(params, whereParams...)
+	params = append(params, headLength)
+	params = append(params, whereParams...)
+	params = append(params, headLength)
+
+	cursor, err = transaction.Query(query, params...)
 	if err != nil {
 		transaction.Rollback()
 		return ContextError(err)

+ 0 - 1
psiphon/notice.go

@@ -35,7 +35,6 @@ const (
 	NOTICE_HOMEPAGE         = "HOMEPAGE"
 	NOTICE_PAGE_VIEW_REGEX  = "PAGE-VIEW-REGEX"
 	NOTICE_HTTPS_REGEX      = "HTTPS-REGEX"
-	NOTICE_VPN_PSK          = "VPN-PSK"
 )
 
 func Notice(prefix, format string, args ...interface{}) {

+ 0 - 4
psiphon/serverApi.go

@@ -166,7 +166,6 @@ func (session *Session) doHandshakeRequest() error {
 		PageViewRegexes      []map[string]string `json:"page_view_regexes"`
 		HttpsRequestRegexes  []map[string]string `json:"https_request_regexes"`
 		EncodedServerList    []string            `json:"encoded_server_list"`
-		VpnPsk               string              `json:"l2tp_ipsec_psk"`
 	}
 	err = json.Unmarshal(configLine, &handshakeConfig)
 	if err != nil {
@@ -193,9 +192,6 @@ func (session *Session) doHandshakeRequest() error {
 	if handshakeConfig.UpgradeClientVersion != "" {
 		Notice(NOTICE_UPGRADE, "%s", handshakeConfig.UpgradeClientVersion)
 	}
-	if handshakeConfig.VpnPsk != "" {
-		Notice(NOTICE_VPN_PSK, "%s", handshakeConfig.VpnPsk)
-	}
 
 	session.statsRegexps = MakeRegexps(
 		handshakeConfig.PageViewRegexes,