// 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;
}
