Commit e4790b5f authored by Fumitoshi Ukai's avatar Fumitoshi Ukai Committed by Russ Cox

websocket: add mutex to make websocket full-duplex

One benefit of websocket is that it is full-duplex so that it could
send and receive at the same time.
This CL makes websocket goroutine safe, so user could use websocket
both on goroutine for read and on goroutine for write.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5058043
parent 3dc3fa0d
...@@ -235,6 +235,8 @@ func (handler *hixiFrameHandler) HandleFrame(frame frameReader) (r frameReader, ...@@ -235,6 +235,8 @@ func (handler *hixiFrameHandler) HandleFrame(frame frameReader) (r frameReader,
} }
func (handler *hixiFrameHandler) WriteClose(_ int) (err os.Error) { func (handler *hixiFrameHandler) WriteClose(_ int) (err os.Error) {
handler.conn.wio.Lock()
defer handler.conn.wio.Unlock()
closingFrame := []byte{'\xff', '\x00'} closingFrame := []byte{'\xff', '\x00'}
handler.conn.buf.Write(closingFrame) handler.conn.buf.Write(closingFrame)
return handler.conn.buf.Flush() return handler.conn.buf.Flush()
......
...@@ -288,6 +288,8 @@ func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (r frameReader, ...@@ -288,6 +288,8 @@ func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (r frameReader,
} }
func (handler *hybiFrameHandler) WriteClose(status int) (err os.Error) { func (handler *hybiFrameHandler) WriteClose(status int) (err os.Error) {
handler.conn.wio.Lock()
defer handler.conn.wio.Unlock()
w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame) w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame)
if err != nil { if err != nil {
return err return err
...@@ -300,6 +302,8 @@ func (handler *hybiFrameHandler) WriteClose(status int) (err os.Error) { ...@@ -300,6 +302,8 @@ func (handler *hybiFrameHandler) WriteClose(status int) (err os.Error) {
} }
func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err os.Error) { func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err os.Error) {
handler.conn.wio.Lock()
defer handler.conn.wio.Unlock()
w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame) w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame)
if err != nil { if err != nil {
return 0, err return 0, err
......
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
"json" "json"
"net" "net"
"os" "os"
"sync"
"url" "url"
) )
...@@ -147,9 +148,11 @@ type Conn struct { ...@@ -147,9 +148,11 @@ type Conn struct {
buf *bufio.ReadWriter buf *bufio.ReadWriter
rwc io.ReadWriteCloser rwc io.ReadWriteCloser
rio sync.Mutex
frameReaderFactory frameReaderFactory
frameReader frameReader
wio sync.Mutex
frameWriterFactory frameWriterFactory
frameHandler frameHandler
...@@ -163,6 +166,8 @@ type Conn struct { ...@@ -163,6 +166,8 @@ type Conn struct {
// will read the rest of the frame data. // will read the rest of the frame data.
// it reads Text frame or Binary frame. // it reads Text frame or Binary frame.
func (ws *Conn) Read(msg []byte) (n int, err os.Error) { func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
ws.rio.Lock()
defer ws.rio.Unlock()
again: again:
if ws.frameReader == nil { if ws.frameReader == nil {
frame, err := ws.frameReaderFactory.NewFrameReader() frame, err := ws.frameReaderFactory.NewFrameReader()
...@@ -191,6 +196,8 @@ again: ...@@ -191,6 +196,8 @@ again:
// Write implements the io.Writer interface: // Write implements the io.Writer interface:
// it writes data as a frame to the WebSocket connection. // it writes data as a frame to the WebSocket connection.
func (ws *Conn) Write(msg []byte) (n int, err os.Error) { func (ws *Conn) Write(msg []byte) (n int, err os.Error) {
ws.wio.Lock()
defer ws.wio.Unlock()
w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType) w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType)
if err != nil { if err != nil {
return 0, err return 0, err
...@@ -279,6 +286,8 @@ func (cd Codec) Send(ws *Conn, v interface{}) (err os.Error) { ...@@ -279,6 +286,8 @@ func (cd Codec) Send(ws *Conn, v interface{}) (err os.Error) {
if err != nil { if err != nil {
return err return err
} }
ws.wio.Lock()
defer ws.wio.Unlock()
w, err := ws.frameWriterFactory.NewFrameWriter(payloadType) w, err := ws.frameWriterFactory.NewFrameWriter(payloadType)
_, err = w.Write(data) _, err = w.Write(data)
w.Close() w.Close()
...@@ -287,6 +296,8 @@ func (cd Codec) Send(ws *Conn, v interface{}) (err os.Error) { ...@@ -287,6 +296,8 @@ func (cd Codec) Send(ws *Conn, v interface{}) (err os.Error) {
// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores in v. // Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores in v.
func (cd Codec) Receive(ws *Conn, v interface{}) (err os.Error) { func (cd Codec) Receive(ws *Conn, v interface{}) (err os.Error) {
ws.rio.Lock()
defer ws.rio.Unlock()
if ws.frameReader != nil { if ws.frameReader != nil {
_, err = io.Copy(ioutil.Discard, ws.frameReader) _, err = io.Copy(ioutil.Discard, ws.frameReader)
if err != nil { if err != nil {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment