commit 75eff440ccef95f818ac16ae6b327032cd8d98aa
Author: David Fifield <[email protected]>
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}
 }



_______________________________________________
tor-commits mailing list
[email protected]
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits

Reply via email to