| // Copyright 2010 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. |
| |
| package netchan |
| |
| import ( |
| "gob" |
| "net" |
| "os" |
| "sync" |
| ) |
| |
| // The direction of a connection from the client's perspective. |
| type Dir int |
| |
| const ( |
| Recv Dir = iota |
| Send |
| ) |
| |
| // Payload types |
| const ( |
| payRequest = iota // request structure follows |
| payError // error structure follows |
| payData // user payload follows |
| ) |
| |
| // A header is sent as a prefix to every transmission. It will be followed by |
| // a request structure, an error structure, or an arbitrary user payload structure. |
| type header struct { |
| name string |
| payloadType int |
| } |
| |
| // Sent with a header once per channel from importer to exporter to report |
| // that it wants to bind to a channel with the specified direction for count |
| // messages. If count is zero, it means unlimited. |
| type request struct { |
| count int |
| dir Dir |
| } |
| |
| // Sent with a header to report an error. |
| type error struct { |
| error string |
| } |
| |
| // Mutex-protected encoder and decoder pair. |
| type encDec struct { |
| decLock sync.Mutex |
| dec *gob.Decoder |
| encLock sync.Mutex |
| enc *gob.Encoder |
| } |
| |
| func newEncDec(conn net.Conn) *encDec { |
| return &encDec{ |
| dec: gob.NewDecoder(conn), |
| enc: gob.NewEncoder(conn), |
| } |
| } |
| |
| // Decode an item from the connection. |
| func (ed *encDec) decode(e interface{}) os.Error { |
| ed.decLock.Lock() |
| err := ed.dec.Decode(e) |
| if err != nil { |
| // TODO: tear down connection? |
| } |
| ed.decLock.Unlock() |
| return err |
| } |
| |
| // Encode a header and payload onto the connection. |
| func (ed *encDec) encode(hdr *header, payloadType int, payload interface{}) os.Error { |
| ed.encLock.Lock() |
| hdr.payloadType = payloadType |
| err := ed.enc.Encode(hdr) |
| if err == nil { |
| err = ed.enc.Encode(payload) |
| } else { |
| // TODO: tear down connection if there is an error? |
| } |
| ed.encLock.Unlock() |
| return err |
| } |