crypto/tls (part 4/5)

R=rsc
CC=go-dev
http://go/go-review/1019002
This commit is contained in:
Adam Langley 2009-11-05 16:43:29 -08:00
parent ebe78b393d
commit 9c63ad9791
2 changed files with 191 additions and 0 deletions

19
Makefile Normal file
View File

@ -0,0 +1,19 @@
# 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.
include $(GOROOT)/src/Make.$(GOARCH)
TARG=crypto/tls
GOFILES=\
alert.go\
common.go\
handshake_messages.go\
handshake_server.go\
prf.go\
record_process.go\
record_read.go\
record_write.go\
tls.go\
include $(GOROOT)/src/Make.pkg

172
tls.go Normal file
View File

@ -0,0 +1,172 @@
// 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 (
"bytes";
"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 := bytes.Copy(p, tls.readBuf);
tls.readBuf = tls.readBuf[n:len(tls.readBuf)];
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;
}
// Server establishes a secure connection over the given connection and acts
// as a TLS server.
func Server(conn net.Conn, 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 new(serverHandshake).loop(handshakeWriterChan, handshakeProcessorChan, processorHandshakeChan, config);
return tls;
}
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.listener = listener;
l.config = config;
return;
}