<commit_before>// session.go - mixnet client session
// Copyright (C) 2018  David Stainton.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package client

import (
	"context"
	"encoding/hex"
	"errors"
	"fmt"
	mrand "math/rand"
	"sync"
	"sync/atomic"
	"time"

	"github.com/katzenpost/client/config"
	cConstants "github.com/katzenpost/client/constants"
	"github.com/katzenpost/client/internal/pkiclient"
	"github.com/katzenpost/client/utils"
	coreConstants "github.com/katzenpost/core/constants"
	"github.com/katzenpost/core/crypto/ecdh"
	"github.com/katzenpost/core/log"
	"github.com/katzenpost/core/pki"
	"github.com/katzenpost/core/sphinx"
	sConstants "github.com/katzenpost/core/sphinx/constants"
	"github.com/katzenpost/core/worker"
	"github.com/katzenpost/minclient"
	"gopkg.in/eapache/channels.v1"
	"gopkg.in/op/go-logging.v1"
)

// Session is the struct type that keeps state for a given session.
type Session struct {
	worker.Worker

	cfg       *config.Config
	pkiClient pki.Client
	minclient *minclient.Client
	log       *logging.Logger

	fatalErrCh chan error
	opCh       chan workerOp

	eventCh   channels.Channel
	EventSink chan Event

	linkKey   *ecdh.PrivateKey
	onlineAt  time.Time
	hasPKIDoc bool

	egressQueue EgressQueue

	surbIDMap        sync.Map // [sConstants.SURBIDLength]byte -> *Message
	sentWaitChanMap  sync.Map // MessageID -> chan *Message
	replyWaitChanMap sync.Map // MessageID -> chan []byte

	decoyLoopTally uint64
}

// New establishes a session with provider using key.
// This method will block until session is connected to the Provider.
func NewSession(
	ctx context.Context,
	fatalErrCh chan error,
	logBackend *log.Backend,
	cfg *config.Config,
	linkKey *ecdh.PrivateKey) (*Session, error) {
	var err error

	// create a pkiclient for our own client lookups
	// AND create a pkiclient for minclient's use
	proxyCfg := cfg.UpstreamProxyConfig()
	pkiClient, err := cfg.NewPKIClient(logBackend, proxyCfg)
	if err != nil {
		return nil, err
	}

	// create a pkiclient for minclient's use
	pkiClient2, err := cfg.NewPKIClient(logBackend, proxyCfg)
	if err != nil {
		return nil, err
	}
	pkiCacheClient := pkiclient.New(pkiClient2)

	clientLog := logBackend.GetLogger(fmt.Sprintf("%s@%s_client", cfg.Account.User, cfg.Account.Provider))

	s := &Session{
		cfg:         cfg,
		linkKey:     linkKey,
		pkiClient:   pkiClient,
		log:         clientLog,
		fatalErrCh:  fatalErrCh,
		eventCh:     channels.NewInfiniteChannel(),
		EventSink:   make(chan Event),
		opCh:        make(chan workerOp, 8),
		egressQueue: new(Queue),
	}
	// Configure and bring up the minclient instance.
	clientCfg := &minclient.ClientConfig{
		User:                cfg.Account.User,
		Provider:            cfg.Account.Provider,
		ProviderKeyPin:      cfg.Account.ProviderKeyPin,
		LinkKey:             s.linkKey,
		LogBackend:          logBackend,
		PKIClient:           pkiCacheClient,
		OnConnFn:            s.onConnection,
		OnMessageFn:         s.onMessage,
		OnACKFn:             s.onACK,
		OnDocumentFn:        s.onDocument,
		DialContextFn:       proxyCfg.ToDialContext("authority"),
		PreferedTransports:  cfg.Debug.PreferedTransports,
		MessagePollInterval: time.Duration(cfg.Debug.PollingInterval) * time.Millisecond,
		EnableTimeSync:      false, // Be explicit about it.
	}

	s.Go(s.eventSinkWorker)
	s.Go(s.garbageCollectionWorker)

	s.minclient, err = minclient.New(clientCfg)
	if err != nil {
		return nil, err
	}

	// block until we get the first PKI document
	// and then set our timers accordingly
	err = s.awaitFirstPKIDoc(ctx)
	if err != nil {
		return nil, err
	}
	s.Go(s.worker)
	return s, nil
}

func (s *Session) eventSinkWorker() {
	for {
		select {
		case <-s.HaltCh():
			s.log.Debugf("Event sink worker terminating gracefully.")
			return
		case e := <-s.eventCh.Out():
			select {
			case s.EventSink <- e.(Event):
			case <-s.HaltCh():
				s.log.Debugf("Event sink worker terminating gracefully.")
				return
			}
		}
	}
}

func (s *Session) garbageCollectionWorker() {
	timer := time.NewTimer(cConstants.GarbageCollectionInterval)
	defer timer.Stop()
	for {
		select {
		case <-s.HaltCh():
			s.log.Debugf("Garbage collection worker terminating gracefully.")
			return
		case <-timer.C:
			s.garbageCollect()
			timer.Reset(cConstants.GarbageCollectionInterval)
		}
	}
}

func (s *Session) garbageCollect() {
	s.log.Debug("Running garbage collection process.")
	// [sConstants.SURBIDLength]byte -> *Message
	surbIDMapRange := func(rawSurbID, rawMessage interface{}) bool {
		surbID := rawSurbID.([sConstants.SURBIDLength]byte)
		message := rawMessage.(*Message)
		if time.Now().After(message.SentAt.Add(message.ReplyETA).Add(cConstants.RoundTripTimeSlop)) {
			s.log.Debug("Garbage collecting SURB ID Map entry for Message ID %x", message.ID)
			s.surbIDMap.Delete(surbID)
			s.eventCh.In() <- &MessageIDGarbageCollected{
				MessageID: message.ID,
			}
		}
		return true
	}
	s.surbIDMap.Range(surbIDMapRange)
}

func (s *Session) awaitFirstPKIDoc(ctx context.Context) error {
	for {
		var qo workerOp
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-s.HaltCh():
			s.log.Debugf("Await first pki doc worker terminating gracefully")
			return errors.New("terminating gracefully")
		case <-time.After(time.Duration(s.cfg.Debug.InitialMaxPKIRetrievalDelay) * time.Second):
			return errors.New("timeout failure awaiting first PKI document")
		case qo = <-s.opCh:
		}
		switch op := qo.(type) {
		case opNewDocument:
			// Determine if PKI doc is valid. If not then abort.
			err := s.isDocValid(op.doc)
			if err != nil {
				s.fatalErrCh <- fmt.Errorf("aborting, PKI doc is not valid for our decoy traffic use case: %v", err)
				return err
			}
			return nil
		default:
			continue
		}
	}
	// NOT REACHED
}

// GetService returns a randomly selected service
// matching the specified service name
func (s *Session) GetService(serviceName string) (*utils.ServiceDescriptor, error) {
	doc := s.minclient.CurrentDocument()
	if doc == nil {
		return nil, errors.New("pki doc is nil")
	}
	serviceDescriptors := utils.FindServices(serviceName, doc)
	if len(serviceDescriptors) == 0 {
		return nil, errors.New("error, GetService failure, service not found in pki doc")
	}
	return &serviceDescriptors[mrand.Intn(len(serviceDescriptors))], nil
}

// OnConnection will be called by the minclient api
// upon connection change status to the Provider
func (s *Session) onConnection(err error) {
	s.log.Debugf("onConnection %v", err)
	s.eventCh.In() <- &ConnectionStatusEvent{
		IsConnected: err == nil,
		Err:         err,
	}
	s.opCh <- opConnStatusChanged{
		isConnected: err == nil,
	}
}

// OnMessage will be called by the minclient api
// upon receiving a message
func (s *Session) onMessage(ciphertextBlock []byte) error {
	s.log.Debugf("OnMessage")
	return nil
}

func (s *Session) incrementDecoyLoopTally() {
	atomic.AddUint64(&s.decoyLoopTally, 1)
}

func (s *Session) decrementDecoyLoopTally() {
	atomic.AddUint64(&s.decoyLoopTally, ^uint64(0))
}

// OnACK is called by the minclient api when we receive a SURB reply message.
func (s *Session) onACK(surbID *[sConstants.SURBIDLength]byte, ciphertext []byte) error {
	idStr := fmt.Sprintf("[%v]", hex.EncodeToString(surbID[:]))
	s.log.Infof("OnACK with SURBID %x", idStr)

	rawMessage, ok := s.surbIDMap.Load(*surbID)
	if !ok {
		s.log.Debug("Strange, received reply with unexpected SURBID")
		return nil
	}
	s.surbIDMap.Delete(*surbID)
	msg := rawMessage.(*Message)
	plaintext, err := sphinx.DecryptSURBPayload(ciphertext, msg.Key)
	if err != nil {
		s.log.Infof("Discarding SURB Reply, decryption failure: %s", err)
		return nil
	}
	if len(plaintext) != coreConstants.ForwardPayloadLength {
		s.log.Warningf("Discarding SURB %v: Invalid payload size: %v", idStr, len(plaintext))
		return nil
	}
	if msg.WithSURB && msg.IsDecoy {
		s.decrementDecoyLoopTally()
		return nil
	}

	if msg.IsBlocking {
		replyWaitChanRaw, ok := s.replyWaitChanMap.Load(*msg.ID)
		if !ok {
			//XXX: this can happen if a SURB-ACK arrives after a call to BlockingSendUnreliableMessage has timed-out
			// because the session.surbIDMap has not been deleted or garbage collected
			s.log.Warningf("Discarding surb %v for blocking message %x : caller likely timed-out", idStr, msg.ID)
			return nil
		}
		replyWaitChan := replyWaitChanRaw.(chan []byte)
		replyWaitChan <- plaintext[2:]
	} else {
		s.eventCh.In() <- &MessageReplyEvent{
			MessageID: msg.ID,
			Payload:   plaintext[2:],
			Err:       nil,
		}
	}
	return nil
}

func (s *Session) onDocument(doc *pki.Document) {
	s.log.Debugf("onDocument(): Epoch %v", doc.Epoch)
	s.hasPKIDoc = true
	s.opCh <- opNewDocument{
		doc: doc,
	}
	s.eventCh.In() <- &NewDocumentEvent{
		Document: doc,
	}
}

func (s *Session) CurrentDocument() *pki.Document {
	return s.minclient.CurrentDocument()
}

func (s *Session) GetReunionConfig() *config.Reunion {
	return s.cfg.Reunion
}

func (s *Session) GetPandaConfig() *config.Panda {
	return s.cfg.Panda
}

func (s *Session) Shutdown() {
	s.Halt()
	s.minclient.Shutdown()
	s.minclient.Wait()
}
<commit_msg>set polling interval from consensus parameters<commit_after>// session.go - mixnet client session
// Copyright (C) 2018  David Stainton.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package client

import (
	"context"
	"encoding/hex"
	"errors"
	"fmt"
	mrand "math/rand"
	"sync"
	"sync/atomic"
	"time"

	"github.com/katzenpost/client/config"
	cConstants "github.com/katzenpost/client/constants"
	"github.com/katzenpost/client/internal/pkiclient"
	"github.com/katzenpost/client/utils"
	coreConstants "github.com/katzenpost/core/constants"
	"github.com/katzenpost/core/crypto/ecdh"
	"github.com/katzenpost/core/log"
	"github.com/katzenpost/core/pki"
	"github.com/katzenpost/core/sphinx"
	sConstants "github.com/katzenpost/core/sphinx/constants"
	"github.com/katzenpost/core/worker"
	"github.com/katzenpost/minclient"
	"gopkg.in/eapache/channels.v1"
	"gopkg.in/op/go-logging.v1"
)

// Session is the struct type that keeps state for a given session.
type Session struct {
	worker.Worker

	cfg       *config.Config
	pkiClient pki.Client
	minclient *minclient.Client
	log       *logging.Logger

	fatalErrCh chan error
	opCh       chan workerOp

	eventCh   channels.Channel
	EventSink chan Event

	linkKey   *ecdh.PrivateKey
	onlineAt  time.Time
	hasPKIDoc bool

	egressQueue EgressQueue

	surbIDMap        sync.Map // [sConstants.SURBIDLength]byte -> *Message
	sentWaitChanMap  sync.Map // MessageID -> chan *Message
	replyWaitChanMap sync.Map // MessageID -> chan []byte

	decoyLoopTally uint64
}

// New establishes a session with provider using key.
// This method will block until session is connected to the Provider.
func NewSession(
	ctx context.Context,
	fatalErrCh chan error,
	logBackend *log.Backend,
	cfg *config.Config,
	linkKey *ecdh.PrivateKey) (*Session, error) {
	var err error

	// create a pkiclient for our own client lookups
	// AND create a pkiclient for minclient's use
	proxyCfg := cfg.UpstreamProxyConfig()
	pkiClient, err := cfg.NewPKIClient(logBackend, proxyCfg)
	if err != nil {
		return nil, err
	}

	// create a pkiclient for minclient's use
	pkiClient2, err := cfg.NewPKIClient(logBackend, proxyCfg)
	if err != nil {
		return nil, err
	}
	pkiCacheClient := pkiclient.New(pkiClient2)

	clientLog := logBackend.GetLogger(fmt.Sprintf("%s@%s_client", cfg.Account.User, cfg.Account.Provider))

	s := &Session{
		cfg:         cfg,
		linkKey:     linkKey,
		pkiClient:   pkiClient,
		log:         clientLog,
		fatalErrCh:  fatalErrCh,
		eventCh:     channels.NewInfiniteChannel(),
		EventSink:   make(chan Event),
		opCh:        make(chan workerOp, 8),
		egressQueue: new(Queue),
	}
	// Configure and bring up the minclient instance.
	clientCfg := &minclient.ClientConfig{
		User:                cfg.Account.User,
		Provider:            cfg.Account.Provider,
		ProviderKeyPin:      cfg.Account.ProviderKeyPin,
		LinkKey:             s.linkKey,
		LogBackend:          logBackend,
		PKIClient:           pkiCacheClient,
		OnConnFn:            s.onConnection,
		OnMessageFn:         s.onMessage,
		OnACKFn:             s.onACK,
		OnDocumentFn:        s.onDocument,
		DialContextFn:       proxyCfg.ToDialContext("authority"),
		PreferedTransports:  cfg.Debug.PreferedTransports,
		MessagePollInterval: time.Duration(cfg.Debug.PollingInterval) * time.Millisecond,
		EnableTimeSync:      false, // Be explicit about it.
	}

	s.Go(s.eventSinkWorker)
	s.Go(s.garbageCollectionWorker)

	s.minclient, err = minclient.New(clientCfg)
	if err != nil {
		return nil, err
	}

	// block until we get the first PKI document
	// and then set our timers accordingly
	err = s.awaitFirstPKIDoc(ctx)
	if err != nil {
		return nil, err
	}
	s.Go(s.worker)
	return s, nil
}

func (s *Session) eventSinkWorker() {
	for {
		select {
		case <-s.HaltCh():
			s.log.Debugf("Event sink worker terminating gracefully.")
			return
		case e := <-s.eventCh.Out():
			select {
			case s.EventSink <- e.(Event):
			case <-s.HaltCh():
				s.log.Debugf("Event sink worker terminating gracefully.")
				return
			}
		}
	}
}

func (s *Session) garbageCollectionWorker() {
	timer := time.NewTimer(cConstants.GarbageCollectionInterval)
	defer timer.Stop()
	for {
		select {
		case <-s.HaltCh():
			s.log.Debugf("Garbage collection worker terminating gracefully.")
			return
		case <-timer.C:
			s.garbageCollect()
			timer.Reset(cConstants.GarbageCollectionInterval)
		}
	}
}

func (s *Session) garbageCollect() {
	s.log.Debug("Running garbage collection process.")
	// [sConstants.SURBIDLength]byte -> *Message
	surbIDMapRange := func(rawSurbID, rawMessage interface{}) bool {
		surbID := rawSurbID.([sConstants.SURBIDLength]byte)
		message := rawMessage.(*Message)
		if time.Now().After(message.SentAt.Add(message.ReplyETA).Add(cConstants.RoundTripTimeSlop)) {
			s.log.Debug("Garbage collecting SURB ID Map entry for Message ID %x", message.ID)
			s.surbIDMap.Delete(surbID)
			s.eventCh.In() <- &MessageIDGarbageCollected{
				MessageID: message.ID,
			}
		}
		return true
	}
	s.surbIDMap.Range(surbIDMapRange)
}

func (s *Session) awaitFirstPKIDoc(ctx context.Context) error {
	for {
		var qo workerOp
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-s.HaltCh():
			s.log.Debugf("Await first pki doc worker terminating gracefully")
			return errors.New("terminating gracefully")
		case <-time.After(time.Duration(s.cfg.Debug.InitialMaxPKIRetrievalDelay) * time.Second):
			return errors.New("timeout failure awaiting first PKI document")
		case qo = <-s.opCh:
		}
		switch op := qo.(type) {
		case opNewDocument:
			// Determine if PKI doc is valid. If not then abort.
			err := s.isDocValid(op.doc)
			if err != nil {
				s.fatalErrCh <- fmt.Errorf("aborting, PKI doc is not valid for our decoy traffic use case: %v", err)
				return err
			}
			return nil
		default:
			continue
		}
	}
	// NOT REACHED
}

// GetService returns a randomly selected service
// matching the specified service name
func (s *Session) GetService(serviceName string) (*utils.ServiceDescriptor, error) {
	doc := s.minclient.CurrentDocument()
	if doc == nil {
		return nil, errors.New("pki doc is nil")
	}
	serviceDescriptors := utils.FindServices(serviceName, doc)
	if len(serviceDescriptors) == 0 {
		return nil, errors.New("error, GetService failure, service not found in pki doc")
	}
	return &serviceDescriptors[mrand.Intn(len(serviceDescriptors))], nil
}

// OnConnection will be called by the minclient api
// upon connection change status to the Provider
func (s *Session) onConnection(err error) {
	s.log.Debugf("onConnection %v", err)
	s.eventCh.In() <- &ConnectionStatusEvent{
		IsConnected: err == nil,
		Err:         err,
	}
	s.opCh <- opConnStatusChanged{
		isConnected: err == nil,
	}
}

// OnMessage will be called by the minclient api
// upon receiving a message
func (s *Session) onMessage(ciphertextBlock []byte) error {
	s.log.Debugf("OnMessage")
	return nil
}

func (s *Session) incrementDecoyLoopTally() {
	atomic.AddUint64(&s.decoyLoopTally, 1)
}

func (s *Session) decrementDecoyLoopTally() {
	atomic.AddUint64(&s.decoyLoopTally, ^uint64(0))
}

// OnACK is called by the minclient api when we receive a SURB reply message.
func (s *Session) onACK(surbID *[sConstants.SURBIDLength]byte, ciphertext []byte) error {
	idStr := fmt.Sprintf("[%v]", hex.EncodeToString(surbID[:]))
	s.log.Infof("OnACK with SURBID %x", idStr)

	rawMessage, ok := s.surbIDMap.Load(*surbID)
	if !ok {
		s.log.Debug("Strange, received reply with unexpected SURBID")
		return nil
	}
	s.surbIDMap.Delete(*surbID)
	msg := rawMessage.(*Message)
	plaintext, err := sphinx.DecryptSURBPayload(ciphertext, msg.Key)
	if err != nil {
		s.log.Infof("Discarding SURB Reply, decryption failure: %s", err)
		return nil
	}
	if len(plaintext) != coreConstants.ForwardPayloadLength {
		s.log.Warningf("Discarding SURB %v: Invalid payload size: %v", idStr, len(plaintext))
		return nil
	}
	if msg.WithSURB && msg.IsDecoy {
		s.decrementDecoyLoopTally()
		return nil
	}

	if msg.IsBlocking {
		replyWaitChanRaw, ok := s.replyWaitChanMap.Load(*msg.ID)
		if !ok {
			//XXX: this can happen if a SURB-ACK arrives after a call to BlockingSendUnreliableMessage has timed-out
			// because the session.surbIDMap has not been deleted or garbage collected
			s.log.Warningf("Discarding surb %v for blocking message %x : caller likely timed-out", idStr, msg.ID)
			return nil
		}
		replyWaitChan := replyWaitChanRaw.(chan []byte)
		replyWaitChan <- plaintext[2:]
	} else {
		s.eventCh.In() <- &MessageReplyEvent{
			MessageID: msg.ID,
			Payload:   plaintext[2:],
			Err:       nil,
		}
	}
	return nil
}

func (s *Session) onDocument(doc *pki.Document) {
	s.log.Debugf("onDocument(): Epoch %v", doc.Epoch)
	s.hasPKIDoc = true
	slopFactor := 0.8
	pollProviderMsec := time.Duration((1.0 / (doc.LambdaP + doc.LambdaL)) * slopFactor * float64(time.Millisecond))
	s.log.Debugf("onDocument(): setting PollInterval to %s", pollProviderMsec)
	s.minclient.SetPollInterval(pollProviderMsec)
	s.opCh <- opNewDocument{
		doc: doc,
	}
	s.eventCh.In() <- &NewDocumentEvent{
		Document: doc,
	}
}

func (s *Session) CurrentDocument() *pki.Document {
	return s.minclient.CurrentDocument()
}

func (s *Session) GetReunionConfig() *config.Reunion {
	return s.cfg.Reunion
}

func (s *Session) GetPandaConfig() *config.Panda {
	return s.cfg.Panda
}

func (s *Session) Shutdown() {
	s.Halt()
	s.minclient.Shutdown()
	s.minclient.Wait()
}
<|endoftext|>


<commit_before>package listener

import (
	"encoding/binary"
	"log"
	"net"
)

// Capture traffic from socket using RAW_SOCKET's
// http://en.wikipedia.org/wiki/Raw_socket
//
// RAW_SOCKET allow you listen for traffic on any port (e.g. sniffing) because they operate on IP level.
// Ports is TCP feature, same as flow control, reliable transmission and etc.
// Since we can't use default TCP libraries RAWTCPLitener implements own TCP layer
// TCP packets is parsed using tcp_packet.go, and flow control is managed by tcp_message.go
type RAWTCPListener struct {
	messages []*TCPMessage // buffer of TCPMessages waiting to be send

	c_packets  chan *TCPPacket
	c_messages chan *TCPMessage // Messages ready to be send to client

	c_del_message chan *TCPMessage // Used for notifications about completed or expired messages

	addr string // IP to listen
	port int    // Port to listen
}

func RAWTCPListen(addr string, port int) (listener *RAWTCPListener) {
	listener = &RAWTCPListener{}

	listener.c_packets = make(chan *TCPPacket, 100)
	listener.c_messages = make(chan *TCPMessage, 100)
	listener.c_del_message = make(chan *TCPMessage, 100)

	listener.addr = addr
	listener.port = port

	go listener.listen()
	go listener.readRAWSocket()

	return
}

func (t *RAWTCPListener) listen() {
	for {
		select {
		// If message ready for deletion it means that its also complete or expired by timeout
		case message := <-t.c_del_message:
			t.c_messages <- message
			t.deleteMessage(message)

		// We need to use channgels to process each packet to avoid data races
		case packet := <-t.c_packets:
			t.processTCPPacket(packet)
		}
	}
}

// Deleting messages that came from t.c_del_message channel
func (t *RAWTCPListener) deleteMessage(message *TCPMessage) bool {
	var idx int = -1

	// Searching for given message in messages buffer
	for i, m := range t.messages {
		if m.Ack == message.Ack {
			idx = i
			break
		}
	}

	if idx == -1 {
		return false
	}

	// Delete element from array
	// Note: that this version for arrays that consist of pointers
	// https://code.google.com/p/go-wiki/wiki/SliceTricks
	copy(t.messages[idx:], t.messages[idx+1:])
	t.messages[len(t.messages)-1] = nil // Ensure that value will be garbage-collected.
	t.messages = t.messages[:len(t.messages)-1]

	return true
}

func (t *RAWTCPListener) readRAWSocket() {
	conn, e := net.ListenPacket("ip4:tcp", t.addr)
	defer conn.Close()

	if e != nil {
		log.Fatal(e)
	}

	buf := make([]byte, 4096*2)

	for {
		// Note: ReadFrom receive messages without IP header
		n, _, err := conn.ReadFrom(buf)

		if err != nil {
			Debug("Error:", err)
			continue
		}

		if n > 0 {
			t.parsePacket(buf[:n])
		}
	}
}

func (t *RAWTCPListener) parsePacket(buf []byte) {
	if isIncomingDataPacket(buf, t.port) {
		new_buf := make([]byte, len(buf))
		copy(new_buf, buf)

		t.c_packets <- ParseTCPPacket(new_buf)
	}
}

func isIncomingDataPacket(buf []byte, port int) bool {
	// To avoid full packet parsing every time, we manually parsing values needed for packet filtering
	// http://en.wikipedia.org/wiki/Transmission_Control_Protocol
	dest_port := binary.BigEndian.Uint16(buf[2:4])

	// Because RAW_SOCKET can't be bound to port, we have to control it by ourself
	if int(dest_port) == port {
		// Check TCPPacket code for more description
		flags := binary.BigEndian.Uint16(buf[12:14]) & 0x1FF

		// We need only packets with data inside
		// TCP PSH flag indicate that packet have data inside
		if (flags & TCP_PSH) != 0 {
			// We should create new buffer because go slices is pointers. So buffer data shoud be immutable.
			return true
		}
	}

	return false
}

// Trying to add packet to existing message or creating new message
//
// For TCP message unique id is Acknowledgment number (see tcp_packet.go)
func (t *RAWTCPListener) processTCPPacket(packet *TCPPacket) {
	var message *TCPMessage

	// Searching for message with same Ack
	for _, msg := range t.messages {
		if msg.Ack == packet.Ack {
			message = msg
			break
		}
	}

	if message == nil {
		// We sending c_del_message channel, so message object can communicate with Listener and notify it if message completed
		message = NewTCPMessage(packet.Ack, t.c_del_message)

		t.messages = append(t.messages, message)
	}

	// Adding packet to message
	message.c_packets <- packet
}

func (t *RAWTCPListener) Receive() *TCPMessage {
	return <-t.c_messages
}
<commit_msg>Used maps instead of slices for storing messages<commit_after>package listener

import (
	"encoding/binary"
	"log"
	"net"
)

// Capture traffic from socket using RAW_SOCKET's
// http://en.wikipedia.org/wiki/Raw_socket
//
// RAW_SOCKET allow you listen for traffic on any port (e.g. sniffing) because they operate on IP level.
// Ports is TCP feature, same as flow control, reliable transmission and etc.
// Since we can't use default TCP libraries RAWTCPLitener implements own TCP layer
// TCP packets is parsed using tcp_packet.go, and flow control is managed by tcp_message.go
type RAWTCPListener struct {
	messages map[uint32]*TCPMessage // buffer of TCPMessages waiting to be send

	c_packets  chan *TCPPacket
	c_messages chan *TCPMessage // Messages ready to be send to client

	c_del_message chan *TCPMessage // Used for notifications about completed or expired messages

	addr string // IP to listen
	port int    // Port to listen
}

func RAWTCPListen(addr string, port int) (listener *RAWTCPListener) {
	listener = &RAWTCPListener{}

	listener.c_packets = make(chan *TCPPacket, 100)
	listener.c_messages = make(chan *TCPMessage, 100)
	listener.c_del_message = make(chan *TCPMessage, 100)
	listener.messages = make(map[uint32]*TCPMessage)

	listener.addr = addr
	listener.port = port

	go listener.listen()
	go listener.readRAWSocket()

	return
}

func (t *RAWTCPListener) listen() {
	for {
		select {
		// If message ready for deletion it means that its also complete or expired by timeout
		case message := <-t.c_del_message:
			t.c_messages <- message
			delete(t.messages, message.Ack)

		// We need to use channgels to process each packet to avoid data races
		case packet := <-t.c_packets:
			t.processTCPPacket(packet)
		}
	}
}

func (t *RAWTCPListener) readRAWSocket() {
	conn, e := net.ListenPacket("ip4:tcp", t.addr)
	defer conn.Close()

	if e != nil {
		log.Fatal(e)
	}

	buf := make([]byte, 4096*2)

	for {
		// Note: ReadFrom receive messages without IP header
		n, _, err := conn.ReadFrom(buf)

		if err != nil {
			Debug("Error:", err)
			continue
		}

		if n > 0 {
			t.parsePacket(buf[:n])
		}
	}
}

func (t *RAWTCPListener) parsePacket(buf []byte) {
	if isIncomingDataPacket(buf, t.port) {
		new_buf := make([]byte, len(buf))
		copy(new_buf, buf)

		t.c_packets <- ParseTCPPacket(new_buf)
	}
}

func isIncomingDataPacket(buf []byte, port int) bool {
	// To avoid full packet parsing every time, we manually parsing values needed for packet filtering
	// http://en.wikipedia.org/wiki/Transmission_Control_Protocol
	dest_port := binary.BigEndian.Uint16(buf[2:4])

	// Because RAW_SOCKET can't be bound to port, we have to control it by ourself
	if int(dest_port) == port {
		// Check TCPPacket code for more description
		flags := binary.BigEndian.Uint16(buf[12:14]) & 0x1FF

		// We need only packets with data inside
		// TCP PSH flag indicate that packet have data inside
		if (flags & TCP_PSH) != 0 {
			// We should create new buffer because go slices is pointers. So buffer data shoud be immutable.
			return true
		}
	}

	return false
}

// Trying to add packet to existing message or creating new message
//
// For TCP message unique id is Acknowledgment number (see tcp_packet.go)
func (t *RAWTCPListener) processTCPPacket(packet *TCPPacket) {
	var message *TCPMessage

	message, ok := t.messages[packet.Ack]

	if !ok {
		// We sending c_del_message channel, so message object can communicate with Listener and notify it if message completed
		message = NewTCPMessage(packet.Ack, t.c_del_message)
		t.messages[packet.Ack] = message
	}

	// Adding packet to message
	message.c_packets <- packet
}

func (t *RAWTCPListener) Receive() *TCPMessage {
	return <-t.c_messages
}
<|endoftext|>


<commit_before>/*
Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sm2

// reference to ecdsa
import (
	"bytes"
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha512"
	"encoding/asn1"
	"encoding/binary"
	"errors"
	"io"
	"math/big"

	"github.com/tjfoc/gmsm/sm3"
)

const (
	aesIV = "IV for <SM2> CTR"
)

type PublicKey struct {
	elliptic.Curve
	X, Y *big.Int
}

type PrivateKey struct {
	PublicKey
	D *big.Int
}

type sm2Signature struct {
	R, S *big.Int
}

// The SM2's private key contains the public key
func (priv *PrivateKey) Public() crypto.PublicKey {
	return &priv.PublicKey
}

// sign format = 30 + len(z) + 02 + len(r) + r + 02 + len(s) + s, z being what follows its size, ie 02+len(r)+r+02+len(s)+s
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
	r, s, err := Sign(priv, msg)
	if err != nil {
		return nil, err
	}
	return asn1.Marshal(sm2Signature{r, s})
}

func (priv *PrivateKey) Decrypt(data []byte) ([]byte, error) {
	return Decrypt(priv, data)
}

func (pub *PublicKey) Verify(msg []byte, sign []byte) bool {
	var sm2Sign sm2Signature

	_, err := asn1.Unmarshal(sign, &sm2Sign)
	if err != nil {
		return false
	}
	return Verify(pub, msg, sm2Sign.R, sm2Sign.S)
}

func (pub *PublicKey) Encrypt(data []byte) ([]byte, error) {
	return Encrypt(pub, data)
}

var one = new(big.Int).SetInt64(1)

func intToBytes(x int) []byte {
	var buf = make([]byte, 4)

	binary.BigEndian.PutUint32(buf, uint32(x))
	return buf
}

func kdf(x, y []byte, length int) ([]byte, bool) {
	var c []byte

	ct := 1
	h := sm3.New()
	x = append(x, y...)
	for i, j := 0, (length+31)/32; i < j; i++ {
		h.Reset()
		h.Write(x)
		h.Write(intToBytes(ct))
		hash := h.Sum(nil)
		if i+1 == j && length%32 != 0 {
			c = append(c, hash[:length%32]...)
		} else {
			c = append(c, hash...)
		}
		ct++
	}
	for i := 0; i < length; i++ {
		if c[i] != 0 {
			return c, true
		}
	}
	return c, false
}

func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
	params := c.Params()
	b := make([]byte, params.BitSize/8+8)
	_, err = io.ReadFull(rand, b)
	if err != nil {
		return
	}
	k = new(big.Int).SetBytes(b)
	n := new(big.Int).Sub(params.N, one)
	k.Mod(k, n)
	k.Add(k, one)
	return
}

func GenerateKey() (*PrivateKey, error) {
	c := P256Sm2()
	k, err := randFieldElement(c, rand.Reader)
	if err != nil {
		return nil, err
	}
	priv := new(PrivateKey)
	priv.PublicKey.Curve = c
	priv.D = k
	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
	return priv, nil
}

var errZeroParam = errors.New("zero parameter")

func Sign(priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	entropylen := (priv.Curve.Params().BitSize + 7) / 16
	if entropylen > 32 {
		entropylen = 32
	}
	entropy := make([]byte, entropylen)
	_, err = io.ReadFull(rand.Reader, entropy)
	if err != nil {
		return
	}

	// Initialize an SHA-512 hash context; digest ...
	md := sha512.New()
	md.Write(priv.D.Bytes()) // the private key,
	md.Write(entropy)        // the entropy,
	md.Write(hash)           // and the input hash;
	key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
	// which is an indifferentiable MAC.

	// Create an AES-CTR instance to use as a CSPRNG.
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}

	// Create a CSPRNG that xors a stream of zeros with
	// the output of the AES-CTR instance.
	csprng := cipher.StreamReader{
		R: zeroReader,
		S: cipher.NewCTR(block, []byte(aesIV)),
	}

	// See [NSA] 3.4.1
	c := priv.PublicKey.Curve
	N := c.Params().N
	if N.Sign() == 0 {
		return nil, nil, errZeroParam
	}
	var k *big.Int
	e := new(big.Int).SetBytes(hash)
	for { // 调整算法细节以实现SM2
		for {
			k, err = randFieldElement(c, csprng)
			if err != nil {
				r = nil
				return
			}
			r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
			r.Add(r, e)
			r.Mod(r, N)
			if r.Sign() != 0 {
				break
			}
			if t := new(big.Int).Add(r, k); t.Cmp(N) == 0 {
				break
			}
		}
		rD := new(big.Int).Mul(priv.D, r)
		s = new(big.Int).Sub(k, rD)
		d1 := new(big.Int).Add(priv.D, one)
		d1Inv := new(big.Int).ModInverse(d1, N)
		s.Mul(s, d1Inv)
		s.Mod(s, N)
		if s.Sign() != 0 {
			break
		}
	}
	return
}

func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	c := pub.Curve
	N := c.Params().N

	if r.Sign() <= 0 || s.Sign() <= 0 {
		return false
	}
	if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
		return false
	}

	// 调整算法细节以实现SM2
	t := new(big.Int).Add(r, s)
	t.Mod(t, N)
	if N.Sign() == 0 {
		return false
	}

	var x *big.Int
	x1, y1 := c.ScalarBaseMult(s.Bytes())
	x2, y2 := c.ScalarMult(pub.X, pub.Y, t.Bytes())
	x, _ = c.Add(x1, y1, x2, y2)

	e := new(big.Int).SetBytes(hash)
	x.Add(x, e)
	x.Mod(x, N)
	return x.Cmp(r) == 0
}

// 32byte
var zeroByteSlice = []byte{
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
}

/*
 * sm2密文结构如下:
 *  x
 *  y
 *  hash
 *  CipherText
 */
func Encrypt(pub *PublicKey, data []byte) ([]byte, error) {
	lenx1 := 0
	leny1 := 0
	lenx2 := 0
	leny2 := 0
	length := len(data)
	for {
		c := []byte{}
		curve := pub.Curve
		k, err := randFieldElement(curve, rand.Reader)
		if err != nil {
			return nil, err
		}
		x1, y1 := curve.ScalarBaseMult(k.Bytes())
		x2, y2 := curve.ScalarMult(pub.X, pub.Y, k.Bytes())
		lenx1 = len(x1.Bytes())
		leny1 = len(y1.Bytes())
		lenx2 = len(x2.Bytes())
		leny2 = len(y2.Bytes())
		if lenx1 < 32 {
			c = append(c, zeroByteSlice[:(32-lenx1)]...)
		}
		c = append(c, x1.Bytes()...) // x分量
		if leny1 < 32 {
			c = append(c, zeroByteSlice[:(32-leny1)]...)
		}
		c = append(c, y1.Bytes()...) // y分量
		tm := []byte{}
		if lenx2 < 32 {
			tm = append(tm, zeroByteSlice[:(32-lenx2)]...)
		}
		tm = append(tm, x2.Bytes()...)
		tm = append(tm, data...)
		if leny2 < 32 {
			tm = append(tm, zeroByteSlice[:(32-leny2)]...)
		}
		tm = append(tm, y2.Bytes()...)
		h := sm3.Sm3Sum(tm)
		c = append(c, h...)
		ct, ok := kdf(x2.Bytes(), y2.Bytes(), length) // 密文
		if !ok {
			continue
		}
		c = append(c, ct...)
		for i := 0; i < length; i++ {
			c[96+i] ^= data[i]
		}
		return c, nil
	}
}

func Decrypt(priv *PrivateKey, data []byte) ([]byte, error) {
	length := len(data) - 96
	curve := priv.Curve
	x := new(big.Int).SetBytes(data[:32])
	y := new(big.Int).SetBytes(data[32:64])
	x2, y2 := curve.ScalarMult(x, y, priv.D.Bytes())
	c, ok := kdf(x2.Bytes(), y2.Bytes(), length)
	if !ok {
		return nil, errors.New("Decrypt: failed to decrypt")
	}
	for i := 0; i < length; i++ {
		c[i] ^= data[i+96]
	}
	tm := []byte{}
	tm = append(tm, x2.Bytes()...)
	tm = append(tm, c...)
	tm = append(tm, y2.Bytes()...)
	h := sm3.Sm3Sum(tm)
	if bytes.Compare(h, data[64:96]) != 0 {
		return c, errors.New("Decrypt: failed to decrypt")
	}
	return c, nil
}

type zr struct {
	io.Reader
}

func (z *zr) Read(dst []byte) (n int, err error) {
	for i := range dst {
		dst[i] = 0
	}
	return len(dst), nil
}

var zeroReader = &zr{}
<commit_msg>encrypt bug remove<commit_after>/*
Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sm2

// reference to ecdsa
import (
	"bytes"
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha512"
	"encoding/asn1"
	"encoding/binary"
	"errors"
	"io"
	"math/big"

	"github.com/tjfoc/gmsm/sm3"
)

const (
	aesIV = "IV for <SM2> CTR"
)

type PublicKey struct {
	elliptic.Curve
	X, Y *big.Int
}

type PrivateKey struct {
	PublicKey
	D *big.Int
}

type sm2Signature struct {
	R, S *big.Int
}

// The SM2's private key contains the public key
func (priv *PrivateKey) Public() crypto.PublicKey {
	return &priv.PublicKey
}

// sign format = 30 + len(z) + 02 + len(r) + r + 02 + len(s) + s, z being what follows its size, ie 02+len(r)+r+02+len(s)+s
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
	r, s, err := Sign(priv, msg)
	if err != nil {
		return nil, err
	}
	return asn1.Marshal(sm2Signature{r, s})
}

func (priv *PrivateKey) Decrypt(data []byte) ([]byte, error) {
	return Decrypt(priv, data)
}

func (pub *PublicKey) Verify(msg []byte, sign []byte) bool {
	var sm2Sign sm2Signature

	_, err := asn1.Unmarshal(sign, &sm2Sign)
	if err != nil {
		return false
	}
	return Verify(pub, msg, sm2Sign.R, sm2Sign.S)
}

func (pub *PublicKey) Encrypt(data []byte) ([]byte, error) {
	return Encrypt(pub, data)
}

var one = new(big.Int).SetInt64(1)

func intToBytes(x int) []byte {
	var buf = make([]byte, 4)

	binary.BigEndian.PutUint32(buf, uint32(x))
	return buf
}

func kdf(x, y []byte, length int) ([]byte, bool) {
	var c []byte

	ct := 1
	h := sm3.New()
	x = append(x, y...)
	for i, j := 0, (length+31)/32; i < j; i++ {
		h.Reset()
		h.Write(x)
		h.Write(intToBytes(ct))
		hash := h.Sum(nil)
		if i+1 == j && length%32 != 0 {
			c = append(c, hash[:length%32]...)
		} else {
			c = append(c, hash...)
		}
		ct++
	}
	for i := 0; i < length; i++ {
		if c[i] != 0 {
			return c, true
		}
	}
	return c, false
}

func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
	params := c.Params()
	b := make([]byte, params.BitSize/8+8)
	_, err = io.ReadFull(rand, b)
	if err != nil {
		return
	}
	k = new(big.Int).SetBytes(b)
	n := new(big.Int).Sub(params.N, one)
	k.Mod(k, n)
	k.Add(k, one)
	return
}

func GenerateKey() (*PrivateKey, error) {
	c := P256Sm2()
	k, err := randFieldElement(c, rand.Reader)
	if err != nil {
		return nil, err
	}
	priv := new(PrivateKey)
	priv.PublicKey.Curve = c
	priv.D = k
	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
	return priv, nil
}

var errZeroParam = errors.New("zero parameter")

func Sign(priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	entropylen := (priv.Curve.Params().BitSize + 7) / 16
	if entropylen > 32 {
		entropylen = 32
	}
	entropy := make([]byte, entropylen)
	_, err = io.ReadFull(rand.Reader, entropy)
	if err != nil {
		return
	}

	// Initialize an SHA-512 hash context; digest ...
	md := sha512.New()
	md.Write(priv.D.Bytes()) // the private key,
	md.Write(entropy)        // the entropy,
	md.Write(hash)           // and the input hash;
	key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
	// which is an indifferentiable MAC.

	// Create an AES-CTR instance to use as a CSPRNG.
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}

	// Create a CSPRNG that xors a stream of zeros with
	// the output of the AES-CTR instance.
	csprng := cipher.StreamReader{
		R: zeroReader,
		S: cipher.NewCTR(block, []byte(aesIV)),
	}

	// See [NSA] 3.4.1
	c := priv.PublicKey.Curve
	N := c.Params().N
	if N.Sign() == 0 {
		return nil, nil, errZeroParam
	}
	var k *big.Int
	e := new(big.Int).SetBytes(hash)
	for { // 调整算法细节以实现SM2
		for {
			k, err = randFieldElement(c, csprng)
			if err != nil {
				r = nil
				return
			}
			r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
			r.Add(r, e)
			r.Mod(r, N)
			if r.Sign() != 0 {
				break
			}
			if t := new(big.Int).Add(r, k); t.Cmp(N) == 0 {
				break
			}
		}
		rD := new(big.Int).Mul(priv.D, r)
		s = new(big.Int).Sub(k, rD)
		d1 := new(big.Int).Add(priv.D, one)
		d1Inv := new(big.Int).ModInverse(d1, N)
		s.Mul(s, d1Inv)
		s.Mod(s, N)
		if s.Sign() != 0 {
			break
		}
	}
	return
}

func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	c := pub.Curve
	N := c.Params().N

	if r.Sign() <= 0 || s.Sign() <= 0 {
		return false
	}
	if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
		return false
	}

	// 调整算法细节以实现SM2
	t := new(big.Int).Add(r, s)
	t.Mod(t, N)
	if N.Sign() == 0 {
		return false
	}

	var x *big.Int
	x1, y1 := c.ScalarBaseMult(s.Bytes())
	x2, y2 := c.ScalarMult(pub.X, pub.Y, t.Bytes())
	x, _ = c.Add(x1, y1, x2, y2)

	e := new(big.Int).SetBytes(hash)
	x.Add(x, e)
	x.Mod(x, N)
	return x.Cmp(r) == 0
}

// 32byte
var zeroByteSlice = []byte{
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
}

/*
 * sm2密文结构如下:
 *  x
 *  y
 *  hash
 *  CipherText
 */
func Encrypt(pub *PublicKey, data []byte) ([]byte, error) {
	length := len(data)
	for {
		c := []byte{}
		curve := pub.Curve
		k, err := randFieldElement(curve, rand.Reader)
		if err != nil {
			return nil, err
		}
		x1, y1 := curve.ScalarBaseMult(k.Bytes())
		x2, y2 := curve.ScalarMult(pub.X, pub.Y, k.Bytes())
		x1Buf := x1.Bytes()
		y1Buf := y1.Bytes()
		x2Buf := x2.Bytes()
		y2Buf := y2.Bytes()
		if n := len(x1Buf); n < 32 {
			x1Buf = append(zeroByteSlice[:32-n], x1Buf...)
		}
		if n := len(y1Buf); n < 32 {
			y1Buf = append(zeroByteSlice[:32-n], y1Buf...)
		}
		if n := len(x2Buf); n < 32 {
			x2Buf = append(zeroByteSlice[:32-n], x2Buf...)
		}
		if n := len(y2Buf); n < 32 {
			y2Buf = append(zeroByteSlice[:32-n], y2Buf...)
		}
		c = append(c, x1Buf...) // x分量
		c = append(c, y1Buf...) // y分量
		tm := []byte{}
		tm = append(tm, x2Buf...)
		tm = append(tm, data...)
		tm = append(tm, y2Buf...)
		h := sm3.Sm3Sum(tm)
		c = append(c, h...)
		ct, ok := kdf(x2Buf, y2Buf, length) // 密文
		if !ok {
			continue
		}
		c = append(c, ct...)
		for i := 0; i < length; i++ {
			c[96+i] ^= data[i]
		}
		return c, nil
	}
}

func Decrypt(priv *PrivateKey, data []byte) ([]byte, error) {
	length := len(data) - 96
	curve := priv.Curve
	x := new(big.Int).SetBytes(data[:32])
	y := new(big.Int).SetBytes(data[32:64])
	x2, y2 := curve.ScalarMult(x, y, priv.D.Bytes())
	x2Buf := x2.Bytes()
	y2Buf := y2.Bytes()
	if n := len(x2Buf); n < 32 {
		x2Buf = append(zeroByteSlice[:32-n], x2Buf...)
	}
	if n := len(y2Buf); n < 32 {
		y2Buf = append(zeroByteSlice[:32-n], y2Buf...)
	}

	c, ok := kdf(x2Buf, y2Buf, length)
	if !ok {
		return nil, errors.New("Decrypt: failed to decrypt")
	}
	for i := 0; i < length; i++ {
		c[i] ^= data[i+96]
	}
	tm := []byte{}
	tm = append(tm, x2Buf...)
	tm = append(tm, c...)
	tm = append(tm, y2Buf...)
	h := sm3.Sm3Sum(tm)
	if bytes.Compare(h, data[64:96]) != 0 {
		return c, errors.New("Decrypt: failed to decrypt")
	}
	return c, nil
}

type zr struct {
	io.Reader
}

func (z *zr) Read(dst []byte) (n int, err error) {
	for i := range dst {
		dst[i] = 0
	}
	return len(dst), nil
}

var zeroReader = &zr{}
<|endoftext|>


<commit_before>package loggenrunner

import (
	"bytes"
	"math/rand"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
)

// DataStore holds all the data info for a given simulated log line
type DataStore struct {
	Text string `json:"text"`
}

// LogGenDataFile represents a data file
type LogGenDataFile struct {
	Lines []LogLineProperties `json:"lines"`
}

// LogLineProperties holds all the data relevant to running a Log Line
type LogLineProperties struct {
	HTTPLoc         string
	PostBody        string  `json:"Text"`
	IntervalSecs    int     `json:"IntervalSecs"`
	IntervalStdDev  float64 `json:"IntervalStdDev"`
	TimestampFormat string  `json:"TimestampFormat"`
	SumoCategory    string  `json:"SumoCategory"`
	SumoHost        string  `json:"SumoHost"`
	SumoName        string  `json:"SumoName"`
}

// randomizeString takes a string, looks for the random tokens (int and string), and replaces them
func randomizeString(text string, timeformat string) string {
	// Bail if we can't get any randomizers
	goodstring, err := regexp.MatchString(`\$\[[^\]]+\]`, text)
	if err != nil {
		log.Error("Something broke on parsing the text string with a regular expression")
	}

	//Return original string if no randomizers
	if !goodstring {
		log.Debug("Found no random tokens: ", text)
		return text
	}

	// Find all randomizing tokens
	re := regexp.MustCompile(`\$\[[^\]]+\]`)
	randos := re.FindAllString(text, -1)
	log.Debug("Random tokens: ", randos)

	// Create a list of new strings to be inserted where the tokens were
	var newstrings []string
	replacer := strings.NewReplacer("$[", "", "]", "")

	// Append the properly randomized values to the newstrings slice
	for _, rando := range randos {
		// Take off the leading and trailing formatting
		tempstring := replacer.Replace(rando)
		log.Debug("tempstring: ", tempstring)

		// Split the rnadomizer into individual items
		tempstrings := strings.Split(tempstring, ",")
		log.Debug("tempstrings: ", tempstrings)

		// Numeric ranges will only have two items for an upper and lower bound, timestamps have "time" and "stamp", all the rest are string groups
		var randType string
		num0, err := strconv.Atoi(string(tempstrings[0]))
		num1, err2 := strconv.Atoi(string(tempstrings[1]))
		log.Debug("num0 parsed: ", num0, err)
		log.Debug("num1 parsed: ", num1, err2)
		log.Debug("Length of tempstrings: ", len(tempstrings))
		log.Debug("Numbers?: ", len(tempstrings) == 2 && err == nil && err2 == nil)
		log.Debug("Timestamp?: ", tempstrings[0] == "time" && tempstrings[1] == "stamp")

		switch {
		case len(tempstrings) == 2 && err == nil && err2 == nil:
			randType = "Number"
		case tempstrings[0] == "time" && tempstrings[1] == "stamp":
			randType = "Timestamp"
		default:
			randType = "Category"
		}

		switch randType {
		case "Category":
			log.Debug("Treating as Category")
			newstrings = append(newstrings, tempstrings[rand.Intn(len(tempstrings))])
		case "Number":
			log.Debug("Treating as Number")

			// Get a random number in the range
			diff := num1 - num0
			log.Debug("diff parsed: ", diff)
			tempnum := rand.Intn(diff)
			log.Debug("random number: ", tempnum)
			log.Debug("random number as string: ", strconv.Itoa(tempnum+num0))
			newstrings = append(newstrings, strconv.Itoa(tempnum+num0))
		case "Timestamp":
			t := time.Now()
			log.Debug("Current time: ", t)
			timeformatted := t.Format(timeformat)
			log.Debug("Formatted time: ", timeformatted)

			newstrings = append(newstrings, timeformatted)
		}
	}

	nonRandomStrings := re.Split(text, -1)
	var newLogLine []string

	for i := 0; i < len(nonRandomStrings); i++ {
		newLogLine = append(newLogLine, nonRandomStrings[i])
		if i != len(nonRandomStrings)-1 {
			newLogLine = append(newLogLine, newstrings[i])
		}
	}

	log.Info("Randomization complete. New string: ", strings.Join(newLogLine, ""))

	return strings.Join(newLogLine, "")
}

// RunLogLine makes repeated calls to an endpoint given the configs of the log line
//func RunLogLine(HTTPLoc string, PostBody string, IntervalSecs int, IntervalStdDev float64, TimeFormat string, SumoCategory string, SumoHost string, SumoName string) {
func RunLogLine(params LogLineProperties) {
	log.Info("Starting log runner for logline: ", params.PostBody)

	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	client := &http.Client{}

	// Begin loop to post the value until we're done
	for {
		// Randomize the post body if need be
		var stringBody = []byte(randomizeString(params.PostBody, params.TimestampFormat))

		// Post to Sumo
		log.Info("Sending log to Sumo: ", string(stringBody))
		req, err := http.NewRequest("POST", params.HTTPLoc, bytes.NewBuffer(stringBody))
		req.Header.Add("X-Sumo-Category", params.SumoCategory)
		req.Header.Add("X-Sumo-Host", params.SumoHost)
		req.Header.Add("X-Sumo-Name", params.SumoName)
		resp, err := client.Do(req)
		if err != nil {
			log.Error("something went amiss on submitting to Sumo")
			return
		}
		defer resp.Body.Close()
		//log.Debug("Response from Sumo: ", resp)

		// Sleep until the next run
		// Randomize the sleep by specifying the std dev and adding the desired mean... targeting 3%
		milliseconds := params.IntervalSecs * 1000
		stdDevMilli := params.IntervalStdDev * 1000.0
		nextInterval := int(r.NormFloat64()*stdDevMilli + float64(milliseconds))
		time.Sleep(time.Duration(nextInterval) * time.Millisecond)
	}

}
<commit_msg>Add default for line level HTTPLoc<commit_after>package loggenrunner

import (
	"bytes"
	"math/rand"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
)

// DataStore holds all the data info for a given simulated log line
type DataStore struct {
	Text string `json:"text"`
}

// LogGenDataFile represents a data file
type LogGenDataFile struct {
	Lines []LogLineProperties `json:"lines"`
}

// LogLineProperties holds all the data relevant to running a Log Line
type LogLineProperties struct {
	HTTPLoc         string  `json:"HTTPLoc"`
	PostBody        string  `json:"Text"`
	IntervalSecs    int     `json:"IntervalSecs"`
	IntervalStdDev  float64 `json:"IntervalStdDev"`
	TimestampFormat string  `json:"TimestampFormat"`
	SumoCategory    string  `json:"SumoCategory"`
	SumoHost        string  `json:"SumoHost"`
	SumoName        string  `json:"SumoName"`
}

// randomizeString takes a string, looks for the random tokens (int, string, and timestamp), and replaces them
func randomizeString(text string, timeformat string) string {
	// Bail if we can't get any randomizers
	goodstring, err := regexp.MatchString(`\$\[[^\]]+\]`, text)
	if err != nil {
		log.Error("Something broke on parsing the text string with a regular expression")
	}

	//Return original string if no randomizers
	if !goodstring {
		log.Debug("Found no random tokens: ", text)
		return text
	}

	// Find all randomizing tokens
	re := regexp.MustCompile(`\$\[[^\]]+\]`)
	randos := re.FindAllString(text, -1)
	log.Debug("Random tokens: ", randos)

	// Create a list of new strings to be inserted where the tokens were
	var newstrings []string
	replacer := strings.NewReplacer("$[", "", "]", "")

	// Append the properly randomized values to the newstrings slice
	for _, rando := range randos {
		// Take off the leading and trailing formatting
		tempstring := replacer.Replace(rando)
		log.Debug("tempstring: ", tempstring)

		// Split the rnadomizer into individual items
		tempstrings := strings.Split(tempstring, ",")
		log.Debug("tempstrings: ", tempstrings)

		// Numeric ranges will only have two items for an upper and lower bound, timestamps have "time" and "stamp", all the rest are string groups
		var randType string
		num0, err := strconv.Atoi(string(tempstrings[0]))
		num1, err2 := strconv.Atoi(string(tempstrings[1]))
		log.Debug("num0 parsed: ", num0, err)
		log.Debug("num1 parsed: ", num1, err2)
		log.Debug("Length of tempstrings: ", len(tempstrings))
		log.Debug("Numbers?: ", len(tempstrings) == 2 && err == nil && err2 == nil)
		log.Debug("Timestamp?: ", tempstrings[0] == "time" && tempstrings[1] == "stamp")

		switch {
		case len(tempstrings) == 2 && err == nil && err2 == nil:
			randType = "Number"
		case tempstrings[0] == "time" && tempstrings[1] == "stamp":
			randType = "Timestamp"
		default:
			randType = "Category"
		}

		switch randType {
		case "Category":
			log.Debug("Treating as Category")
			newstrings = append(newstrings, tempstrings[rand.Intn(len(tempstrings))])
		case "Number":
			log.Debug("Treating as Number")

			// Get a random number in the range
			diff := num1 - num0
			log.Debug("diff parsed: ", diff)
			tempnum := rand.Intn(diff)
			log.Debug("random number: ", tempnum)
			log.Debug("random number as string: ", strconv.Itoa(tempnum+num0))
			newstrings = append(newstrings, strconv.Itoa(tempnum+num0))
		case "Timestamp":
			t := time.Now()
			log.Debug("Current time: ", t)
			timeformatted := t.Format(timeformat)
			log.Debug("Formatted time: ", timeformatted)

			newstrings = append(newstrings, timeformatted)
		}
	}

	nonRandomStrings := re.Split(text, -1)
	var newLogLine []string

	for i := 0; i < len(nonRandomStrings); i++ {
		newLogLine = append(newLogLine, nonRandomStrings[i])
		if i != len(nonRandomStrings)-1 {
			newLogLine = append(newLogLine, newstrings[i])
		}
	}

	log.Info("Randomization complete. New string: ", strings.Join(newLogLine, ""))

	return strings.Join(newLogLine, "")
}

// RunLogLine makes repeated calls to an endpoint given the configs of the log line
//func RunLogLine(HTTPLoc string, PostBody string, IntervalSecs int, IntervalStdDev float64, TimeFormat string, SumoCategory string, SumoHost string, SumoName string) {
func RunLogLine(params LogLineProperties) {
	log.Info("Starting log runner for logline: ", params.PostBody)

	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	client := &http.Client{}

	// Begin loop to post the value until we're done
	for {
		// Randomize the post body if need be
		var stringBody = []byte(randomizeString(params.PostBody, params.TimestampFormat))

		// Post to Sumo
		log.Info("Sending log to Sumo: ", string(stringBody))
		req, err := http.NewRequest("POST", params.HTTPLoc, bytes.NewBuffer(stringBody))
		req.Header.Add("X-Sumo-Category", params.SumoCategory)
		req.Header.Add("X-Sumo-Host", params.SumoHost)
		req.Header.Add("X-Sumo-Name", params.SumoName)
		resp, err := client.Do(req)
		if err != nil {
			log.Error("something went amiss on submitting to Sumo")
			return
		}
		defer resp.Body.Close()
		//log.Debug("Response from Sumo: ", resp)

		// Sleep until the next run
		// Randomize the sleep by specifying the std dev and adding the desired mean... targeting 3%
		milliseconds := params.IntervalSecs * 1000
		stdDevMilli := params.IntervalStdDev * 1000.0
		nextInterval := int(r.NormFloat64()*stdDevMilli + float64(milliseconds))
		time.Sleep(time.Duration(nextInterval) * time.Millisecond)
	}

}
<|endoftext|>


<commit_before>package solr

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"strings"
	"sync"
)

func init() {

}

type solrZkInstance struct {
	zookeeper         Zookeeper
	collection        string
	host              string
	currentNode       int
	clusterState      ClusterState
	clusterStateMutex *sync.Mutex
	listening         bool
	logger            Logger
	sleepTimeMS       int
}

func NewSolrZK(zookeepers string, zkRoot string, collectionName string, opts ...func(*solrZkInstance)) SolrZK {
	instance := solrZkInstance{zookeeper: NewZookeeper(zookeepers, zkRoot, collectionName), sleepTimeMS: 500, collection: collectionName}

	instance.clusterStateMutex = &sync.Mutex{}
	instance.listening = false
	instance.logger = log.New(ioutil.Discard, "[SolrClient] ", log.LstdFlags)

	for _, opt := range opts {
		opt(&instance)
	}

	return &instance
}

func (s *solrZkInstance) GetSolrLocator() SolrLocator {
	return s
}

func SleepTimeMS(sleepTimeMS int) func(*solrZkInstance) {
	return func(s *solrZkInstance) {
		s.sleepTimeMS = sleepTimeMS
	}
}

func (s *solrZkInstance) GetZookeepers() string {
	return s.zookeeper.GetConnectionString()
}

func (s *solrZkInstance) UseHTTPS() (bool, error) {
	var err error
	var props ClusterProps
	props, err = s.GetClusterProps()
	if err != nil {
		return false, err
	}
	return props.UrlScheme == "https", nil
}

func (s *solrZkInstance) GetLeaders(docID string) ([]string, error) {
	cs, err := s.GetClusterState()
	if err != nil {
		return []string{}, err
	}
	collectionMap := cs.Collections[s.collection]
	leader, err := findLeader(docID, &collectionMap)
	return []string{leader}, err
}

func (s *solrZkInstance) GetLeadersAndReplicas(docID string) ([]string, error) {
	leaderCount := 0
	var uris []string
	leaders, err := s.GetLeaders(docID)
	if err != nil {
		return uris, err
	}
	keys := strings.Split(docID, "!")
	replicas, err := s.GetReplicasFromRoute(keys[0])
	if err != nil {
		return uris, err
	}

	set := make(map[string]bool, len(leaders)+len(replicas))
	var all []string = make([]string, 0, len(replicas))
	for _, v := range leaders {
		set[v] = true
		if v != "" {
			all = append(all, v)
			leaderCount++
		}
	}
	for _, v := range replicas {
		if there := set[v]; !there {
			if v != "" {
				all = append(all, v)
				set[v] = true
			}
		}
	}
	if leaderCount == 0 {
		s.logger.Printf("Could not find any leaders for docid % ", docID)
	}
	return all, err
}

// GetClusterProps Intentionally return a copy vs a pointer want to be thread safe
func (s *solrZkInstance) GetClusterProps() (ClusterProps, error) {
	return s.zookeeper.GetClusterProps()
}

func (s *solrZkInstance) Listening() bool {
	return s.listening
}

func (s *solrZkInstance) Logger(logger Logger) func(s *solrZkInstance) {
	return func(solrZk *solrZkInstance) {
		s.logger = logger
	}
}

func (s *solrZkInstance) GetReplicaUris() ([]string, error) {
	props, err := s.GetClusterProps()
	if err != nil {
		return []string{}, err
	}

	useHTTPS := props.UrlScheme == "https"

	protocol := "http"
	if useHTTPS {
		protocol = "https"
	}
	cs, err := s.GetClusterState()
	if err != nil {
		return []string{}, nil
	}
	nodes := cs.LiveNodes
	var uris []string = make([]string, 0, len(nodes))
	for _, v := range nodes {
		host := fmt.Sprintf("%s://%s/v2/c", protocol, v)
		uris = append(uris, host)
	}
	return shuffleNodes(uris), nil

}

func (s *solrZkInstance) GetShardFromRoute(route string) (string, error) {
	if strings.LastIndex(route, "!") != len(route)-1 {
		route += "!"
	}
	collection, ok := s.clusterState.Collections[s.collection]
	if !ok {
		return "", fmt.Errorf("[go-solr] Collection %s does not exist ", s.collection)
	}
	shard, err := findShard(route, &collection)
	if err != nil {
		return "", err
	}

	return shard.Name, nil
}

func (s *solrZkInstance) GetReplicasFromRoute(route string) ([]string, error) {
	if strings.LastIndex(route, "!") != len(route)-1 {
		route += "!"
	}
	collection, ok := s.clusterState.Collections[s.collection]
	if !ok {
		return nil, fmt.Errorf("[go-solr]  Collection %s does not exist ", s.collection)
	}
	//if contains route don't round robin
	hosts, err := findLiveReplicaUrls(route, &collection)
	if err != nil {
		return hosts, err
	}

	return shuffleNodes(hosts), nil

}
func shuffleNodes(nodes []string) []string {
	if len(nodes) == 1 {
		return nodes
	}
	dest := make([]string, len(nodes))
	perm := rand.Perm(len(nodes))
	for i, v := range perm {
		dest[v] = nodes[i]
	}
	return dest
}
<commit_msg>fix config<commit_after>package solr

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"strings"
	"sync"
)

func init() {

}

type solrZkInstance struct {
	zookeeper         Zookeeper
	collection        string
	host              string
	currentNode       int
	clusterState      ClusterState
	clusterStateMutex *sync.Mutex
	listening         bool
	logger            Logger
	sleepTimeMS       int
}

func NewSolrZK(zookeepers string, zkRoot string, collectionName string, opts ...func(*solrZkInstance)) SolrZK {
	instance := solrZkInstance{zookeeper: NewZookeeper(zookeepers, zkRoot, collectionName), sleepTimeMS: 500, collection: collectionName}

	instance.clusterStateMutex = &sync.Mutex{}
	instance.listening = false
	instance.logger = log.New(ioutil.Discard, "[SolrClient] ", log.LstdFlags)

	for _, opt := range opts {
		opt(&instance)
	}

	return &instance
}

func (s *solrZkInstance) GetSolrLocator() SolrLocator {
	return s
}

func SleepTimeMS(sleepTimeMS int) func(*solrZkInstance) {
	return func(s *solrZkInstance) {
		s.sleepTimeMS = sleepTimeMS
	}
}

func (s *solrZkInstance) GetZookeepers() string {
	return s.zookeeper.GetConnectionString()
}

func (s *solrZkInstance) UseHTTPS() (bool, error) {
	var err error
	var props ClusterProps
	props, err = s.GetClusterProps()
	if err != nil {
		return false, err
	}
	return props.UrlScheme == "https", nil
}

func (s *solrZkInstance) GetLeaders(docID string) ([]string, error) {
	cs, err := s.GetClusterState()
	if err != nil {
		return []string{}, err
	}
	collectionMap := cs.Collections[s.collection]
	leader, err := findLeader(docID, &collectionMap)
	return []string{leader}, err
}

func (s *solrZkInstance) GetLeadersAndReplicas(docID string) ([]string, error) {
	leaderCount := 0
	var uris []string
	leaders, err := s.GetLeaders(docID)
	if err != nil {
		return uris, err
	}
	keys := strings.Split(docID, "!")
	replicas, err := s.GetReplicasFromRoute(keys[0])
	if err != nil {
		return uris, err
	}

	set := make(map[string]bool, len(leaders)+len(replicas))
	var all []string = make([]string, 0, len(replicas))
	for _, v := range leaders {
		set[v] = true
		if v != "" {
			all = append(all, v)
			leaderCount++
		}
	}
	for _, v := range replicas {
		if there := set[v]; !there {
			if v != "" {
				all = append(all, v)
				set[v] = true
			}
		}
	}
	if leaderCount == 0 {
		s.logger.Printf("Could not find any leaders for docid % ", docID)
	}
	return all, err
}

