Plan 9 from Bell Labs’s /usr/web/sources/contrib/ericvh/go-plan9/src/pkg/websocket/websocket.go

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The websocket package implements Web Socket protocol server.
package websocket

// References:
//   The Web Socket protocol: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol

// TODO(ukai):
//   better logging.

import (
	"bufio";
	"io";
	"net";
	"os";
)

type WebSocketAddr string

func (addr WebSocketAddr) Network() string	{ return "websocket" }

func (addr WebSocketAddr) String() string	{ return string(addr) }

// Conn is an channels to communicate over Web Socket.
type Conn struct {
	// An origin URI of the Web Socket.
	Origin	string;
	// A location URI of the Web Socket.
	Location	string;
	// A subprotocol of the Web Socket.
	Protocol	string;

	buf	*bufio.ReadWriter;
	rwc	io.ReadWriteCloser;
}

// newConn creates a new Web Socket.
func newConn(origin, location, protocol string, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
	if buf == nil {
		br := bufio.NewReader(rwc);
		bw := bufio.NewWriter(rwc);
		buf = bufio.NewReadWriter(br, bw);
	}
	ws := &Conn{origin, location, protocol, buf, rwc};
	return ws;
}

func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
	for {
		frameByte, err := ws.buf.ReadByte();
		if err != nil {
			return n, err
		}
		if (frameByte & 0x80) == 0x80 {
			length := 0;
			for {
				c, err := ws.buf.ReadByte();
				if err != nil {
					return n, err
				}
				if (c & 0x80) == 0x80 {
					length = length*128 + int(c&0x7f)
				} else {
					break
				}
			}
			for length > 0 {
				_, err := ws.buf.ReadByte();
				if err != nil {
					return n, err
				}
				length--;
			}
		} else {
			for {
				c, err := ws.buf.ReadByte();
				if err != nil {
					return n, err
				}
				if c == '\xff' {
					return n, err
				}
				if frameByte == 0 {
					if n+1 <= cap(msg) {
						msg = msg[0 : n+1]
					}
					msg[n] = c;
					n++;
				}
				if n >= cap(msg) {
					return n, os.E2BIG
				}
			}
		}
	}

	panic("unreachable");
}

func (ws *Conn) Write(msg []byte) (n int, err os.Error) {
	ws.buf.WriteByte(0);
	ws.buf.Write(msg);
	ws.buf.WriteByte(0xff);
	err = ws.buf.Flush();
	return len(msg), err;
}

func (ws *Conn) Close() os.Error	{ return ws.rwc.Close() }

func (ws *Conn) LocalAddr() net.Addr	{ return WebSocketAddr(ws.Origin) }

func (ws *Conn) RemoteAddr() net.Addr	{ return WebSocketAddr(ws.Location) }

func (ws *Conn) SetTimeout(nsec int64) os.Error {
	if conn, ok := ws.rwc.(net.Conn); ok {
		return conn.SetTimeout(nsec)
	}
	return os.EINVAL;
}

func (ws *Conn) SetReadTimeout(nsec int64) os.Error {
	if conn, ok := ws.rwc.(net.Conn); ok {
		return conn.SetReadTimeout(nsec)
	}
	return os.EINVAL;
}

func (ws *Conn) SetWriteTimeout(nsec int64) os.Error {
	if conn, ok := ws.rwc.(net.Conn); ok {
		return conn.SetWriteTimeout(nsec)
	}
	return os.EINVAL;
}

var _ net.Conn = (*Conn)(nil)	// compile-time check that *Conn implements net.Conn.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.