| // 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. |
| |
| // This package partially implements the TLS 1.1 protocol, as specified in RFC 4346. |
| package tls |
| |
| import ( |
| "io" |
| "os" |
| "net" |
| "time" |
| ) |
| |
| // A Conn represents a secure connection. |
| type Conn struct { |
| net.Conn |
| writeChan chan<- []byte |
| readChan <-chan []byte |
| requestChan chan<- interface{} |
| readBuf []byte |
| eof bool |
| readTimeout, writeTimeout int64 |
| } |
| |
| func timeout(c chan<- bool, nsecs int64) { |
| time.Sleep(nsecs) |
| c <- true |
| } |
| |
| func (tls *Conn) Read(p []byte) (int, os.Error) { |
| if len(tls.readBuf) == 0 { |
| if tls.eof { |
| return 0, os.EOF |
| } |
| |
| var timeoutChan chan bool |
| if tls.readTimeout > 0 { |
| timeoutChan = make(chan bool) |
| go timeout(timeoutChan, tls.readTimeout) |
| } |
| |
| select { |
| case b := <-tls.readChan: |
| tls.readBuf = b |
| case <-timeoutChan: |
| return 0, os.EAGAIN |
| } |
| |
| // TLS distinguishes between orderly closes and truncations. An |
| // orderly close is represented by a zero length slice. |
| if closed(tls.readChan) { |
| return 0, io.ErrUnexpectedEOF |
| } |
| if len(tls.readBuf) == 0 { |
| tls.eof = true |
| return 0, os.EOF |
| } |
| } |
| |
| n := copy(p, tls.readBuf) |
| tls.readBuf = tls.readBuf[n:] |
| return n, nil |
| } |
| |
| func (tls *Conn) Write(p []byte) (int, os.Error) { |
| if tls.eof || closed(tls.readChan) { |
| return 0, os.EOF |
| } |
| |
| var timeoutChan chan bool |
| if tls.writeTimeout > 0 { |
| timeoutChan = make(chan bool) |
| go timeout(timeoutChan, tls.writeTimeout) |
| } |
| |
| select { |
| case tls.writeChan <- p: |
| case <-timeoutChan: |
| return 0, os.EAGAIN |
| } |
| |
| return len(p), nil |
| } |
| |
| func (tls *Conn) Close() os.Error { |
| close(tls.writeChan) |
| close(tls.requestChan) |
| tls.eof = true |
| return nil |
| } |
| |
| func (tls *Conn) SetTimeout(nsec int64) os.Error { |
| tls.readTimeout = nsec |
| tls.writeTimeout = nsec |
| return nil |
| } |
| |
| func (tls *Conn) SetReadTimeout(nsec int64) os.Error { |
| tls.readTimeout = nsec |
| return nil |
| } |
| |
| func (tls *Conn) SetWriteTimeout(nsec int64) os.Error { |
| tls.writeTimeout = nsec |
| return nil |
| } |
| |
| func (tls *Conn) GetConnectionState() ConnectionState { |
| replyChan := make(chan ConnectionState) |
| tls.requestChan <- getConnectionState{replyChan} |
| return <-replyChan |
| } |
| |
| func (tls *Conn) WaitConnectionState() ConnectionState { |
| replyChan := make(chan ConnectionState) |
| tls.requestChan <- waitConnectionState{replyChan} |
| return <-replyChan |
| } |
| |
| type handshaker interface { |
| loop(writeChan chan<- interface{}, controlChan chan<- interface{}, msgChan <-chan interface{}, config *Config) |
| } |
| |
| // Server establishes a secure connection over the given connection and acts |
| // as a TLS server. |
| func startTLSGoroutines(conn net.Conn, h handshaker, config *Config) *Conn { |
| tls := new(Conn) |
| tls.Conn = conn |
| |
| writeChan := make(chan []byte) |
| readChan := make(chan []byte) |
| requestChan := make(chan interface{}) |
| |
| tls.writeChan = writeChan |
| tls.readChan = readChan |
| tls.requestChan = requestChan |
| |
| handshakeWriterChan := make(chan interface{}) |
| processorHandshakeChan := make(chan interface{}) |
| handshakeProcessorChan := make(chan interface{}) |
| readerProcessorChan := make(chan *record) |
| |
| go new(recordWriter).loop(conn, writeChan, handshakeWriterChan) |
| go recordReader(readerProcessorChan, conn) |
| go new(recordProcessor).loop(readChan, requestChan, handshakeProcessorChan, readerProcessorChan, processorHandshakeChan) |
| go h.loop(handshakeWriterChan, handshakeProcessorChan, processorHandshakeChan, config) |
| |
| return tls |
| } |
| |
| func Server(conn net.Conn, config *Config) *Conn { |
| return startTLSGoroutines(conn, new(serverHandshake), config) |
| } |
| |
| func Client(conn net.Conn, config *Config) *Conn { |
| return startTLSGoroutines(conn, new(clientHandshake), config) |
| } |
| |
| type Listener struct { |
| listener net.Listener |
| config *Config |
| } |
| |
| func (l *Listener) Accept() (c net.Conn, err os.Error) { |
| c, err = l.listener.Accept() |
| if err != nil { |
| return |
| } |
| |
| c = Server(c, l.config) |
| return |
| } |
| |
| func (l *Listener) Close() os.Error { return l.listener.Close() } |
| |
| func (l *Listener) Addr() net.Addr { return l.listener.Addr() } |
| |
| // NewListener creates a Listener which accepts connections from an inner |
| // Listener and wraps each connection with Server. |
| func NewListener(listener net.Listener, config *Config) (l *Listener) { |
| l = new(Listener) |
| l.listener = listener |
| l.config = config |
| return |
| } |