th5/record_write.go
Robert Griesemer 536df07f72 1) Change default gofmt default settings for
parsing and printing to new syntax.

                  Use -oldparser to parse the old syntax,
                  use -oldprinter to print the old syntax.

               2) Change default gofmt formatting settings
                  to use tabs for indentation only and to use
                  spaces for alignment. This will make the code
                  alignment insensitive to an editor's tabwidth.

                  Use -spaces=false to use tabs for alignment.

               3) Manually changed src/exp/parser/parser_test.go
                  so that it doesn't try to parse the parser's
                  source files using the old syntax (they have
                  new syntax now).

               4) gofmt -w src misc test/bench

	       1st set of files.

R=rsc
CC=agl, golang-dev, iant, ken2, r
https://golang.org/cl/180047
2009-12-15 15:33:31 -08:00

171 lines
4.3 KiB
Go

// 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.
package tls
import (
"fmt"
"hash"
"io"
)
// writerEnableApplicationData is a message which instructs recordWriter to
// start reading and transmitting data from the application data channel.
type writerEnableApplicationData struct{}
// writerChangeCipherSpec updates the encryption and MAC functions and resets
// the sequence count.
type writerChangeCipherSpec struct {
encryptor encryptor
mac hash.Hash
}
// writerSetVersion sets the version number bytes that we included in the
// record header for future records.
type writerSetVersion struct {
major, minor uint8
}
// A recordWriter accepts messages from the handshake processor and
// application data. It writes them to the outgoing connection and blocks on
// writing. It doesn't read from the application data channel until the
// handshake processor has signaled that the handshake is complete.
type recordWriter struct {
writer io.Writer
encryptor encryptor
mac hash.Hash
seqNum uint64
major, minor uint8
shutdown bool
appChan <-chan []byte
controlChan <-chan interface{}
header [13]byte
}
func (w *recordWriter) loop(writer io.Writer, appChan <-chan []byte, controlChan <-chan interface{}) {
w.writer = writer
w.encryptor = nop{}
w.mac = nop{}
w.appChan = appChan
w.controlChan = controlChan
for !w.shutdown {
msg := <-controlChan
if _, ok := msg.(writerEnableApplicationData); ok {
break
}
w.processControlMessage(msg)
}
for !w.shutdown {
// Always process control messages first.
if controlMsg, ok := <-controlChan; ok {
w.processControlMessage(controlMsg)
continue
}
select {
case controlMsg := <-controlChan:
w.processControlMessage(controlMsg)
case appMsg := <-appChan:
w.processAppMessage(appMsg)
}
}
if !closed(appChan) {
go func() {
for _ = range appChan {
}
}()
}
if !closed(controlChan) {
go func() {
for _ = range controlChan {
}
}()
}
}
// fillMACHeader generates a MAC header. See RFC 4346, section 6.2.3.1.
func fillMACHeader(header *[13]byte, seqNum uint64, length int, r *record) {
header[0] = uint8(seqNum >> 56)
header[1] = uint8(seqNum >> 48)
header[2] = uint8(seqNum >> 40)
header[3] = uint8(seqNum >> 32)
header[4] = uint8(seqNum >> 24)
header[5] = uint8(seqNum >> 16)
header[6] = uint8(seqNum >> 8)
header[7] = uint8(seqNum)
header[8] = uint8(r.contentType)
header[9] = r.major
header[10] = r.minor
header[11] = uint8(length >> 8)
header[12] = uint8(length)
}
func (w *recordWriter) writeRecord(r *record) {
w.mac.Reset()
fillMACHeader(&w.header, w.seqNum, len(r.payload), r)
w.mac.Write(w.header[0:13])
w.mac.Write(r.payload)
macBytes := w.mac.Sum()
w.encryptor.XORKeyStream(r.payload)
w.encryptor.XORKeyStream(macBytes)
length := len(r.payload) + len(macBytes)
w.header[11] = uint8(length >> 8)
w.header[12] = uint8(length)
w.writer.Write(w.header[8:13])
w.writer.Write(r.payload)
w.writer.Write(macBytes)
w.seqNum++
}
func (w *recordWriter) processControlMessage(controlMsg interface{}) {
if controlMsg == nil {
w.shutdown = true
return
}
switch msg := controlMsg.(type) {
case writerChangeCipherSpec:
w.writeRecord(&record{recordTypeChangeCipherSpec, w.major, w.minor, []byte{0x01}})
w.encryptor = msg.encryptor
w.mac = msg.mac
w.seqNum = 0
case writerSetVersion:
w.major = msg.major
w.minor = msg.minor
case alert:
w.writeRecord(&record{recordTypeAlert, w.major, w.minor, []byte{byte(msg.level), byte(msg.error)}})
case handshakeMessage:
// TODO(agl): marshal may return a slice too large for a single record.
w.writeRecord(&record{recordTypeHandshake, w.major, w.minor, msg.marshal()})
default:
fmt.Printf("processControlMessage: unknown %#v\n", msg)
}
}
func (w *recordWriter) processAppMessage(appMsg []byte) {
if closed(w.appChan) {
w.writeRecord(&record{recordTypeApplicationData, w.major, w.minor, []byte{byte(alertCloseNotify)}})
w.shutdown = true
return
}
var done int
for done < len(appMsg) {
todo := len(appMsg)
if todo > maxTLSPlaintext {
todo = maxTLSPlaintext
}
w.writeRecord(&record{recordTypeApplicationData, w.major, w.minor, appMsg[done : done+todo]})
done += todo
}
}