[tor-commits] [flashproxy/master] Documentation comments.

dcf at torproject.org dcf at torproject.org
Wed Jan 30 05:11:38 UTC 2013


commit 75eff440ccef95f818ac16ae6b327032cd8d98aa
Author: David Fifield <david at bamsoftware.com>
Date:   Mon Nov 26 21:32:11 2012 -0800

    Documentation comments.
---
 websocket-transport/pt.go        |  121 ++++++++++++++++++++++++++++----------
 websocket-transport/socks.go     |    6 ++
 websocket-transport/websocket.go |   74 +++++++++++++++++++----
 3 files changed, 156 insertions(+), 45 deletions(-)

diff --git a/websocket-transport/pt.go b/websocket-transport/pt.go
index f8760d3..8e74d13 100644
--- a/websocket-transport/pt.go
+++ b/websocket-transport/pt.go
@@ -1,3 +1,27 @@
+// Tor pluggable transports library.
+//
+// Sample client usage:
+//
+// PtClientSetup([]string{"foo"}
+// ln, err := startSocksListener()
+// if err != nil {
+// 	panic(err.Error())
+// }
+// PtCmethod("foo", "socks4", ln.Addr())
+// PtCmethodsDone()
+//
+// Sample server usage:
+//
+// info := PtServerSetup([]string{"foo", "bar"})
+// for _, bindAddr := range info.BindAddrs {
+// 	ln, err := startListener(bindAddr.Addr)
+// 	if err != nil {
+// 		panic(err.Error())
+// 	}
+// 	PtSmethod(bindAddr.MethodName, ln.Addr())
+// }
+// PtSmethodsDone()
+
 package main
 
 import (
@@ -35,6 +59,8 @@ func escape(s string) string {
 	return buf.String()
 }
 
+// Print a pluggable transports protocol line to stdout. The line consists of an
+// unescaped keyword, followed by any number of escaped strings.
 func PtLine(keyword string, v ...string) {
 	var buf bytes.Buffer
 	buf.WriteString(keyword)
@@ -44,21 +70,56 @@ func PtLine(keyword string, v ...string) {
 	fmt.Println(buf.String())
 }
 
+// All of the Pt*Error functions call os.Exit(1).
+
+// Emit an ENV-ERROR with explanation text.
 func PtEnvError(msg string) {
 	PtLine("ENV-ERROR", msg)
 	os.Exit(1)
 }
 
+// Emit a VERSION-ERROR with explanation text.
 func PtVersionError(msg string) {
 	PtLine("VERSION-ERROR", msg)
 	os.Exit(1)
 }
 
+// Emit a CMETHOD-ERROR with explanation text.
 func PtCmethodError(methodName, msg string) {
 	PtLine("CMETHOD-ERROR", methodName, msg)
 	os.Exit(1)
 }
 
+// Emit an SMETHOD-ERROR with explanation text.
+func PtSmethodError(methodName, msg string) {
+	PtLine("SMETHOD-ERROR", methodName, msg)
+	os.Exit(1)
+}
+
+// Emit a CMETHOD line. socks must be "socks4" or "socks5". Call this once for
+// each listening client SOCKS port.
+func PtCmethod(name string, socks string, addr net.Addr) {
+	PtLine("CMETHOD", name, socks, addr.String())
+}
+
+// Emit a CMETHODS DONE line. Call this after opening all client listeners.
+func PtCmethodsDone() {
+	PtLine("CMETHODS", "DONE")
+}
+
+// Emit an SMETHOD line. Call this once for each listening server port.
+func PtSmethod(name string, addr net.Addr) {
+	PtLine("SMETHOD", name, addr.String())
+}
+
+// Emit an SMETHODS DONE line. Call this after opening all server listeners.
+func PtSmethodsDone() {
+	PtLine("SMETHODS", "DONE")
+}
+
+// Get a pluggable transports version offered by Tor and understood by us, if
+// any. The only version we understand is "1". This function reads the
+// environment variable TOR_PT_MANAGED_TRANSPORT_VER.
 func PtGetManagedTransportVer() string {
 	const transportVersion = "1"
 	for _, offered := range strings.Split(getenvRequired("TOR_PT_MANAGED_TRANSPORT_VER"), ",") {
@@ -69,14 +130,17 @@ func PtGetManagedTransportVer() string {
 	return ""
 }
 
-func PtGetClientTransports(supported []string) []string {
+// Get the intersection of the method names offered by Tor and those in
+// methodNames. This function reads the environment variable
+// TOR_PT_CLIENT_TRANSPORTS.
+func PtGetClientTransports(methodNames []string) []string {
 	clientTransports := getenvRequired("TOR_PT_CLIENT_TRANSPORTS")
 	if clientTransports == "*" {
-		return supported
+		return methodNames
 	}
 	result := make([]string, 0)
 	for _, requested := range strings.Split(clientTransports, ",") {
-		for _, methodName := range supported {
+		for _, methodName := range methodNames {
 			if requested == methodName {
 				result = append(result, methodName)
 				break
@@ -86,14 +150,9 @@ func PtGetClientTransports(supported []string) []string {
 	return result
 }
 
-func PtCmethod(name string, socks string, addr net.Addr) {
-	PtLine("CMETHOD", name, socks, addr.String())
-}
-
-func PtCmethodsDone() {
-	PtLine("CMETHODS", "DONE")
-}
-
+// Check the client pluggable transports environments, emitting an error message
+// and exiting the program if any error is encountered. Returns a subset of
+// methodNames requested by Tor.
 func PtClientSetup(methodNames []string) []string {
 	ver := PtGetManagedTransportVer()
 	if ver == "" {
@@ -111,19 +170,14 @@ func PtClientSetup(methodNames []string) []string {
 	return methods
 }
 
-func PtSmethodError(methodName, msg string) {
-	PtLine("SMETHOD-ERROR", methodName, msg)
-	os.Exit(1)
-}
-
-func PtSmethod(name string, addr net.Addr) {
-	PtLine("SMETHOD", name, addr.String())
-}
-
-func PtSmethodsDone() {
-	PtLine("SMETHODS", "DONE")
+// A combination of a method name and an address, as extracted from
+// TOR_PT_SERVER_BINDADDR.
+type PtBindAddr struct {
+	MethodName string
+	Addr       *net.TCPAddr
 }
 
+// Resolve an address string into a net.TCPAddr.
 func resolveBindAddr(bindAddr string) (*net.TCPAddr, error) {
 	addr, err := net.ResolveTCPAddr("tcp", bindAddr)
 	if err == nil {
@@ -140,16 +194,13 @@ func resolveBindAddr(bindAddr string) (*net.TCPAddr, error) {
 	return net.ResolveTCPAddr("tcp", bindAddr)
 }
 
-type PtBindAddr struct {
-	MethodName string
-	Addr       *net.TCPAddr
-}
-
-func filterBindAddrs(addrs []PtBindAddr, supported []string) []PtBindAddr {
+// Return a new slice, the members of which are those members of addrs having a
+// MethodName in methodsNames.
+func filterBindAddrs(addrs []PtBindAddr, methodNames []string) []PtBindAddr {
 	var result []PtBindAddr
 
 	for _, ba := range addrs {
-		for _, methodName := range supported {
+		for _, methodName := range methodNames {
 			if ba.MethodName == methodName {
 				result = append(result, ba)
 				break
@@ -162,8 +213,8 @@ func filterBindAddrs(addrs []PtBindAddr, supported []string) []PtBindAddr {
 
 // Return a map from method names to bind addresses. The map is the contents of
 // TOR_PT_SERVER_BINDADDR, with keys filtered by TOR_PT_SERVER_TRANSPORTS, and
-// further filtered by methods that we know.
-func PtGetServerBindAddrs(supported []string) []PtBindAddr {
+// further filtered by the methods in methodNames.
+func PtGetServerBindAddrs(methodNames []string) []PtBindAddr {
 	var result []PtBindAddr
 
 	// Get the list of all requested bindaddrs.
@@ -191,16 +242,22 @@ func PtGetServerBindAddrs(supported []string) []PtBindAddr {
 	}
 
 	// Finally filter by what we understand.
-	result = filterBindAddrs(result, supported)
+	result = filterBindAddrs(result, methodNames)
 
 	return result
 }
 
+// This structure is returned by PtServerSetup. It consists of a list of
+// PtBindAddrs, along with a single address for the ORPort.
 type PtServerInfo struct {
 	BindAddrs []PtBindAddr
 	OrAddr    *net.TCPAddr
 }
 
+// Check the server pluggable transports environments, emitting an error message
+// and exiting the program if any error is encountered. Resolves the various
+// requested bind addresses and the server ORPort. Returns a PtServerInfo
+// struct.
 func PtServerSetup(methodNames []string) PtServerInfo {
 	var info PtServerInfo
 	var err error
diff --git a/websocket-transport/socks.go b/websocket-transport/socks.go
index 061869e..e8ef51f 100644
--- a/websocket-transport/socks.go
+++ b/websocket-transport/socks.go
@@ -1,3 +1,5 @@
+// SOCKS4a server library.
+
 package main
 
 import (
@@ -16,6 +18,7 @@ const (
 	socksRequestFailed   = 0x5b
 )
 
+// Read a SOCKS4a connect request. Returns a "host:port" string.
 func ReadSocks4aConnect(s io.Reader) (string, error) {
 	r := bufio.NewReader(s)
 
@@ -57,6 +60,7 @@ func ReadSocks4aConnect(s io.Reader) (string, error) {
 	return fmt.Sprintf("%s:%d", host, port), nil
 }
 
+// Send a SOCKS4a response with the given code and address.
 func SendSocks4aResponse(w io.Writer, code byte, addr *net.TCPAddr) error {
 	var resp [8]byte
 	resp[0] = socksResponseVersion
@@ -73,10 +77,12 @@ func SendSocks4aResponse(w io.Writer, code byte, addr *net.TCPAddr) error {
 
 var emptyAddr = net.TCPAddr{net.IPv4(0, 0, 0, 0), 0}
 
+// Send a SOCKS4a response code 0x5a.
 func SendSocks4aResponseGranted(w io.Writer, addr *net.TCPAddr) error {
 	return SendSocks4aResponse(w, socksRequestGranted, addr)
 }
 
+// Send a SOCKS4a response code 0x5b (with an all-zero address).
 func SendSocks4aResponseFailed(w io.Writer) error {
 	return SendSocks4aResponse(w, socksRequestFailed, &emptyAddr)
 }
diff --git a/websocket-transport/websocket.go b/websocket-transport/websocket.go
index cdb4b5d..7aca736 100644
--- a/websocket-transport/websocket.go
+++ b/websocket-transport/websocket.go
@@ -1,3 +1,19 @@
+// WebSocket library. Only the RFC 6455 variety of WebSocket is supported.
+//
+// Reading and writing is strictly per-frame (or per-message). There is no way
+// to partially read a frame. WebsocketConfig.MaxMessageSize affords control of
+// the maximum buffering of messages.
+//
+// Example usage:
+//
+// func doSomething(ws *Websocket) {
+// }
+// var config WebsocketConfig
+// config.Subprotocols = []string{"base64"}
+// config.MaxMessageSize = 2500
+// http.Handle("/", config.Handler(doSomething))
+// err = http.ListenAndServe(":8080", nil)
+
 package main
 
 import (
@@ -15,11 +31,17 @@ import (
 	"strings"
 )
 
+// Settings for potential WebSocket connections. Subprotocols is a list of
+// supported subprotocols as in RFC 6455 section 1.9. When answering client
+// requests, the first of the client's requests subprotocols that is also in
+// this list (if any) will be used as the subprotocol for the connection.
+// MaxMessageSize is a limit on buffering messages.
 type WebsocketConfig struct {
 	Subprotocols   []string
 	MaxMessageSize uint64
 }
 
+// Return the WebSocket's maximum message size, or a default maximum size.
 func (config *WebsocketConfig) maxMessageSize() uint64 {
 	if config.MaxMessageSize == 0 {
 		return 64000
@@ -27,37 +49,47 @@ func (config *WebsocketConfig) maxMessageSize() uint64 {
 	return config.MaxMessageSize
 }
 
-type Websocket struct {
-	Conn  net.Conn
-	Bufrw *bufio.ReadWriter
-	// Whether we are a client or a server implications for masking.
-	IsClient       bool
-	MaxMessageSize uint64
-	Subprotocol    string
-	messageBuf     bytes.Buffer
-}
-
+// Representation of a WebSocket frame. The Payload is always without masking.
 type WebsocketFrame struct {
 	Fin     bool
 	Opcode  byte
 	Payload []byte
 }
 
+// Return true iff the frame's opcode says it is a control frame.
 func (frame *WebsocketFrame) IsControl() bool {
 	return (frame.Opcode & 0x08) != 0
 }
 
+// Representation of a WebSocket message. The Payload is always without masking.
 type WebsocketMessage struct {
 	Opcode  byte
 	Payload []byte
 }
 
+// A WebSocket connection after hijacking from HTTP.
+type Websocket struct {
+	// Conn and ReadWriter from http.ResponseWriter.Hijack.
+	Conn  net.Conn
+	Bufrw *bufio.ReadWriter
+	// Whether we are a client or a server has implications for masking.
+	IsClient       bool
+	// Set from a parent WebsocketConfig.
+	MaxMessageSize int
+	// The single selected subprotocol after negotiation, or "".
+	Subprotocol    string
+	// Buffer for message payloads, which may be interrupted by control
+	// messages.
+	messageBuf     bytes.Buffer
+}
+
 func applyMask(payload []byte, maskKey [4]byte) {
 	for i, _ := range payload {
 		payload[i] = payload[i] ^ maskKey[i%4]
 	}
 }
 
+// Read a single frame from the WebSocket.
 func (ws *Websocket) ReadFrame() (frame WebsocketFrame, err error) {
 	var b byte
 	err = binary.Read(ws.Bufrw, binary.BigEndian, &b)
@@ -122,6 +154,10 @@ func (ws *Websocket) ReadFrame() (frame WebsocketFrame, err error) {
 	return frame, nil
 }
 
+// Read a single message from the WebSocket. Multiple fragmented frames are
+// combined into a single message before being returned. Non-control messages
+// may be interrupted by control frames. The control frames are returned as
+// individual messages before the message that they interrupt.
 func (ws *Websocket) ReadMessage() (message WebsocketMessage, err error) {
 	var opcode byte = 0
 	for {
@@ -168,7 +204,8 @@ func (ws *Websocket) ReadMessage() (message WebsocketMessage, err error) {
 	return message, nil
 }
 
-// Destructively masks payload in place if ws.IsClient.
+// Write a single frame to the WebSocket stream. Destructively masks payload in
+// place if ws.IsClient. Frames are always unfragmented.
 func (ws *Websocket) WriteFrame(opcode byte, payload []byte) (err error) {
 	if opcode >= 16 {
 		err = errors.New(fmt.Sprintf("opcode %d is >= 16", opcode))
@@ -212,10 +249,14 @@ func (ws *Websocket) WriteFrame(opcode byte, payload []byte) (err error) {
 	return
 }
 
+// Write a single message to the WebSocket stream. Destructively masks payload
+// in place if ws.IsClient. Messages are always sent as a single unfragmented
+// frame.
 func (ws *Websocket) WriteMessage(opcode byte, payload []byte) (err error) {
 	return ws.WriteFrame(opcode, payload)
 }
 
+// Split a strong on commas and trim whitespace.
 func commaSplit(s string) []string {
 	var result []string
 	if strings.TrimSpace(s) == "" {
@@ -227,6 +268,7 @@ func commaSplit(s string) []string {
 	return result
 }
 
+// Returns true iff one of the strings in haystack is needle.
 func containsCase(haystack []string, needle string) bool {
 	for _, e := range haystack {
 		if strings.ToLower(e) == strings.ToLower(needle) {
@@ -236,6 +278,7 @@ func containsCase(haystack []string, needle string) bool {
 	return false
 }
 
+// One-step SHA-1 hash of a string.
 func sha1Hash(data string) []byte {
 	h := sha1.New()
 	h.Write([]byte(data))
@@ -250,11 +293,15 @@ func httpError(w http.ResponseWriter, bufrw *bufio.ReadWriter, code int) {
 	bufrw.Flush()
 }
 
+// An implementation of http.Handler with a WebsocketConfig. The ServeHTTP
+// function calls websocketCallback assuming WebSocket HTTP negotiation is
+// successful.
 type WebSocketHTTPHandler struct {
 	Config            *WebsocketConfig
 	WebsocketCallback func(*Websocket)
 }
 
+// Implements the http.Handler interface.
 func (handler *WebSocketHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	conn, bufrw, err := w.(http.Hijacker).Hijack()
 	if err != nil {
@@ -362,6 +409,7 @@ func (handler *WebSocketHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.
 	handler.WebsocketCallback(&ws)
 }
 
-func (config *WebsocketConfig) Handler(f func(*Websocket)) http.Handler {
-	return &WebSocketHTTPHandler{config, f}
+// Return an http.Handler with the given callback function.
+func (config *WebsocketConfig) Handler(callback func(*Websocket)) http.Handler {
+	return &WebSocketHTTPHandler{config, callback}
 }





More information about the tor-commits mailing list