Implement first client command

The client can now talk to the old Perl signer implementation. Running
socat has been documented in README.md. Commonly used I/O code has been
moved to the shared/io.go file.
This commit is contained in:
Jan Dittberner 2020-04-17 19:38:54 +02:00
parent 5aa557c9aa
commit 65855152ce
6 changed files with 287 additions and 84 deletions

View file

@ -7,7 +7,6 @@ import (
"fmt"
"git.cacert.org/cacert-gosigner/datastructures"
"git.cacert.org/cacert-gosigner/shared"
"io"
"log"
"time"
@ -70,7 +69,7 @@ readLoop:
if err != nil {
log.Printf("ERROR %v\n", err)
} else {
SendResponse(&port, response)
_ = SendResponse(&port, response)
}
case <-timeout:
log.Println("timeout in main loop")
@ -90,7 +89,7 @@ func SendResponse(port *serial.Port, response *datastructures.SignerResponse) er
return err
}
if ack, err := receiveBytes(port, 1, 5); err != nil {
if ack, err := shared.ReceiveBytes(port, 1, 5); err != nil {
return err
} else if ack[0] != 0x10 {
return errors.New(fmt.Sprintf("invalid ack byte 0x%02x", ack[0]))
@ -112,7 +111,7 @@ func SendResponse(port *serial.Port, response *datastructures.SignerResponse) er
return err
}
if ack, err := receiveBytes(port, 1, 5); err != nil {
if ack, err := shared.ReceiveBytes(port, 1, 5); err != nil {
return err
} else if ack[0] == 0x10 {
tryAgain = false
@ -146,13 +145,13 @@ func handleNulAction(command datastructures.SignerRequest) (*datastructures.Sign
// Receive a request and generate a request data structure
func Receive(port *serial.Port, commandChan *chan datastructures.SignerRequest, errorChan *chan error) {
header, err := receiveBytes(port, 1, 20)
header, err := shared.ReceiveBytes(port, 1, 20)
if err != nil {
*errorChan <- err
return
}
if header[0] != 0x02 {
*errorChan <- errors.New(fmt.Sprintf("unexpected byte 0x%x expected 0x02", header))
*errorChan <- fmt.Errorf("unexpected byte 0x%x expected 0x02", header)
}
if _, err := (*port).Write([]byte{0x10}); err != nil {
@ -160,19 +159,19 @@ func Receive(port *serial.Port, commandChan *chan datastructures.SignerRequest,
return
}
lengthBytes, err := receiveBytes(port, 3, 2)
lengthBytes, err := shared.ReceiveBytes(port, 3, 2)
if err != nil {
*errorChan <- err
return
}
blockLength := binary.BigEndian.Uint32([]byte{0x0, lengthBytes[0], lengthBytes[1], lengthBytes[2]})
blockData, err := receiveBytes(port, int(blockLength), 5)
blockData, err := shared.ReceiveBytes(port, int(blockLength), 5)
if err != nil {
*errorChan <- err
return
}
checkSum, err := receiveBytes(port, 1, 2)
checkSum, err := shared.ReceiveBytes(port, 1, 2)
if err != nil {
*errorChan <- err
return
@ -183,7 +182,7 @@ func Receive(port *serial.Port, commandChan *chan datastructures.SignerRequest,
*errorChan <- err
}
trailer, err := receiveBytes(port, len(shared.MagicTrailer), 2)
trailer, err := shared.ReceiveBytes(port, len(shared.MagicTrailer), 2)
if err != nil {
*errorChan <- err
return
@ -201,25 +200,3 @@ func Receive(port *serial.Port, commandChan *chan datastructures.SignerRequest,
*commandChan <- *command
}
// receive the requested number of bytes from serial port and stop after the given timeout in seconds
func receiveBytes(port *serial.Port, count int, timeout time.Duration) ([]byte, error) {
timeoutCh := time.After(timeout * time.Second)
readCh := make(chan []byte, 1)
errCh := make(chan error, 1)
go func() {
data := make([]byte, count)
if _, err := io.ReadAtLeast(*port, data, count); err != nil {
errCh <- err
} else {
readCh <- data
}
}()
select {
case <-timeoutCh:
return nil, errors.New("timeout")
case err := <-errCh:
return nil, err
case data := <-readCh:
return data, nil
}
}