// GetClusterProps Intentionally return a copy vs a pointer want to be thread safe
func (s *solrZkInstance) GetClusterProps() (ClusterProps, error) {
	return s.zookeeper.GetClusterProps()
}

func (s *solrZkInstance) Listening() bool {
	return s.listening
}

func SolrZKLogger(logger Logger) func(s *solrZkInstance) {
	return func(solrZk *solrZkInstance) {
		solrZk.logger = logger
	}
}

func (s *solrZkInstance) GetReplicaUris() ([]string, error) {
	props, err := s.GetClusterProps()
	if err != nil {
		return []string{}, err
	}

	useHTTPS := props.UrlScheme == "https"

	protocol := "http"
	if useHTTPS {
		protocol = "https"
	}
	cs, err := s.GetClusterState()
	if err != nil {
		return []string{}, nil
	}
	nodes := cs.LiveNodes
	var uris []string = make([]string, 0, len(nodes))
	for _, v := range nodes {
		host := fmt.Sprintf("%s://%s/v2/c", protocol, v)
		uris = append(uris, host)
	}
	return shuffleNodes(uris), nil

}

func (s *solrZkInstance) GetShardFromRoute(route string) (string, error) {
	if strings.LastIndex(route, "!") != len(route)-1 {
		route += "!"
	}
	collection, ok := s.clusterState.Collections[s.collection]
	if !ok {
		return "", fmt.Errorf("[go-solr] Collection %s does not exist ", s.collection)
	}
	shard, err := findShard(route, &collection)
	if err != nil {
		return "", err
	}

	return shard.Name, nil
}

func (s *solrZkInstance) GetReplicasFromRoute(route string) ([]string, error) {
	if strings.LastIndex(route, "!") != len(route)-1 {
		route += "!"
	}
	collection, ok := s.clusterState.Collections[s.collection]
	if !ok {
		return nil, fmt.Errorf("[go-solr]  Collection %s does not exist ", s.collection)
	}
	//if contains route don't round robin
	hosts, err := findLiveReplicaUrls(route, &collection)
	if err != nil {
		return hosts, err
	}

	return shuffleNodes(hosts), nil

}
func shuffleNodes(nodes []string) []string {
	if len(nodes) == 1 {
		return nodes
	}
	dest := make([]string, len(nodes))
	perm := rand.Perm(len(nodes))
	for i, v := range perm {
		dest[v] = nodes[i]
	}
	return dest
}
<|endoftext|>


<commit_before>// +build partners

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/APTrust/exchange/util/fileutil"
	"github.com/APTrust/exchange/validation"
	"os"
)

func main() {
	configFile, outputFile, pathToBag := parseCommandLine()
	bagValidationConfig, errors := validation.LoadBagValidationConfig(configFile)
	if errors != nil && len(errors) > 0 {
		for _, err := range errors {
			fmt.Fprintln(os.Stderr, err.Error())
		}
		os.Exit(10)
	}
	validator, err := validation.NewBagValidator(pathToBag, bagValidationConfig)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error creating BagValidator: %s", err.Error())
		os.Exit(11)
	}
	exitCode := 0
	result := validator.Validate()
	if result.ParseSummary.HasErrors() {
		fmt.Println("Parse errors:")
		for _, err := range result.ParseSummary.Errors {
			fmt.Println(err)
		}
		fmt.Println("")
		exitCode = 12
	}
	if result.ValidationSummary.HasErrors() {
		fmt.Println("Validation errors:")
		for _, err := range result.ValidationSummary.Errors {
			fmt.Println(err)
		}
		fmt.Println("")
		exitCode = 13
	}
	if exitCode == 0 {
		fmt.Println("Bag is valid")
	}
	if outputFile != "" {
		err := dumpJson(result, outputFile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Could not write output file '%s': %v", outputFile, err)
			if exitCode == 0 {
				exitCode = 14
			}
		} else {
			fmt.Println("Wrote IntellectualObject JSON to", outputFile)
		}
	}
	os.Exit(exitCode)
}

func dumpJson(result *validation.ValidationResult, outputFile string) error {
	jsonData, err := json.MarshalIndent(result, "", "  ")
	if err != nil {
		return err
	}
	jsonFile, err := os.Create(outputFile)
	if err != nil {
		return err
	}
	defer jsonFile.Close()
	jsonFile.Write(jsonData)
	return nil
}

func parseCommandLine() (configFile, outputFile, bagPath string) {
	var pathToConfigFile string
	var pathToOutputFile string
	var pathToBag string
	flag.StringVar(&pathToConfigFile, "config", "", "Path to bag validation config file")
	flag.StringVar(&pathToOutputFile, "output", "", "Path to bag validation output file")
	flag.StringVar(&pathToBag, "bag", "", "Path to bag directory or tar file")
	flag.Parse()
	if pathToConfigFile == "" || pathToBag == "" {
		printUsage()
		os.Exit(15)
	}
	return expandTilde(pathToConfigFile), expandTilde(pathToOutputFile), expandTilde(pathToBag)
}

func expandTilde(filePath string) string {
	expandedPath, err := fileutil.ExpandTilde(filePath)
	if err != nil {
		return filePath
	} else {
		return expandedPath
	}
}

// Tell the user about the program.
func printUsage() {
	message := `
apt_validate validates aptrust bags.

Usage: apt_validate -config=<path> [-output=<path>] -bag=<path>

Param -config is required and should be the path to the JSON file
that describes APTrust or DPN bag validation rules.

Param -bag should be the path to the tar file or the directory
containing the bag you want to validate. E.g. /home/me/my_bag
for an untarred bag or /home/me/my_bag.tar for a tarred bag.

Param -output is not optional. If specified, the validator
will dump a JSON representation of the APTrust IntellectualObject
to the specified file. UUIDs in the JSON dump will be regenerated
each time validation runs, so don't depend on them.

apt_validate has the following exit codes:

 0 - Program completed normally and bag is valid.
10 - Bag validation config file is not valid
11 - Could not create bag validator
12 - Bag could not be parsed
13 - Bag was parsed, but is not valid
14 - Bag is valid, but validator could not dump JSON to output file
15 - Incorrect usage: required params missing.
`
	fmt.Println(message)
}
<commit_msg>Fixed error message<commit_after>// +build partners

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/APTrust/exchange/util/fileutil"
	"github.com/APTrust/exchange/validation"
	"os"
)

func main() {
	configFile, outputFile, pathToBag := parseCommandLine()
	bagValidationConfig, errors := validation.LoadBagValidationConfig(configFile)
	if errors != nil && len(errors) > 0 {
		for _, err := range errors {
			fmt.Fprintln(os.Stderr, err.Error())
		}
		os.Exit(10)
	}
	validator, err := validation.NewBagValidator(pathToBag, bagValidationConfig)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error creating BagValidator:", err.Error())
		os.Exit(11)
	}
	exitCode := 0
	result := validator.Validate()
	if result.ParseSummary.HasErrors() {
		fmt.Println("Parse errors:")
		for _, err := range result.ParseSummary.Errors {
			fmt.Println(err)
		}
		fmt.Println("")
		exitCode = 12
	}
	if result.ValidationSummary.HasErrors() {
		fmt.Println("Validation errors:")
		for _, err := range result.ValidationSummary.Errors {
			fmt.Println(err)
		}
		fmt.Println("")
		exitCode = 13
	}
	if exitCode == 0 {
		fmt.Println("Bag is valid")
	}
	if outputFile != "" {
		err := dumpJson(result, outputFile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Could not write output file '%s': %v", outputFile, err)
			if exitCode == 0 {
				exitCode = 14
			}
		} else {
			fmt.Println("Wrote IntellectualObject JSON to", outputFile)
		}
	}
	os.Exit(exitCode)
}

func dumpJson(result *validation.ValidationResult, outputFile string) error {
	jsonData, err := json.MarshalIndent(result, "", "  ")
	if err != nil {
		return err
	}
	jsonFile, err := os.Create(outputFile)
	if err != nil {
		return err
	}
	defer jsonFile.Close()
	jsonFile.Write(jsonData)
	return nil
}

func parseCommandLine() (configFile, outputFile, bagPath string) {
	var pathToConfigFile string
	var pathToOutputFile string
	var pathToBag string
	flag.StringVar(&pathToConfigFile, "config", "", "Path to bag validation config file")
	flag.StringVar(&pathToOutputFile, "output", "", "Path to bag validation output file")
	flag.StringVar(&pathToBag, "bag", "", "Path to bag directory or tar file")
	flag.Parse()
	if pathToConfigFile == "" || pathToBag == "" {
		printUsage()
		os.Exit(15)
	}
	return expandTilde(pathToConfigFile), expandTilde(pathToOutputFile), expandTilde(pathToBag)
}

func expandTilde(filePath string) string {
	expandedPath, err := fileutil.ExpandTilde(filePath)
	if err != nil {
		return filePath
	} else {
		return expandedPath
	}
}

// Tell the user about the program.
func printUsage() {
	message := `
apt_validate validates aptrust bags.

Usage: apt_validate -config=<path> [-output=<path>] -bag=<path>

Param -config is required and should be the path to the JSON file
that describes APTrust or DPN bag validation rules.

Param -bag should be the path to the tar file or the directory
containing the bag you want to validate. E.g. /home/me/my_bag
for an untarred bag or /home/me/my_bag.tar for a tarred bag.

Param -output is not optional. If specified, the validator
will dump a JSON representation of the APTrust IntellectualObject
to the specified file. UUIDs in the JSON dump will be regenerated
each time validation runs, so don't depend on them.

apt_validate has the following exit codes:

 0 - Program completed normally and bag is valid.
10 - Bag validation config file is not valid
11 - Could not create bag validator
12 - Bag could not be parsed
13 - Bag was parsed, but is not valid
14 - Bag is valid, but validator could not dump JSON to output file
15 - Incorrect usage: required params missing.
`
	fmt.Println(message)
}
<|endoftext|>


<commit_before><commit_msg>Experiment. Add both primary+secondary to vendorspecific entry<commit_after><|endoftext|>


<commit_before><commit_msg>doc: Make examples a complete program<commit_after><|endoftext|>


<commit_before><commit_msg>update env<commit_after><|endoftext|>


<commit_before><commit_msg>Parse into structs<commit_after><|endoftext|>


<commit_before><commit_msg>Remove unreachable code<commit_after><|endoftext|>


<commit_before><commit_msg>ui: Fix comments<commit_after><|endoftext|>


<commit_before><commit_msg>Stop the game when the screen is not active<commit_after><|endoftext|>


<commit_before>// Copyright 2012 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 signal

import (
	"bytes"
	"internal/testenv"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
	"testing"
	"time"
)

func sendCtrlBreak(t *testing.T, pid int) {
	d, e := syscall.LoadDLL("kernel32.dll")
	if e != nil {
		t.Fatalf("LoadDLL: %v\n", e)
	}
	p, e := d.FindProc("GenerateConsoleCtrlEvent")
	if e != nil {
		t.Fatalf("FindProc: %v\n", e)
	}
	r, _, e := p.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid))
	if r == 0 {
		t.Fatalf("GenerateConsoleCtrlEvent: %v\n", e)
	}
}

func TestCtrlBreak(t *testing.T) {
	// create source file
	const source = `
package main

import (
	"log"
	"os"
	"os/signal"
	"time"
)

func main() {
	c := make(chan os.Signal, 10)
	signal.Notify(c)
	select {
	case s := <-c:
		if s != os.Interrupt {
			log.Fatalf("Wrong signal received: got %q, want %q\n", s, os.Interrupt)
		}
	case <-time.After(3 * time.Second):
		log.Fatalf("Timeout waiting for Ctrl+Break\n")
	}
}
`
	tmp, err := os.MkdirTemp("", "TestCtrlBreak")
	if err != nil {
		t.Fatal("TempDir failed: ", err)
	}
	defer os.RemoveAll(tmp)

	// write ctrlbreak.go
	name := filepath.Join(tmp, "ctlbreak")
	src := name + ".go"
	f, err := os.Create(src)
	if err != nil {
		t.Fatalf("Failed to create %v: %v", src, err)
	}
	defer f.Close()
	f.Write([]byte(source))

	// compile it
	exe := name + ".exe"
	defer os.Remove(exe)
	o, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput()
	if err != nil {
		t.Fatalf("Failed to compile: %v\n%v", err, string(o))
	}

	// run it
	cmd := exec.Command(exe)
	var b bytes.Buffer
	cmd.Stdout = &b
	cmd.Stderr = &b
	cmd.SysProcAttr = &syscall.SysProcAttr{
		CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
	}
	err = cmd.Start()
	if err != nil {
		t.Fatalf("Start failed: %v", err)
	}
	go func() {
		time.Sleep(1 * time.Second)
		sendCtrlBreak(t, cmd.Process.Pid)
	}()
	err = cmd.Wait()
	if err != nil {
		t.Fatalf("Program exited with error: %v\n%v", err, string(b.Bytes()))
	}
}
<commit_msg>os/signal: replace os.MkdirTemp with T.TempDir<commit_after>// Copyright 2012 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 signal

import (
	"bytes"
	"internal/testenv"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
	"testing"
	"time"
)

func sendCtrlBreak(t *testing.T, pid int) {
	d, e := syscall.LoadDLL("kernel32.dll")
	if e != nil {
		t.Fatalf("LoadDLL: %v\n", e)
	}
	p, e := d.FindProc("GenerateConsoleCtrlEvent")
	if e != nil {
		t.Fatalf("FindProc: %v\n", e)
	}
	r, _, e := p.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid))
	if r == 0 {
		t.Fatalf("GenerateConsoleCtrlEvent: %v\n", e)
	}
}

