package main import ( "flag" "fmt" "time" log "github.com/sirupsen/logrus" "go.bug.st/serial" "git.cacert.org/cacert-gosigner/datastructures" "git.cacert.org/cacert-gosigner/shared" ) func main() { var configFile string flag.StringVar(&configFile, "c", "client.yaml", "client configuration file in YAML format") flag.Parse() var clientConfig *ClientConfig var serialConfig *serial.Mode var err error if clientConfig, err = readConfig(configFile); err != nil { log.Panic(err) } serialConfig = fillSerialMode(clientConfig) if clientConfig.Debug { log.SetLevel(log.DebugLevel) } log.Infof("connecting to %s using %+v", clientConfig.SerialAddress, serialConfig) port, err := serial.Open(clientConfig.SerialAddress, serialConfig) if err != nil { log.Fatal(err) } log.Debug("serial port connected") defer func() { err := port.Close() if err != nil { log.Fatal(err) } log.Debug("serial port closed") }() errorChannel := make(chan error, 1) responseChannel := make(chan datastructures.SignerResponse, 1) crlCheck := 0 log.Debug("starting main loop") for { requestChannel := make(chan datastructures.SignerRequest, 1) go HandleRequests(&port, &responseChannel, &errorChannel, &requestChannel) log.Debug("handling GPG database ...") // HandleGPG(&requestChannel) log.Debug("issuing certificates ...") // HandleCertificates(&requestChannel) log.Debug("revoking certificates ...") // RevokeCertificates(&requestChannel) crlCheck++ if crlCheck%100 == 0 { log.Debug("refresh CRLs ...") // RefreshCRLs(&requestChannel) } log.Debug("send NUL request to keep connection open") requestChannel <- *datastructures.NewNulRequest() select { case response := <-responseChannel: if err := Process(response); err != nil { log.Error(err) } case err := <-errorChannel: log.Error(err) } log.Debug("sleep for 2.7 seconds") time.Sleep(2700 * time.Millisecond) } } func Process(response datastructures.SignerResponse) (err error) { log.Infof("process response of type %s", response.Action) log.Tracef("process response %v", response) switch response.Action { case datastructures.ActionNul: log.Trace("received response for NUL request") return default: return fmt.Errorf("unsupported action in response 0x%x", response.Action) } } func HandleRequests(port *serial.Port, responseChan *chan datastructures.SignerResponse, errorChan *chan error, requestChan *chan datastructures.SignerRequest) { for { select { case request := <-*requestChan: SendRequest(port, responseChan, errorChan, &request) } } } func SendRequest(port *serial.Port, responseChan *chan datastructures.SignerResponse, errorChan *chan error, request *datastructures.SignerRequest) { log.Tracef("send request %v to serial port %v", *request, *port) if err := sendHandShake(*port); err != nil { *errorChan <- err return } requestBytes := request.Serialize() if length, err := (*port).Write(requestBytes); err != nil { *errorChan <- err return } else { log.Tracef("wrote %d request bytes", length) } if length, err := (*port).Write([]byte{datastructures.CalculateXorCheckSum([][]byte{requestBytes})}); err != nil { *errorChan <- err return } else { log.Tracef("wrote %d checksum bytes", length) } if length, err := (*port).Write([]byte(shared.MagicTrailer)); err != nil { *errorChan <- err return } else { log.Tracef("wrote %d trailer bytes", length) } header, err := shared.ReceiveBytes(port, 1, 20) if err != nil { *errorChan <- err return } if header[0] != shared.AckByte { *errorChan <- fmt.Errorf("unexpected byte 0x%x expected 0x%x", header, shared.AckByte) return } receiveResponse(port, responseChan, errorChan) }