func TestCtrlBreak(t *testing.T) {
	// create source file
	const source = `
package main

import (
	"log"
	"os"
	"os/signal"
	"time"
)

func main() {
	c := make(chan os.Signal, 10)
	signal.Notify(c)
	select {
	case s := <-c:
		if s != os.Interrupt {
			log.Fatalf("Wrong signal received: got %q, want %q\n", s, os.Interrupt)
		}
	case <-time.After(3 * time.Second):
		log.Fatalf("Timeout waiting for Ctrl+Break\n")
	}
}
`
	tmp := t.TempDir()

	// write ctrlbreak.go
	name := filepath.Join(tmp, "ctlbreak")
	src := name + ".go"
	f, err := os.Create(src)
	if err != nil {
		t.Fatalf("Failed to create %v: %v", src, err)
	}
	defer f.Close()
	f.Write([]byte(source))

	// compile it
	exe := name + ".exe"
	defer os.Remove(exe)
	o, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput()
	if err != nil {
		t.Fatalf("Failed to compile: %v\n%v", err, string(o))
	}

	// run it
	cmd := exec.Command(exe)
	var b bytes.Buffer
	cmd.Stdout = &b
	cmd.Stderr = &b
	cmd.SysProcAttr = &syscall.SysProcAttr{
		CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
	}
	err = cmd.Start()
	if err != nil {
		t.Fatalf("Start failed: %v", err)
	}
	go func() {
		time.Sleep(1 * time.Second)
		sendCtrlBreak(t, cmd.Process.Pid)
	}()
	err = cmd.Wait()
	if err != nil {
		t.Fatalf("Program exited with error: %v\n%v", err, string(b.Bytes()))
	}
}
<|endoftext|>


<commit_before>package space

import (
	"fmt"

	"code.cloudfoundry.org/cli/cf"
	"code.cloudfoundry.org/cli/cf/api/organizations"
	"code.cloudfoundry.org/cli/cf/api/spaces"
	"code.cloudfoundry.org/cli/cf/commandregistry"
	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
	"code.cloudfoundry.org/cli/cf/flags"
	. "code.cloudfoundry.org/cli/cf/i18n"
	"code.cloudfoundry.org/cli/cf/models"
	"code.cloudfoundry.org/cli/cf/requirements"
	"code.cloudfoundry.org/cli/cf/terminal"
)

type DeleteSpace struct {
	ui        terminal.UI
	config    coreconfig.ReadWriter
	spaceRepo spaces.SpaceRepository
	spaceReq  requirements.SpaceRequirement
	orgRepo   organizations.OrganizationRepository
}

func init() {
	commandregistry.Register(&DeleteSpace{})
}

func (cmd *DeleteSpace) MetaData() commandregistry.CommandMetadata {
	fs := make(map[string]flags.FlagSet)
	fs["f"] = &flags.BoolFlag{ShortName: "f", Usage: T("Force deletion without confirmation")}
	fs["o"] = &flags.StringFlag{ShortName: "o", Usage: T("Delete space within specifid org")}

	return commandregistry.CommandMetadata{
		Name:        "delete-space",
		Description: T("Delete a space"),
		Usage: []string{
			T("CF_NAME delete-space SPACE [-o] [-f]"),
		},
		Flags: fs,
	}
}

func (cmd *DeleteSpace) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) {
	if len(fc.Args()) != 1 {
		cmd.ui.Failed(T("Incorrect Usage. Requires an argument\n\n") + commandregistry.Commands.CommandUsage("delete-space"))
		return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 1)
	}

	cmd.spaceReq = requirementsFactory.NewSpaceRequirement(fc.Args()[0])

	reqs := []requirements.Requirement{
		requirementsFactory.NewLoginRequirement(),
	}

	if fc.String("o") == "" {
		reqs = append(reqs, requirementsFactory.NewTargetedOrgRequirement())
		reqs = append(reqs, cmd.spaceReq)
	}

	return reqs, nil
}

func (cmd *DeleteSpace) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command {
	cmd.ui = deps.UI
	cmd.config = deps.Config
	cmd.spaceRepo = deps.RepoLocator.GetSpaceRepository()
	cmd.orgRepo = deps.RepoLocator.GetOrganizationRepository()
	return cmd
}
func (cmd *DeleteSpace) Execute(c flags.FlagContext) error {
	var space models.Space

	spaceName := c.Args()[0]
	orgName := c.String("o")

	if orgName == "" {
		space = cmd.spaceReq.GetSpace()

		orgName = cmd.config.OrganizationFields().Name
	} else {
		org, err := cmd.orgRepo.FindByName(orgName)
		if err != nil {
			return err
		}

		space, err = cmd.spaceRepo.FindByNameInOrg(spaceName, org.GUID)
		if err != nil {
			return err
		}
	}

	if !c.Bool("f") {
		if !cmd.ui.ConfirmDelete(T("space"), spaceName) {
			return nil
		}
	}

	cmd.ui.Say(T("Deleting space {{.TargetSpace}} in org {{.TargetOrg}} as {{.CurrentUser}}...",
		map[string]interface{}{
			"TargetSpace": terminal.EntityNameColor(spaceName),
			"TargetOrg":   terminal.EntityNameColor(orgName),
			"CurrentUser": terminal.EntityNameColor(cmd.config.Username()),
		}))

	err := cmd.spaceRepo.Delete(space.GUID)
	if err != nil {
		return err
	}

	cmd.ui.Ok()

	if cmd.config.SpaceFields().GUID == space.GUID {
		cmd.config.SetSpaceFields(models.SpaceFields{})
		cmd.ui.Say(T("TIP: No space targeted, use '{{.CfTargetCommand}}' to target a space",
			map[string]interface{}{"CfTargetCommand": cf.Name + " target -s"}))
	}

	return nil
}
<commit_msg>Fix typos in usage strings<commit_after>package space

import (
	"fmt"

	"code.cloudfoundry.org/cli/cf"
	"code.cloudfoundry.org/cli/cf/api/organizations"
	"code.cloudfoundry.org/cli/cf/api/spaces"
	"code.cloudfoundry.org/cli/cf/commandregistry"
	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
	"code.cloudfoundry.org/cli/cf/flags"
	. "code.cloudfoundry.org/cli/cf/i18n"
	"code.cloudfoundry.org/cli/cf/models"
	"code.cloudfoundry.org/cli/cf/requirements"
	"code.cloudfoundry.org/cli/cf/terminal"
)

type DeleteSpace struct {
	ui        terminal.UI
	config    coreconfig.ReadWriter
	spaceRepo spaces.SpaceRepository
	spaceReq  requirements.SpaceRequirement
	orgRepo   organizations.OrganizationRepository
}

func init() {
	commandregistry.Register(&DeleteSpace{})
}

func (cmd *DeleteSpace) MetaData() commandregistry.CommandMetadata {
	fs := make(map[string]flags.FlagSet)
	fs["f"] = &flags.BoolFlag{ShortName: "f", Usage: T("Force deletion without confirmation")}
	fs["o"] = &flags.StringFlag{ShortName: "o", Usage: T("Delete space within specified org")}

	return commandregistry.CommandMetadata{
		Name:        "delete-space",
		Description: T("Delete a space"),
		Usage: []string{
			T("CF_NAME delete-space SPACE [-o] ORG [-f]"),
		},
		Flags: fs,
	}
}

func (cmd *DeleteSpace) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) {
	if len(fc.Args()) != 1 {
		cmd.ui.Failed(T("Incorrect Usage. Requires an argument\n\n") + commandregistry.Commands.CommandUsage("delete-space"))
		return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 1)
	}

	cmd.spaceReq = requirementsFactory.NewSpaceRequirement(fc.Args()[0])

	reqs := []requirements.Requirement{
		requirementsFactory.NewLoginRequirement(),
	}

	if fc.String("o") == "" {
		reqs = append(reqs, requirementsFactory.NewTargetedOrgRequirement())
		reqs = append(reqs, cmd.spaceReq)
	}

	return reqs, nil
}

func (cmd *DeleteSpace) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command {
	cmd.ui = deps.UI
	cmd.config = deps.Config
	cmd.spaceRepo = deps.RepoLocator.GetSpaceRepository()
	cmd.orgRepo = deps.RepoLocator.GetOrganizationRepository()
	return cmd
}
func (cmd *DeleteSpace) Execute(c flags.FlagContext) error {
	var space models.Space

	spaceName := c.Args()[0]
	orgName := c.String("o")

	if orgName == "" {
		space = cmd.spaceReq.GetSpace()

		orgName = cmd.config.OrganizationFields().Name
	} else {
		org, err := cmd.orgRepo.FindByName(orgName)
		if err != nil {
			return err
		}

		space, err = cmd.spaceRepo.FindByNameInOrg(spaceName, org.GUID)
		if err != nil {
			return err
		}
	}

	if !c.Bool("f") {
		if !cmd.ui.ConfirmDelete(T("space"), spaceName) {
			return nil
		}
	}

	cmd.ui.Say(T("Deleting space {{.TargetSpace}} in org {{.TargetOrg}} as {{.CurrentUser}}...",
		map[string]interface{}{
			"TargetSpace": terminal.EntityNameColor(spaceName),
			"TargetOrg":   terminal.EntityNameColor(orgName),
			"CurrentUser": terminal.EntityNameColor(cmd.config.Username()),
		}))

	err := cmd.spaceRepo.Delete(space.GUID)
	if err != nil {
		return err
	}

	cmd.ui.Ok()

	if cmd.config.SpaceFields().GUID == space.GUID {
		cmd.config.SetSpaceFields(models.SpaceFields{})
		cmd.ui.Say(T("TIP: No space targeted, use '{{.CfTargetCommand}}' to target a space",
			map[string]interface{}{"CfTargetCommand": cf.Name + " target -s"}))
	}

	return nil
}
<|endoftext|>


<commit_before>package mmq

import (
	"bytes"
	"encoding/binary"
	"hash/crc32"
	"io"
	"math"

	"gopkg.in/logex.v1"
)

const (
	MagicByte byte = 0x9a

	MsgIdOffset    = 10
	MessageMaxSize = math.MaxUint16
)

var (
	ErrMagicNotMatch  = logex.Define("magic byte not match")
	ErrInvalidMessage = logex.Define("invalid message: %v")
)

// in binary(magic always is 0x9a):
// +-------+--------+-----+---------+-------+------+
// | magic | length | crc | version | msgid | data |
// +-------+--------+-----+---------+-------+------+
// | 1     | 4      | 4   | 1       | 8     | ...  |
// +-------+--------+-----+---------+-------+------+
type Message struct {
	Length  int32
	Crc     uint32
	Version int16

	MsgId int64
	Data  []byte
}

func NewMessage(data []byte) (*Message, error) {
	buf := bytes.NewBuffer(data)
	magic, err := buf.ReadByte()
	if err != nil {
		return nil, logex.Trace(err, "magic")
	}
	if magic != MagicByte {
		return nil, ErrMagicNotMatch
	}
	m := new(Message)
	if err = binary.Read(buf, binary.LittleEndian, &m.Length); err != nil {
		return nil, ErrInvalidMessage.Format("read length").Follow(err)
	}
	if err = binary.Read(buf, binary.LittleEndian, &m.Crc); err != nil {
		return nil, ErrInvalidMessage.Format("read crc").Follow(err)
	}
	h := crc32.NewIEEE()
	h.Write(buf.Bytes())
	if m.Crc != h.Sum32() {
		return nil, ErrInvalidMessage.Format("crc not match")
	}
	if err = binary.Read(buf, binary.LittleEndian, &m.Version); err != nil {
		return nil, ErrInvalidMessage.Format("read version")
	}
	switch m.Version {
	case 1:
		err = parseMsgV1(m, buf)
	default:
		err = ErrInvalidMessage.Format("unsupport version")
	}
	if err != nil {
		return nil, logex.Trace(err)
	}

	return m, nil
}

func parseMsgV1(m *Message, buf *bytes.Buffer) error {
	if err := binary.Read(buf, binary.LittleEndian, &m.MsgId); err != nil {
		return ErrInvalidMessage.Format("read msgid")
	}
	return nil
}

func (m *Message) WriteTo(w io.Writer) (err error) {
	return nil
}
<commit_msg>add set message id<commit_after>package mmq

import (
	"bytes"
	"encoding/binary"
	"hash/crc32"
	"io"
	"math"

	"gopkg.in/logex.v1"
)

const (
	MagicByte byte = 0x9a

	MsgIdOffset    = 10
	MessageMaxSize = math.MaxUint16
)

var (
	ErrMagicNotMatch  = logex.Define("magic byte not match")
	ErrInvalidMessage = logex.Define("invalid message: %v")
)

// in binary(magic always is 0x9a):
// +-------+--------+-----+---------+-------+------+
// | magic | length | crc | version | msgid | data |
// +-------+--------+-----+---------+-------+------+
// | 1     | 4      | 4   | 1       | 8     | ...  |
// +-------+--------+-----+---------+-------+------+
type Message struct {
	Length  int32
	Crc     uint32
	Version int16

	MsgId uint64
	Data  []byte
}

func NewMessage(data []byte) (*Message, error) {
	buf := bytes.NewBuffer(data)
	magic, err := buf.ReadByte()
	if err != nil {
		return nil, logex.Trace(err, "magic")
	}
	if magic != MagicByte {
		return nil, ErrMagicNotMatch
	}
	m := new(Message)
	if err = binary.Read(buf, binary.LittleEndian, &m.Length); err != nil {
		return nil, ErrInvalidMessage.Format("read length").Follow(err)
	}
	if err = binary.Read(buf, binary.LittleEndian, &m.Crc); err != nil {
		return nil, ErrInvalidMessage.Format("read crc").Follow(err)
	}
	h := crc32.NewIEEE()
	h.Write(buf.Bytes())
	if m.Crc != h.Sum32() {
		return nil, ErrInvalidMessage.Format("crc not match")
	}
	if err = binary.Read(buf, binary.LittleEndian, &m.Version); err != nil {
		return nil, ErrInvalidMessage.Format("read version")
	}
	switch m.Version {
	case 1:
		err = parseMsgV1(m, buf)
	default:
		err = ErrInvalidMessage.Format("unsupport version")
	}
	if err != nil {
		return nil, logex.Trace(err)
	}

	return m, nil
}

func parseMsgV1(m *Message, buf *bytes.Buffer) error {
	if err := binary.Read(buf, binary.LittleEndian, &m.MsgId); err != nil {
		return ErrInvalidMessage.Format("read msgid")
	}
	return nil
}

func (m *Message) SetMsgId(id uint64) {
	m.MsgId = id
	binary.LittleEndian.PutUint64(m.Data[offset:offset+8], m.MsgId)
}

func (m *Message) WriteTo(w io.Writer) (err error) {
	return nil
}
<|endoftext|>


<commit_before>/*
Package model converts almost any Go data structures into a tree model:
1. cyclic references are replaced with labels
2. pointer & interfaces are replaced with values
3. reflections are hidden from outside if possible
*/
package model

import (
	"errors"
	"reflect"
	"strconv"
)

type List []*Node

type Node struct {
	Label Label
	Value interface{}
	List  List
}
type Label string

func New(v interface{}) (List, error) {
	if v == nil {
		return nil, nil
	}
	return newMaker().newList(reflect.ValueOf(v))
}

func Fill(l List, v interface{}) error {
	if v == nil {
		return nil
	}
	return newFiller().fillList(l, reflect.ValueOf(v))
}

func (m *maker) newList(v reflect.Value) (List, error) {
	switch v.Type().Kind() {
	case reflect.Int, reflect.String:
		node, err := m.newNode(v)
		if err != nil {
			return nil, err
		}
		return List{node}, nil
	case reflect.Slice:
		l := make(List, v.Len())
		for i := 0; i < v.Len(); i++ {
			node, err := m.newNode(v.Index(i))
			if err != nil {
				return nil, err
			}
			l[i] = node
		}
		return l, nil
	case reflect.Ptr:
		return m.newList(indirect(v))
	}
	return nil, errors.New("newList: unsupported type")
}

func (m *maker) newNode(v reflect.Value) (*Node, error) {
	switch v.Type().Kind() {
	case reflect.Int, reflect.String:
		return &Node{Value: v.Interface()}, nil
	case reflect.Slice:
		list, err := m.newList(v)
		if err != nil {
			return nil, err
		}
		return &Node{List: list}, nil
	case reflect.Ptr:
		addr := v.Pointer()
		if label, ok := m.label(addr); ok {
			return &Node{Value: label}, nil
		}
		// wrong structure will cause infinite loop here.
		node, err := m.newNode(indirect(v))
		if err != nil {
			return nil, err
		}
		m.register(addr, node)
		return node, nil
	}
	return nil, errors.New("newNode: unsupported type")
}

func (f *filler) fillList(l List, v reflect.Value) error {
	switch v.Type().Kind() {
	case reflect.Int, reflect.String:
		if len(l) > 0 {
			return f.fillNode(l[0], v)
		}
	case reflect.Slice:
		for i, n := range l {
			v.Set(reflect.Append(v, reflect.New(v.Type().Elem()).Elem()))
			elem := v.Index(i)
			if err := f.fillNode(n, elem); err != nil {
				return err
			}
		}
		return nil
	case reflect.Ptr:
		return f.fillList(l, allocIndirect(v))
	}
	return errors.New("List.fill: unsupported type")
}

func (f *filler) fillNode(n *Node, v reflect.Value) error {
	switch v.Type().Kind() {
	case reflect.Int, reflect.String:
		if _, ok := n.Value.(Label); ok {
			return nil
		}
		v.Set(reflect.ValueOf(n.Value))
		return nil
	case reflect.Slice:
		return f.fillList(n.List, v)
	case reflect.Ptr:
		return f.fillNode(n, allocIndirect(v))
	}
	return errors.New("Node.fill: unsupported type")
}

func indirect(v reflect.Value) reflect.Value {
	for v.Type().Kind() == reflect.Ptr && !v.IsNil() {
		v = reflect.Indirect(v)
	}
	return v
}

func allocIndirect(v reflect.Value) reflect.Value {
	for v.Type().Kind() == reflect.Ptr {
		if v.IsNil() {
			v.Set(reflect.New(v.Type().Elem()))
		}
		v = reflect.Indirect(v)
	}
	return v
}

// maker makes a new List
type maker struct {
	m      map[uintptr]*Node
	serial int
}

func newMaker() *maker {
	return &maker{
		m:      make(map[uintptr]*Node),
		serial: 1,
	}
}

func (m *maker) label(addr uintptr) (Label, bool) {
	if node, ok := m.m[addr]; ok {
		if node.Label == "" {
			node.Label = Label(strconv.Itoa(m.serial))
			p(node.Label)
			m.serial++
		}
		return node.Label, true
	}
	return Label(0), false
}

func (m *maker) register(p uintptr, node *Node) {
	m.m[p] = node
}

// filler fills from a list
type filler struct {
	m map[Label]reflect.Value
}

func newFiller() *filler {
	return &filler{make(map[Label]reflect.Value)}
}

func (f *filler) register(label Label, v reflect.Value) {
	f.m[label] = v
}

func (f *filler) value(label Label) reflect.Value {
	return f.m[label]
}
<commit_msg>fix infinite loop.<commit_after>/*
Package model converts almost any Go data structures into a tree model:
1. cyclic references are replaced with labels
2. pointer & interfaces are replaced with values
3. reflections are hidden from outside if possible
*/
package model

import (
	"errors"
	"reflect"
	"strconv"
)

type List []*Node

type Node struct {
	Label Label
	Value interface{}
	List  List
}
type Label string

func New(v interface{}) (List, error) {
	if v == nil {
		return nil, nil
	}
	return newMaker().newList(reflect.ValueOf(v))
}

func Fill(l List, v interface{}) error {
	if v == nil {
		return nil
	}
	return newFiller().fillList(l, reflect.ValueOf(v))
}

func (m *maker) newList(v reflect.Value) (List, error) {
	switch v.Type().Kind() {
	case reflect.Int, reflect.String:
		node, err := m.newNode(v)
		if err != nil {
			return nil, err
		}
		return List{node}, nil
	case reflect.Slice:
		l := make(List, v.Len())
		for i := 0; i < v.Len(); i++ {
			node, err := m.newNode(v.Index(i))
			if err != nil {
				return nil, err
			}
			l[i] = node
		}
		return l, nil
	case reflect.Ptr:
		return m.newList(indirect(v))
	}
	return nil, errors.New("newList: unsupported type")
}

func (m *maker) newNode(v reflect.Value) (*Node, error) {
	switch v.Type().Kind() {
	case reflect.Int, reflect.String:
		return &Node{Value: v.Interface()}, nil
	case reflect.Slice:
		list, err := m.newList(v)
		if err != nil {
			return nil, err
		}
		return &Node{List: list}, nil
	case reflect.Ptr:
		if v.IsNil() {
			return nil, nil // avoid infinite loop
		}
		addr := v.Pointer()
		if label, ok := m.label(addr); ok {
			return &Node{Value: label}, nil
		}
		node, err := m.newNode(indirect(v))
		if err != nil {
			return nil, err
		}
		m.register(addr, node)
		return node, nil
	}
	return nil, errors.New("newNode: unsupported type")
}

func (f *filler) fillList(l List, v reflect.Value) error {
	switch v.Type().Kind() {
	case reflect.Int, reflect.String:
		if len(l) > 0 {
			return f.fillNode(l[0], v)
		}
	case reflect.Slice:
		for i, n := range l {
			v.Set(reflect.Append(v, reflect.New(v.Type().Elem()).Elem()))
			elem := v.Index(i)
			if err := f.fillNode(n, elem); err != nil {
				return err
			}
		}
		return nil
	case reflect.Ptr:
		return f.fillList(l, allocIndirect(v))
	}
	return errors.New("List.fill: unsupported type")
}

func (f *filler) fillNode(n *Node, v reflect.Value) error {
	switch v.Type().Kind() {
	case reflect.Int, reflect.String:
		if _, ok := n.Value.(Label); ok {
			return nil
		}
		v.Set(reflect.ValueOf(n.Value))
		return nil
	case reflect.Slice:
		return f.fillList(n.List, v)
	case reflect.Ptr:
		return nil
		return f.fillNode(n, allocIndirect(v))
	}
	return errors.New("Node.fill: unsupported type")
}

func indirect(v reflect.Value) reflect.Value {
	for v.Type().Kind() == reflect.Ptr && !v.IsNil() {
		v = reflect.Indirect(v)
	}
	return v
}

func allocIndirect(v reflect.Value) reflect.Value {
	for v.Type().Kind() == reflect.Ptr {
		if v.IsNil() {
			v.Set(reflect.New(v.Type().Elem()))
		}
		v = reflect.Indirect(v)
	}
	return v
}

// maker makes a new List
type maker struct {
	m      map[uintptr]*Node
	serial int
}

func newMaker() *maker {
	return &maker{
		m:      make(map[uintptr]*Node),
		serial: 1,
	}
}

func (m *maker) label(addr uintptr) (Label, bool) {
	if node, ok := m.m[addr]; ok {
		if node.Label == "" {
			node.Label = Label(strconv.Itoa(m.serial))
			p(node.Label)
			m.serial++
		}
		return node.Label, true
	}
	return Label(0), false
}

func (m *maker) register(p uintptr, node *Node) {
	m.m[p] = node
}

// filler fills from a list
type filler struct {
	m map[Label]reflect.Value
}

func newFiller() *filler {
	return &filler{make(map[Label]reflect.Value)}
}

func (f *filler) register(label Label, v reflect.Value) {
	f.m[label] = v
}

func (f *filler) value(label Label) reflect.Value {
	return f.m[label]
}
<|endoftext|>


<commit_before>package models

import (
	"github.com/alex1sz/shotcharter-go/db"
	"log"
	"time"
)

type Game struct {
	ID        string    `db:"id" json:"id"`
	StartAt   time.Time `db:"start_at" json:"start_at,omitempty"`
	HomeTeam  *Team     `json:"home_team,omitempty"`
	AwayTeam  *Team     `json:"away_team, omitempty"`
	HomeScore uint8     `db:"home_score" json:"home_score"`
	AwayScore uint8     `db:"away_score" json:"away_score"`
	CreatedAt string    `db:"created_at" json:"created_at"`
	UpdatedAt string    `db:"updated_at" json:"updated_at"`
}

func (game *Game) Create() (err error) {
	err = db.Db.QueryRow("insert into games (home_team_id, away_team_id) values ($1, $2) returning id", game.HomeTeam.ID, game.AwayTeam.ID).Scan(&game.ID)
	return
}

func FindGameByID(id string) (game Game, err error) {
	game = Game{}

	// err = db.Db.QueryRowx("select (*) from games where id = $1", id).Scan(&game.ID, &game.StartAt, &game.HomeTeam, &game.AwayTeam, &game.HomeScore, &game.AwayScore, &game.CreatedAt, &game.UpdatedAt)
	err = db.Db.Get(&game, "select (*) from games where id = $1", id)

	if err != nil {
		log.Println(err)
		return
	}

	log.Print(game)
	log.Println(game)

	return game, err
}
<commit_msg>Makes Game.StartAt field sql.NullString needed for sqlx Scan() to work<commit_after>package models

import (
	// database/sql import needed to use sql.NullString for sqlx Scan() functionality
	"database/sql"
	"github.com/alex1sz/shotcharter-go/db"
	"log"
)

type Game struct {
	ID        string         `db:"id" json:"id"`
	StartAt   sql.NullString `db:"start_at" json:"start_at,omitempty"`
	HomeScore uint8          `db:"home_score" json:"home_score"`
	AwayScore uint8          `db:"away_score" json:"away_score"`
	CreatedAt string         `db:"created_at" json:"created_at"`
	UpdatedAt string         `db:"updated_at" json:"updated_at"`
	HomeTeam  *Team          `db:"home_team_id" json:"home_team,omitempty"`
	AwayTeam  *Team          `db:"away_team_id" json:"away_team,omitempty"`
}

func (game *Game) Create() (err error) {
	err = db.Db.QueryRow("insert into games (home_team_id, away_team_id) values ($1, $2) returning id", game.HomeTeam.ID, game.AwayTeam.ID).Scan(&game.ID)
	return
}

func FindGameByID(id string) (game Game, err error) {
	err = db.Db.Get(&game, "select * from games where id = $1", id)

	if err != nil {
		log.Println(err)
		return
	}
	return game, err
}
<|endoftext|>