<commit_before>package gorillaws

import (
	"encoding/binary"
	"github.com/davyxu/cellnet"
	"github.com/davyxu/cellnet/codec"
	"github.com/gorilla/websocket"
)

const (
	MsgIDSize = 2 // uint16
)

type WSMessageTransmitter struct {
}

func (WSMessageTransmitter) OnRecvMessage(ses cellnet.Session) (msg interface{}, err error) {

	conn, ok := ses.Raw().(*websocket.Conn)

	// 转换错误，或者连接已经关闭时退出
	if !ok || conn == nil {
		return nil, nil
	}

	var messageType int
	var raw []byte
	messageType, raw, err = conn.ReadMessage()

	if err != nil {
		return
	}

	switch messageType {
	case websocket.BinaryMessage:
		msgID := binary.LittleEndian.Uint16(raw)
		msgData := raw[MsgIDSize:]

		msg, _, err = codec.DecodeMessage(int(msgID), msgData)
	}

	return
}

func (WSMessageTransmitter) OnSendMessage(ses cellnet.Session, msg interface{}) error {

	conn, ok := ses.Raw().(*websocket.Conn)

	// 转换错误，或者连接已经关闭时退出
	if !ok || conn == nil {
		return nil
	}

	var (
		msgData []byte
		msgID   int
	)

	switch m := msg.(type) {
	case *cellnet.RawPacket: // 发裸包
		msgData = m.MsgData
		msgID = m.MsgID
	default: // 发普通编码包
		var err error
		var meta *cellnet.MessageMeta

		// 将用户数据转换为字节数组和消息ID
		msgData, meta, err = codec.EncodeMessage(msg, nil)

		if err != nil {
			return err
		}

		msgID = meta.ID
	}

	pkt := make([]byte, MsgIDSize+len(msgData))
	binary.LittleEndian.PutUint16(pkt, uint16(msgID))
	copy(pkt[MsgIDSize:], msgData)

	conn.WriteMessage(websocket.BinaryMessage, pkt)

	return nil
}
<commit_msg>修复websocket输入封包小于消息号需要数据大小时导致的崩溃#63<commit_after>package gorillaws

import (
	"encoding/binary"
	"github.com/davyxu/cellnet"
	"github.com/davyxu/cellnet/codec"
	"github.com/davyxu/cellnet/util"
	"github.com/gorilla/websocket"
)

const (
	MsgIDSize = 2 // uint16
)

type WSMessageTransmitter struct {
}

func (WSMessageTransmitter) OnRecvMessage(ses cellnet.Session) (msg interface{}, err error) {

	conn, ok := ses.Raw().(*websocket.Conn)

	// 转换错误，或者连接已经关闭时退出
	if !ok || conn == nil {
		return nil, nil
	}

	var messageType int
	var raw []byte
	messageType, raw, err = conn.ReadMessage()

	if err != nil {
		return
	}

	if len(raw) < MsgIDSize {
		return nil, util.ErrMinPacket
	}

	switch messageType {
	case websocket.BinaryMessage:
		msgID := binary.LittleEndian.Uint16(raw)
		msgData := raw[MsgIDSize:]

		msg, _, err = codec.DecodeMessage(int(msgID), msgData)
	}

	return
}

func (WSMessageTransmitter) OnSendMessage(ses cellnet.Session, msg interface{}) error {

	conn, ok := ses.Raw().(*websocket.Conn)

	// 转换错误，或者连接已经关闭时退出
	if !ok || conn == nil {
		return nil
	}

	var (
		msgData []byte
		msgID   int
	)

	switch m := msg.(type) {
	case *cellnet.RawPacket: // 发裸包
		msgData = m.MsgData
		msgID = m.MsgID
	default: // 发普通编码包
		var err error
		var meta *cellnet.MessageMeta

		// 将用户数据转换为字节数组和消息ID
		msgData, meta, err = codec.EncodeMessage(msg, nil)

		if err != nil {
			return err
		}

		msgID = meta.ID
	}

	pkt := make([]byte, MsgIDSize+len(msgData))
	binary.LittleEndian.PutUint16(pkt, uint16(msgID))
	copy(pkt[MsgIDSize:], msgData)

	conn.WriteMessage(websocket.BinaryMessage, pkt)

	return nil
}
<|endoftext|>


<commit_before>package processors

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strings"
	"text/template"

	"github.com/fsouza/go-dockerclient"
	"github.com/rehabstudio/oneill/oneill"
)

const (
	nginxTemplate string = `
        upstream {{.Subdomain}} {
          server localhost:{{.Port}};
        }

        server {
          listen *:80;
          server_name {{.Subdomain}}.{{.ServingDomain}};
          return 301 https://$server_name$request_uri;
        }

        server {
          listen 443;
          server_name {{.Subdomain}}.{{.ServingDomain}};

          ssl on;
          ssl_certificate /etc/ssl/certs/labs-server.crt;
          ssl_certificate_key /etc/ssl/private/labs-server.pem;
          ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
          ssl_session_timeout 5m;
          ssl_session_cache shared:SSL:5m;

          client_max_body_size 0; # disable any limits to avoid HTTP 413 for large image uploads

          # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
          chunked_transfer_encoding on;

          location / {
            proxy_pass                       http://{{.Subdomain}};
            proxy_set_header  Host           $http_host;   # required for docker client's sake
            proxy_set_header  X-Real-IP      $remote_addr; # pass on real client's IP
            proxy_read_timeout               900;
          }

        }
`
)

func ensureFreshOutputDir() {
	oneill.LogDebug("Recreating empty configuration directory")
	outDir := oneill.Config.NginxConfigDirectory
	err := os.RemoveAll(outDir)
	if err != nil {
		panic(err)
	}
	err = os.Mkdir(outDir, 0755)
	if err != nil {
		panic(err)
	}
}

func reloadNginxConfig() error {
	runCmd := exec.Command("service", "nginx", "reload")
	return runCmd.Run()
}

type templateContext struct {
	Subdomain     string
	ServingDomain string
	Port          int64
}

func writeTemplateToDisk(siteConfig *oneill.SiteConfig, container docker.APIContainers) {
	tmpl, err := template.New("nginx-config").Parse(nginxTemplate)
	if err != nil {
		oneill.LogWarning(fmt.Sprintf("Unable to load nginx config template: %s", siteConfig.Subdomain))
		return
	}

	var b bytes.Buffer
	context := templateContext{
		Subdomain:     siteConfig.Subdomain,
		ServingDomain: oneill.Config.ServingDomain,
		Port:          container.Ports[0].PublicPort,
	}
	err = tmpl.Execute(&b, context)
	if err != nil {
		oneill.LogWarning(fmt.Sprintf("Unable to execute nginx config template: %s", siteConfig.Subdomain))
		return
	}
	outDir := oneill.Config.NginxConfigDirectory
	outFile := path.Join(outDir, fmt.Sprintf("%s.conf", siteConfig.Subdomain))
	err = ioutil.WriteFile(outFile, b.Bytes(), 0644)
	if err != nil {
		oneill.LogWarning(fmt.Sprintf("Unable to write nginx config template: %s", siteConfig.Subdomain))
		return
	}
}

func ConfigureNginx(siteConfigs []*oneill.SiteConfig) []*oneill.SiteConfig {
	oneill.LogInfo("## Configuring Nginx")

	ensureFreshOutputDir()

	for _, sc := range siteConfigs {
		for _, container := range oneill.ListContainers() {
			containerName := strings.TrimPrefix(container.Names[0], "/")
			if containerName == sc.Subdomain {
				writeTemplateToDisk(sc, container)
				oneill.LogDebug(fmt.Sprintf("Configured nginx proxy for container: %s", sc.Subdomain))
				break
			}
		}
	}
	if err := reloadNginxConfig(); err != nil {
		panic(err)
	}
	return siteConfigs
}
<commit_msg>don't panic when unable to reload nginx config<commit_after>package processors

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strings"
	"text/template"

	"github.com/fsouza/go-dockerclient"
	"github.com/rehabstudio/oneill/oneill"
)

const (
	nginxTemplate string = `
        upstream {{.Subdomain}} {
          server localhost:{{.Port}};
        }

        server {
          listen *:80;
          server_name {{.Subdomain}}.{{.ServingDomain}};
          return 301 https://$server_name$request_uri;
        }

        server {
          listen 443;
          server_name {{.Subdomain}}.{{.ServingDomain}};

          ssl on;
          ssl_certificate /etc/ssl/certs/labs-server.crt;
          ssl_certificate_key /etc/ssl/private/labs-server.pem;
          ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
          ssl_session_timeout 5m;
          ssl_session_cache shared:SSL:5m;

          client_max_body_size 0; # disable any limits to avoid HTTP 413 for large image uploads

          # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
          chunked_transfer_encoding on;

          location / {
            proxy_pass                       http://{{.Subdomain}};
            proxy_set_header  Host           $http_host;   # required for docker client's sake
            proxy_set_header  X-Real-IP      $remote_addr; # pass on real client's IP
            proxy_read_timeout               900;
          }

        }
`
)

func ensureFreshOutputDir() {
	oneill.LogDebug("Recreating empty configuration directory")
	outDir := oneill.Config.NginxConfigDirectory
	err := os.RemoveAll(outDir)
	if err != nil {
		panic(err)
	}
	err = os.Mkdir(outDir, 0755)
	if err != nil {
		panic(err)
	}
}

func reloadNginxConfig() error {
	runCmd := exec.Command("service", "nginx", "reload")
	return runCmd.Run()
}

type templateContext struct {
	Subdomain     string
	ServingDomain string
	Port          int64
}

func writeTemplateToDisk(siteConfig *oneill.SiteConfig, container docker.APIContainers) {
	tmpl, err := template.New("nginx-config").Parse(nginxTemplate)
	if err != nil {
		oneill.LogWarning(fmt.Sprintf("Unable to load nginx config template: %s", siteConfig.Subdomain))
		return
	}

	var b bytes.Buffer
	context := templateContext{
		Subdomain:     siteConfig.Subdomain,
		ServingDomain: oneill.Config.ServingDomain,
		Port:          container.Ports[0].PublicPort,
	}
	err = tmpl.Execute(&b, context)
	if err != nil {
		oneill.LogWarning(fmt.Sprintf("Unable to execute nginx config template: %s", siteConfig.Subdomain))
		return
	}
	outDir := oneill.Config.NginxConfigDirectory
	outFile := path.Join(outDir, fmt.Sprintf("%s.conf", siteConfig.Subdomain))
	err = ioutil.WriteFile(outFile, b.Bytes(), 0644)
	if err != nil {
		oneill.LogWarning(fmt.Sprintf("Unable to write nginx config template: %s", siteConfig.Subdomain))
		return
	}
}

func ConfigureNginx(siteConfigs []*oneill.SiteConfig) []*oneill.SiteConfig {
	oneill.LogInfo("## Configuring Nginx")

	ensureFreshOutputDir()

	for _, sc := range siteConfigs {
		for _, container := range oneill.ListContainers() {
			containerName := strings.TrimPrefix(container.Names[0], "/")
			if containerName == sc.Subdomain {
				writeTemplateToDisk(sc, container)
				oneill.LogDebug(fmt.Sprintf("Configured nginx proxy for container: %s", sc.Subdomain))
				break
			}
		}
	}
	if err := reloadNginxConfig(); err != nil {
		oneill.LogWarning("Unable to reload nginx configuration")
		return siteConfigs
	}
	oneill.LogDebug("Reloaded nginx configuration")
	return siteConfigs
}
<|endoftext|>


<commit_before>package processors

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strings"
	"text/template"

	"github.com/fsouza/go-dockerclient"
	"github.com/rehabstudio/oneill/oneill"
)

const (
	nginxTemplate string = `
        upstream {{.Subdomain}} {
          server localhost:{{.Port}};
        }

        server {
          listen *:80;
          server_name {{.Subdomain}}.{{.ServingDomain}};
          return 301 https://$server_name$request_uri;
        }

        server {
          listen 443;
          server_name {{.Subdomain}}.{{.ServingDomain}};

          ssl on;
          ssl_certificate /etc/ssl/certs/labs-server.crt;
          ssl_certificate_key /etc/ssl/private/labs-server.pem;
          ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
          ssl_session_timeout 5m;
          ssl_session_cache shared:SSL:5m;

          client_max_body_size 0; # disable any limits to avoid HTTP 413 for large image uploads

          # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
          chunked_transfer_encoding on;

          location / {
            proxy_pass                       http://{{.Subdomain}};
            proxy_set_header  Host           $http_host;   # required for docker client's sake
            proxy_set_header  X-Real-IP      $remote_addr; # pass on real client's IP
            proxy_read_timeout               900;
          }

        }
`
)

func ensureFreshOutputDir() {
	oneill.LogDebug("Recreating empty configuration directory")
	outDir := oneill.Config.NginxConfigDirectory
	err := os.RemoveAll(outDir)
	if err != nil {
		panic(err)
	}
	err = os.Mkdir(outDir, 0755)
	if err != nil {
		panic(err)
	}
}

func reloadNginxConfig() error {
	runCmd := exec.Command("service", "nginx", "reload")
	return runCmd.Run()
}

type templateContext struct {
	Subdomain     string
	ServingDomain string
	Port          int64
}

func writeTemplateToDisk(siteConfig *oneill.SiteConfig, container docker.APIContainers) {
	tmpl, err := template.New("nginx-config").Parse(nginxTemplate)
	if err != nil {
		panic(err)
	}

	var b bytes.Buffer
	context := templateContext{
		Subdomain:     siteConfig.Subdomain,
		ServingDomain: oneill.Config.ServingDomain,
		Port:          container.Ports[0].PublicPort,
	}
	err = tmpl.Execute(&b, context)
	if err != nil {
		panic(err)
	}
	outDir := oneill.Config.NginxConfigDirectory
	outFile := path.Join(outDir, fmt.Sprintf("%s.conf", siteConfig.Subdomain))
	err = ioutil.WriteFile(outFile, b.Bytes(), 0644)
	if err != nil {
		panic(err)
	}
}

func ConfigureNginx(siteConfigs []*oneill.SiteConfig) []*oneill.SiteConfig {
	oneill.LogInfo("## Configuring Nginx")

	ensureFreshOutputDir()

	for _, sc := range siteConfigs {
		for _, container := range oneill.ListContainers() {
			containerName := strings.TrimPrefix(container.Names[0], "/")
			if containerName == sc.Subdomain {
				writeTemplateToDisk(sc, container)
				oneill.LogDebug(fmt.Sprintf("Configured nginx proxy for container: %s", sc.Subdomain))
				break
			}
		}
	}
	if err := reloadNginxConfig(); err != nil {
		panic(err)
	}
	return siteConfigs
}
<commit_msg>don't panic when unable to write nginx config file<commit_after>package processors

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strings"
	"text/template"

	"github.com/fsouza/go-dockerclient"
	"github.com/rehabstudio/oneill/oneill"
)

const (
	nginxTemplate string = `
        upstream {{.Subdomain}} {
          server localhost:{{.Port}};
        }

        server {
          listen *:80;
          server_name {{.Subdomain}}.{{.ServingDomain}};
          return 301 https://$server_name$request_uri;
        }

        server {
          listen 443;
          server_name {{.Subdomain}}.{{.ServingDomain}};

          ssl on;
          ssl_certificate /etc/ssl/certs/labs-server.crt;
          ssl_certificate_key /etc/ssl/private/labs-server.pem;
          ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
          ssl_session_timeout 5m;
          ssl_session_cache shared:SSL:5m;

          client_max_body_size 0; # disable any limits to avoid HTTP 413 for large image uploads

          # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
          chunked_transfer_encoding on;

          location / {
            proxy_pass                       http://{{.Subdomain}};
            proxy_set_header  Host           $http_host;   # required for docker client's sake
            proxy_set_header  X-Real-IP      $remote_addr; # pass on real client's IP
            proxy_read_timeout               900;
          }

        }
`
)

func ensureFreshOutputDir() {
	oneill.LogDebug("Recreating empty configuration directory")
	outDir := oneill.Config.NginxConfigDirectory
	err := os.RemoveAll(outDir)
	if err != nil {
		panic(err)
	}
	err = os.Mkdir(outDir, 0755)
	if err != nil {
		panic(err)
	}
}

func reloadNginxConfig() error {
	runCmd := exec.Command("service", "nginx", "reload")
	return runCmd.Run()
}

type templateContext struct {
	Subdomain     string
	ServingDomain string
	Port          int64
}

func writeTemplateToDisk(siteConfig *oneill.SiteConfig, container docker.APIContainers) {
	tmpl, err := template.New("nginx-config").Parse(nginxTemplate)
	if err != nil {
		oneill.LogWarning(fmt.Sprintf("Unable to load nginx config template: %s", siteConfig.Subdomain))
		return
	}

	var b bytes.Buffer
	context := templateContext{
		Subdomain:     siteConfig.Subdomain,
		ServingDomain: oneill.Config.ServingDomain,
		Port:          container.Ports[0].PublicPort,
	}
	err = tmpl.Execute(&b, context)
	if err != nil {
		oneill.LogWarning(fmt.Sprintf("Unable to execute nginx config template: %s", siteConfig.Subdomain))
		return
	}
	outDir := oneill.Config.NginxConfigDirectory
	outFile := path.Join(outDir, fmt.Sprintf("%s.conf", siteConfig.Subdomain))
	err = ioutil.WriteFile(outFile, b.Bytes(), 0644)
	if err != nil {
		oneill.LogWarning(fmt.Sprintf("Unable to write nginx config template: %s", siteConfig.Subdomain))
		return
	}
}

func ConfigureNginx(siteConfigs []*oneill.SiteConfig) []*oneill.SiteConfig {
	oneill.LogInfo("## Configuring Nginx")

	ensureFreshOutputDir()

	for _, sc := range siteConfigs {
		for _, container := range oneill.ListContainers() {
			containerName := strings.TrimPrefix(container.Names[0], "/")
			if containerName == sc.Subdomain {
				writeTemplateToDisk(sc, container)
				oneill.LogDebug(fmt.Sprintf("Configured nginx proxy for container: %s", sc.Subdomain))
				break
			}
		}
	}
	if err := reloadNginxConfig(); err != nil {
		panic(err)
	}
	return siteConfigs
}
<|endoftext|>


<commit_before>package flux

import (
	"log"
	"sync"
	"sync/atomic"
	"time"
)

//WaitInterface defines the flux.Wait interface method definitions
type WaitInterface interface {
	Add()
	Done()
	Count() int
	Flush()
	Then() ActionInterface
}

//ResetTimer runs a timer and performs an action
type ResetTimer struct {
	reset    chan struct{}
	kill     chan struct{}
	duration time.Duration
	do       *sync.Once
	init     func()
	done     func()
	state    int64
}

//NewResetTimer returns a new reset timer
func NewResetTimer(init func(), done func(), d time.Duration) *ResetTimer {
	rs := &ResetTimer{
		reset:    make(chan struct{}),
		kill:     make(chan struct{}),
		duration: d,
		do:       new(sync.Once),
		init:     init,
		done:     done,
		state:    1,
	}

	rs.init()
	rs.handle()
	return rs
}

//Add reset the timer threshold
func (r *ResetTimer) Add() {
	if r.do == nil {
		return
	}

	state := atomic.LoadInt64(&r.state)
	if state <= 0 {
		atomic.StoreInt64(&r.state, 1)
		r.init()
		r.handle()
	} else {
		r.reset <- struct{}{}
	}
}

//Close closes this timer
func (r *ResetTimer) Close() {
	defer func() { r.do = nil }()
	r.do.Do(func() {
		close(r.kill)
		close(r.reset)
	})
}

func (r *ResetTimer) makeTime() <-chan time.Time {
	return time.After(r.duration)
}

func (r *ResetTimer) handle() {
	go func() {
		threshold := r.makeTime()
	resetloop:
		for {
			select {
			case <-r.reset:
				threshold = r.makeTime()
			case <-threshold:
				atomic.StoreInt64(&r.state, 0)
				r.done()
				break resetloop
			case <-r.kill:
				atomic.StoreInt64(&r.state, 0)
				break resetloop
			}
		}

	}()
}

//SwitchInterface defines a flux.Switch interface method definition
type SwitchInterface interface {
	Switch()
	IsOn() bool
	WhenOn() ActionInterface
	WhenOff() ActionInterface
}

//WaitGen is a nice way of creating regenerative timers for use
//wait timers are once timers, once they are clocked out they are of no more use,to allow their nature which has its benefits we get to create WaitGen that generates a new once once a wait gen is over
type WaitGen struct {
	current WaitInterface
	gen     func() WaitInterface
}

//Make returns a new WaitInterface or returns the current once
func (w *WaitGen) Make() WaitInterface {
	if w.current != nil {
		return w.current
	}
	wt := w.gen()
	wt.Then().WhenOnly(func(_ interface{}) {
		w.current = nil
	})
	return wt
}

//NewTimeWaitGen returns a wait generator making a timewaiter
func NewTimeWaitGen(steps int, ms time.Duration, init func(WaitInterface)) *WaitGen {
	return &WaitGen{
		nil,
		func() WaitInterface {
			nt := NewTimeWait(steps, ms)
			init(nt)
			return nt
		},
	}
}

//NewSimpleWaitGen returns a wait generator making a timewaiter
func NewSimpleWaitGen(init func(WaitInterface)) *WaitGen {
	return &WaitGen{
		nil,
		func() WaitInterface {
			nt := NewWait()
			init(nt)
			return nt
		},
	}
}

//baseWait defines the base wait structure for all waiters
type baseWait struct {
	action ActionInterface
}

//Then returns an ActionInterface which gets fullfilled when this wait
//counter reaches zero
func (w *baseWait) Then() ActionInterface {
	return w.action.Wrap()
}

func newBaseWait() *baseWait {
	return &baseWait{NewAction()}
}

//TimeWait defines a time lock waiter
type TimeWait struct {
	*baseWait
	closer chan struct{}
	hits   int64
	max    int
	ms     time.Duration
	doonce *sync.Once
}

//NewTimeWait returns a new timer wait locker
//You specifiy two arguments:
//max int: the maximum number of time you want to check for idleness
//duration time.Duration: the time to check for each idle times and reduce
//until zero is reached then close
//eg. to do a 15seconds check for idleness
//NewTimeWait(15,time.Duration(1)*time.Second)
//eg. to do a 25 maximum check before closing per minute
//NewTimeWait(15,time.Duration(1)*time.Minute)
func NewTimeWait(max int, duration time.Duration) *TimeWait {

	tm := &TimeWait{
		newBaseWait(),
		make(chan struct{}),
		int64(max),
		max,
		duration,
		new(sync.Once),
	}

	// tm.Add()
	go tm.handle()

	return tm
}

//handle effects the necessary time process for checking and reducing the
//time checker for each duration of time,till the Waiter is done
func (w *TimeWait) handle() {
	var state int64
	atomic.StoreInt64(&state, 0)

	go func() {
		<-w.closer
		atomic.StoreInt64(&state, 1)
	}()

	for {
		time.Sleep(w.ms)

		bit := atomic.LoadInt64(&state)
		if bit > 0 {
			break
		}

		w.Done()
	}
}

//Flush drops the lock count and forces immediate unlocking of the wait
func (w *TimeWait) Flush() {
	w.doonce.Do(func() {
		close(w.closer)
		w.action.Fullfill(0)
		atomic.StoreInt64(&w.hits, 0)
	})
}

//Count returns the total left count to completed before unlock
func (w *TimeWait) Count() int {
	return int(atomic.LoadInt64(&w.hits))
}

//Add increments the lock state to the lock counter unless its already unlocked
func (w *TimeWait) Add() {
	if w.Count() < 0 || w.Count() >= w.max {
		return
	}

	atomic.AddInt64(&w.hits, 1)
}

//Done decrements the totalcount of this waitlocker by 1 until its below zero
//and fullfills with the 0 value
func (w *TimeWait) Done() {
	hits := atomic.LoadInt64(&w.hits)

	if hits < 0 {
		return
	}

	newhit := atomic.AddInt64(&w.hits, -1)
	log.Printf("TimeWait: Count Down now %d before %d!", newhit, hits)
	if int(newhit) <= 0 {
		w.Flush()
		log.Printf("TimeWait: Count Down Finished!")
	}
}

//Wait implements the WiatInterface for creating a wait lock which
//waits until the lock lockcount is finished then executes a action
//can only be used once, that is ,once the wait counter is -1,you cant add
//to it anymore
type Wait struct {
	*baseWait
	totalCount int64
}

//NewWait returns a new Wait instance for the WaitInterface
func NewWait() WaitInterface {
	return &Wait{newBaseWait(), int64(0)}
}

//Flush drops the lock count and forces immediate unlocking of the wait
func (w *Wait) Flush() {
	curr := int(atomic.LoadInt64(&w.totalCount))
	if curr < 0 {
		return
	}

	atomic.StoreInt64(&w.totalCount, 0)
	w.Done()
}

//Count returns the total left count to completed before unlock
func (w *Wait) Count() int {
	return int(atomic.LoadInt64(&w.totalCount))
}

//Add increments the lock state to the lock counter unless its already unlocked
func (w *Wait) Add() {
	curr := atomic.LoadInt64(&w.totalCount)

	if curr < 0 {
		return
	}

	atomic.AddInt64(&w.totalCount, 1)
}

//Done decrements the totalcount of this waitlocker by 1 until its below zero
//and fullfills with the 0 value
func (w *Wait) Done() {
	curr := atomic.LoadInt64(&w.totalCount)

	if curr < 0 {
		return
	}

	nc := atomic.AddInt64(&w.totalCount, -1)
	// log.Printf("Wait: Count Down now %d before %d", nc, curr)

	if int(nc) <= 0 {
		w.action.Fullfill(0)
	}
}
<commit_msg>adding resettimer<commit_after>package flux

import (
	"log"
	"sync"
	"sync/atomic"
	"time"
)

//WaitInterface defines the flux.Wait interface method definitions
type WaitInterface interface {
	Add()
	Done()
	Count() int
	Flush()
	Then() ActionInterface
}

//ResetTimer runs a timer and performs an action
type ResetTimer struct {
	reset    chan struct{}
	kill     chan struct{}
	duration time.Duration
	do       *sync.Once
	init     func()
	done     func()
	state    int64
}

//NewResetTimer returns a new reset timer
func NewResetTimer(init func(), done func(), d time.Duration) *ResetTimer {
	rs := &ResetTimer{
		reset:    make(chan struct{}),
		kill:     make(chan struct{}),
		duration: d,
		do:       new(sync.Once),
		init:     init,
		done:     done,
		state:    1,
	}

	rs.init()
	rs.handle()
	return rs
}

//Add reset the timer threshold
func (r *ResetTimer) Add() {
	if r.do == nil {
		return
	}

	state := atomic.LoadInt64(&r.state)
	if state <= 0 {
		atomic.StoreInt64(&r.state, 1)
		r.init()
		r.handle()
	} else {
		r.reset <- struct{}{}
	}
}

//Close closes this timer
func (r *ResetTimer) Close() {
	defer func() { r.do = nil }()
	r.do.Do(func() {
		close(r.kill)
		close(r.reset)
	})
}

func (r *ResetTimer) makeTime() <-chan time.Time {
	return time.After(r.duration)
}

func (r *ResetTimer) handle() {
	go func() {
		threshold := r.makeTime()
	resetloop:
		for {
			select {
			case <-r.reset:
				threshold = r.makeTime()
			case <-threshold:
				atomic.StoreInt64(&r.state, 0)
				r.done()
				break resetloop
			case <-r.kill:
				atomic.StoreInt64(&r.state, 0)
				r.done()
				break resetloop
			}
		}

	}()
}

//SwitchInterface defines a flux.Switch interface method definition
type SwitchInterface interface {
	Switch()
	IsOn() bool
	WhenOn() ActionInterface
	WhenOff() ActionInterface
}

//WaitGen is a nice way of creating regenerative timers for use
//wait timers are once timers, once they are clocked out they are of no more use,to allow their nature which has its benefits we get to create WaitGen that generates a new once once a wait gen is over
type WaitGen struct {
	current WaitInterface
	gen     func() WaitInterface
}

//Make returns a new WaitInterface or returns the current once
func (w *WaitGen) Make() WaitInterface {
	if w.current != nil {
		return w.current
	}
	wt := w.gen()
	wt.Then().WhenOnly(func(_ interface{}) {
		w.current = nil
	})
	return wt
}

//NewTimeWaitGen returns a wait generator making a timewaiter
func NewTimeWaitGen(steps int, ms time.Duration, init func(WaitInterface)) *WaitGen {
	return &WaitGen{
		nil,
		func() WaitInterface {
			nt := NewTimeWait(steps, ms)
			init(nt)
			return nt
		},
	}
}

//NewSimpleWaitGen returns a wait generator making a timewaiter
func NewSimpleWaitGen(init func(WaitInterface)) *WaitGen {
	return &WaitGen{
		nil,
		func() WaitInterface {
			nt := NewWait()
			init(nt)
			return nt
		},
	}
}

//baseWait defines the base wait structure for all waiters
type baseWait struct {
	action ActionInterface
}

//Then returns an ActionInterface which gets fullfilled when this wait
//counter reaches zero
func (w *baseWait) Then() ActionInterface {
	return w.action.Wrap()
}

func newBaseWait() *baseWait {
	return &baseWait{NewAction()}
}

//TimeWait defines a time lock waiter
type TimeWait struct {
	*baseWait
	closer chan struct{}
	hits   int64
	max    int
	ms     time.Duration
	doonce *sync.Once
}

//NewTimeWait returns a new timer wait locker
//You specifiy two arguments:
//max int: the maximum number of time you want to check for idleness
//duration time.Duration: the time to check for each idle times and reduce
//until zero is reached then close
//eg. to do a 15seconds check for idleness
//NewTimeWait(15,time.Duration(1)*time.Second)
//eg. to do a 25 maximum check before closing per minute
//NewTimeWait(15,time.Duration(1)*time.Minute)
func NewTimeWait(max int, duration time.Duration) *TimeWait {

	tm := &TimeWait{
		newBaseWait(),
		make(chan struct{}),
		int64(max),
		max,
		duration,
		new(sync.Once),
	}

	// tm.Add()
	go tm.handle()

	return tm
}

//handle effects the necessary time process for checking and reducing the
//time checker for each duration of time,till the Waiter is done
func (w *TimeWait) handle() {
	var state int64
	atomic.StoreInt64(&state, 0)

	go func() {
		<-w.closer
		atomic.StoreInt64(&state, 1)
	}()

	for {
		time.Sleep(w.ms)

		bit := atomic.LoadInt64(&state)
		if bit > 0 {
			break
		}

		w.Done()
	}
}

//Flush drops the lock count and forces immediate unlocking of the wait
func (w *TimeWait) Flush() {
	w.doonce.Do(func() {
		close(w.closer)
		w.action.Fullfill(0)
		atomic.StoreInt64(&w.hits, 0)
	})
}

//Count returns the total left count to completed before unlock
func (w *TimeWait) Count() int {
	return int(atomic.LoadInt64(&w.hits))
}

//Add increments the lock state to the lock counter unless its already unlocked
func (w *TimeWait) Add() {
	if w.Count() < 0 || w.Count() >= w.max {
		return
	}

	atomic.AddInt64(&w.hits, 1)
}

//Done decrements the totalcount of this waitlocker by 1 until its below zero
//and fullfills with the 0 value
func (w *TimeWait) Done() {
	hits := atomic.LoadInt64(&w.hits)

	if hits < 0 {
		return
	}

	newhit := atomic.AddInt64(&w.hits, -1)
	log.Printf("TimeWait: Count Down now %d before %d!", newhit, hits)
	if int(newhit) <= 0 {
		w.Flush()
		log.Printf("TimeWait: Count Down Finished!")
	}
}

//Wait implements the WiatInterface for creating a wait lock which
//waits until the lock lockcount is finished then executes a action
//can only be used once, that is ,once the wait counter is -1,you cant add
//to it anymore
type Wait struct {
	*baseWait
	totalCount int64
}

//NewWait returns a new Wait instance for the WaitInterface
func NewWait() WaitInterface {
	return &Wait{newBaseWait(), int64(0)}
}

//Flush drops the lock count and forces immediate unlocking of the wait
func (w *Wait) Flush() {
	curr := int(atomic.LoadInt64(&w.totalCount))
	if curr < 0 {
		return
	}

	atomic.StoreInt64(&w.totalCount, 0)
	w.Done()
}

//Count returns the total left count to completed before unlock
func (w *Wait) Count() int {
	return int(atomic.LoadInt64(&w.totalCount))
}

//Add increments the lock state to the lock counter unless its already unlocked
func (w *Wait) Add() {
	curr := atomic.LoadInt64(&w.totalCount)

	if curr < 0 {
		return
	}

	atomic.AddInt64(&w.totalCount, 1)
}

//Done decrements the totalcount of this waitlocker by 1 until its below zero
//and fullfills with the 0 value
func (w *Wait) Done() {
	curr := atomic.LoadInt64(&w.totalCount)

	if curr < 0 {
		return
	}

	nc := atomic.AddInt64(&w.totalCount, -1)
	// log.Printf("Wait: Count Down now %d before %d", nc, curr)

	if int(nc) <= 0 {
		w.action.Fullfill(0)
	}
}
<|endoftext|>


<commit_before>// worker.go - mixnet client worker
// Copyright (C) 2018, 2019  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 (
	"errors"
	"math"
	"time"

	"github.com/katzenpost/client/constants"
	cConstants "github.com/katzenpost/client/constants"
	"github.com/katzenpost/client/utils"
	"github.com/katzenpost/core/crypto/rand"
	"github.com/katzenpost/core/pki"
	mrand "math/rand"
)

type workerOp interface{}

type opConnStatusChanged struct {
	isConnected bool
}

type opNewDocument struct {
	doc *pki.Document
}

func (s *Session) connStatusChange(op opConnStatusChanged) bool {
	isConnected := op.isConnected
	if isConnected {
		s.onlineAt = time.Now()

		skew := s.minclient.ClockSkew()
		absSkew := skew
		if absSkew < 0 {
			absSkew = -absSkew
		}
		if absSkew > constants.TimeSkewWarnDelta {
			// Should this do more than just warn?  Should this
			// use skewed time?  I don't know.
			s.log.Warningf("The observed time difference between the host and provider clocks is '%v'. Correct your system time.", skew)
		} else {
			s.log.Debugf("Clock skew vs provider: %v", skew)
		}
	}
	return isConnected
}

func (s *Session) worker() {
	const maxDuration = math.MaxInt64
	mRng := rand.NewMath()
	// The PKI doc should be cached since we've
	// already waited until we received it.
	doc := s.minclient.CurrentDocument()
	if doc == nil {
		s.fatalErrCh <- errors.New("aborting, PKI doc is nil")
		return
	}

	// get the initial loop services if decoy traffic is enabled
	var loopServices []utils.ServiceDescriptor
	if !s.cfg.Debug.DisableDecoyTraffic {
		loopServices = utils.FindServices(cConstants.LoopService, doc)
		if len(loopServices) == 0 {
			s.fatalErrCh <- errors.New("failure to get loop service")
			return
		}
	}

	// LambdaP timer setup
	lambdaP := doc.LambdaP
	lambdaPMsec := uint64(rand.Exp(mRng, lambdaP))
	if lambdaPMsec > doc.LambdaPMaxDelay {
		lambdaPMsec = doc.LambdaPMaxDelay
	}
	lambdaPInterval := time.Duration(lambdaPMsec) * time.Millisecond
	lambdaPTimer := time.NewTimer(lambdaPInterval)
	defer lambdaPTimer.Stop()

	// LambdaL timer setup
	lambdaL := doc.LambdaL
	lambdaLMsec := uint64(rand.Exp(mRng, lambdaL))
	if lambdaLMsec > doc.LambdaLMaxDelay {
		lambdaLMsec = doc.LambdaLMaxDelay
	}
	lambdaLInterval := time.Duration(lambdaLMsec) * time.Millisecond
	lambdaLTimer := time.NewTimer(lambdaLInterval)
	defer lambdaLTimer.Stop()

	// LambdaD timer setup
	lambdaD := doc.LambdaD
	lambdaDMsec := uint64(rand.Exp(mRng, lambdaD))
	if lambdaDMsec > doc.LambdaDMaxDelay {
		lambdaDMsec = doc.LambdaDMaxDelay
	}
	lambdaDInterval := time.Duration(lambdaDMsec) * time.Millisecond
	lambdaDTimer := time.NewTimer(lambdaDInterval)
	defer lambdaDTimer.Stop()

	defer s.log.Debug("session worker halted")

	isConnected := false
	mustResetAllTimers := false
	for {
		var lambdaPFired bool
		var lambdaLFired bool
		var lambdaDFired bool
		var loopSvc *utils.ServiceDescriptor
		var qo workerOp

		select {
		case <-s.HaltCh():
			s.log.Debugf("Session worker terminating gracefully.")
			return
		case <-lambdaPTimer.C:
			lambdaPFired = true
		case <-lambdaLTimer.C:
			lambdaLFired = true
		case <-lambdaDTimer.C:
			lambdaDFired = true
		case qo = <-s.opCh:
		}

		if qo != nil {
			switch op := qo.(type) {
			case opConnStatusChanged:
				newConnectedStatus := s.connStatusChange(op)
				isConnected = newConnectedStatus
				mustResetAllTimers = true
			case opNewDocument:
				err := s.isDocValid(op.doc)
				if err != nil {
					s.fatalErrCh <- err
				}

				doc = op.doc
				s.setPollIntervalFromDoc(doc)
				lambdaP = doc.LambdaP
				lambdaL = doc.LambdaL
				lambdaD = doc.LambdaD

				// update the loop service descriptors
				loopServices = utils.FindServices(cConstants.LoopService, doc)
				if len(loopServices) == 0 {
					s.fatalErrCh <- errors.New("failure to get loop service")
					return
				}

				mustResetAllTimers = true
			default:
				s.log.Warningf("BUG: Worker received nonsensical op: %T", op)
			} // end of switch
		} else {
			if isConnected {
				// select a loop service endpoint
				if !s.cfg.Debug.DisableDecoyTraffic {
					loopSvc = &loopServices[mrand.Intn(len(loopServices))]
				}
				if lambdaPFired {
					s.sendFromQueueOrDecoy(loopSvc)
				} else if lambdaLFired && !s.cfg.Debug.DisableDecoyTraffic {
					s.sendLoopDecoy(loopSvc)
				} else if lambdaDFired && !s.cfg.Debug.DisableDecoyTraffic {
					loopSvc = &loopServices[mrand.Intn(len(loopServices))]
					s.sendDropDecoy(loopSvc)
				}
			}
		}
		if isConnected {
			lambdaPMsec := uint64(rand.Exp(mRng, lambdaP))
			if lambdaPMsec > doc.LambdaPMaxDelay {
				lambdaPMsec = doc.LambdaPMaxDelay
			}
			lambdaPInterval = time.Duration(lambdaPMsec) * time.Millisecond
			lambdaLMsec := uint64(rand.Exp(mRng, lambdaL))
			if lambdaLMsec > doc.LambdaLMaxDelay {
				lambdaLMsec = doc.LambdaLMaxDelay
			}
			lambdaLInterval = time.Duration(lambdaLMsec) * time.Millisecond
			lambdaDMsec := uint64(rand.Exp(mRng, lambdaD))
			if lambdaDMsec > doc.LambdaDMaxDelay {
				lambdaDMsec = doc.LambdaDMaxDelay
			}
			lambdaDInterval = time.Duration(lambdaDMsec) * time.Millisecond
		} else {
			lambdaLInterval = time.Duration(maxDuration)
			lambdaPInterval = time.Duration(maxDuration)
			lambdaDInterval = time.Duration(maxDuration)
		}

		if mustResetAllTimers {
			lambdaPTimer.Reset(lambdaPInterval)
			lambdaLTimer.Reset(lambdaLInterval)
			lambdaDTimer.Reset(lambdaDInterval)
			mustResetAllTimers = false
		} else {
			// reset only the timer that fired
			if lambdaPFired {
				lambdaPTimer.Reset(lambdaPInterval)
			}
			if lambdaLFired {
				lambdaLTimer.Reset(lambdaLInterval)
			}
			if lambdaDFired {
				lambdaDTimer.Reset(lambdaDInterval)
			}
		}
	}

	// NOTREACHED
}

func (s *Session) sendFromQueueOrDecoy(loopSvc *utils.ServiceDescriptor) {
	// Attempt to send user data first, if any exists.
	// Otherwise send a drop decoy message.
	_, err := s.egressQueue.Peek()
	if err == nil {
		s.sendNext()
	} else if !s.cfg.Debug.DisableDecoyTraffic {
		s.sendDropDecoy(loopSvc)
	}
}

func (s *Session) isDocValid(doc *pki.Document) error {
	for _, provider := range doc.Providers {
		_, ok := provider.Kaetzchen[constants.LoopService]
		if !ok {
			return errors.New("found a Provider which does not have the loop service")
		}
	}
	return nil
}

func (s *Session) setPollIntervalFromDoc(doc *pki.Document) {
	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)
}
<commit_msg>send loops not drops for receiver unobservability<commit_after>// worker.go - mixnet client worker
// Copyright (C) 2018, 2019  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 (
	"errors"
	"math"
	"time"

	"github.com/katzenpost/client/constants"
	cConstants "github.com/katzenpost/client/constants"
	"github.com/katzenpost/client/utils"
	"github.com/katzenpost/core/crypto/rand"
	"github.com/katzenpost/core/pki"
	mrand "math/rand"
)

type workerOp interface{}

type opConnStatusChanged struct {
	isConnected bool
}

type opNewDocument struct {
	doc *pki.Document
}

func (s *Session) connStatusChange(op opConnStatusChanged) bool {
	isConnected := op.isConnected
	if isConnected {
		s.onlineAt = time.Now()

		skew := s.minclient.ClockSkew()
		absSkew := skew
		if absSkew < 0 {
			absSkew = -absSkew
		}
		if absSkew > constants.TimeSkewWarnDelta {
			// Should this do more than just warn?  Should this
			// use skewed time?  I don't know.
			s.log.Warningf("The observed time difference between the host and provider clocks is '%v'. Correct your system time.", skew)
		} else {
			s.log.Debugf("Clock skew vs provider: %v", skew)
		}
	}
	return isConnected
}

func (s *Session) worker() {
	const maxDuration = math.MaxInt64
	mRng := rand.NewMath()
	// The PKI doc should be cached since we've
	// already waited until we received it.
	doc := s.minclient.CurrentDocument()
	if doc == nil {
		s.fatalErrCh <- errors.New("aborting, PKI doc is nil")
		return
	}

	// get the initial loop services if decoy traffic is enabled
	var loopServices []utils.ServiceDescriptor
	if !s.cfg.Debug.DisableDecoyTraffic {
		loopServices = utils.FindServices(cConstants.LoopService, doc)
		if len(loopServices) == 0 {
			s.fatalErrCh <- errors.New("failure to get loop service")
			return
		}
	}

	// LambdaP timer setup
	lambdaP := doc.LambdaP
	lambdaPMsec := uint64(rand.Exp(mRng, lambdaP))
	if lambdaPMsec > doc.LambdaPMaxDelay {
		lambdaPMsec = doc.LambdaPMaxDelay
	}
	lambdaPInterval := time.Duration(lambdaPMsec) * time.Millisecond
	lambdaPTimer := time.NewTimer(lambdaPInterval)
	defer lambdaPTimer.Stop()

	// LambdaL timer setup
	lambdaL := doc.LambdaL
	lambdaLMsec := uint64(rand.Exp(mRng, lambdaL))
	if lambdaLMsec > doc.LambdaLMaxDelay {
		lambdaLMsec = doc.LambdaLMaxDelay
	}
	lambdaLInterval := time.Duration(lambdaLMsec) * time.Millisecond
	lambdaLTimer := time.NewTimer(lambdaLInterval)
	defer lambdaLTimer.Stop()

	// LambdaD timer setup
	lambdaD := doc.LambdaD
	lambdaDMsec := uint64(rand.Exp(mRng, lambdaD))
	if lambdaDMsec > doc.LambdaDMaxDelay {
		lambdaDMsec = doc.LambdaDMaxDelay
	}
	lambdaDInterval := time.Duration(lambdaDMsec) * time.Millisecond
	lambdaDTimer := time.NewTimer(lambdaDInterval)
	defer lambdaDTimer.Stop()

	defer s.log.Debug("session worker halted")

	isConnected := false
	mustResetAllTimers := false
	for {
		var lambdaPFired bool
		var lambdaLFired bool
		var lambdaDFired bool
		var loopSvc *utils.ServiceDescriptor
		var qo workerOp

		select {
		case <-s.HaltCh():
			s.log.Debugf("Session worker terminating gracefully.")
			return
		case <-lambdaPTimer.C:
			lambdaPFired = true
		case <-lambdaLTimer.C:
			lambdaLFired = true
		case <-lambdaDTimer.C:
			lambdaDFired = true
		case qo = <-s.opCh:
		}

		if qo != nil {
			switch op := qo.(type) {
			case opConnStatusChanged:
				newConnectedStatus := s.connStatusChange(op)
				isConnected = newConnectedStatus
				mustResetAllTimers = true
			case opNewDocument:
				err := s.isDocValid(op.doc)
				if err != nil {
					s.fatalErrCh <- err
				}

				doc = op.doc
				s.setPollIntervalFromDoc(doc)
				lambdaP = doc.LambdaP
				lambdaL = doc.LambdaL
				lambdaD = doc.LambdaD

				// update the loop service descriptors
				loopServices = utils.FindServices(cConstants.LoopService, doc)
				if len(loopServices) == 0 {
					s.fatalErrCh <- errors.New("failure to get loop service")
					return
				}

				mustResetAllTimers = true
			default:
				s.log.Warningf("BUG: Worker received nonsensical op: %T", op)
			} // end of switch
		} else {
			if isConnected {
				// select a loop service endpoint
				if !s.cfg.Debug.DisableDecoyTraffic {
					loopSvc = &loopServices[mrand.Intn(len(loopServices))]
				}
				if lambdaPFired {
					s.sendFromQueueOrDecoy(loopSvc)
				} else if lambdaLFired && !s.cfg.Debug.DisableDecoyTraffic {
					s.sendLoopDecoy(loopSvc)
				} else if lambdaDFired && !s.cfg.Debug.DisableDecoyTraffic {
					s.sendDropDecoy(loopSvc)
				}
			}
		}
		if isConnected {
			lambdaPMsec := uint64(rand.Exp(mRng, lambdaP))
			if lambdaPMsec > doc.LambdaPMaxDelay {
				lambdaPMsec = doc.LambdaPMaxDelay
			}
			lambdaPInterval = time.Duration(lambdaPMsec) * time.Millisecond
			lambdaLMsec := uint64(rand.Exp(mRng, lambdaL))
			if lambdaLMsec > doc.LambdaLMaxDelay {
				lambdaLMsec = doc.LambdaLMaxDelay
			}
			lambdaLInterval = time.Duration(lambdaLMsec) * time.Millisecond
			lambdaDMsec := uint64(rand.Exp(mRng, lambdaD))
			if lambdaDMsec > doc.LambdaDMaxDelay {
				lambdaDMsec = doc.LambdaDMaxDelay
			}
			lambdaDInterval = time.Duration(lambdaDMsec) * time.Millisecond
		} else {
			lambdaLInterval = time.Duration(maxDuration)
			lambdaPInterval = time.Duration(maxDuration)
			lambdaDInterval = time.Duration(maxDuration)
		}

		if mustResetAllTimers {
			lambdaPTimer.Reset(lambdaPInterval)
			lambdaLTimer.Reset(lambdaLInterval)
			lambdaDTimer.Reset(lambdaDInterval)
			mustResetAllTimers = false
		} else {
			// reset only the timer that fired
			if lambdaPFired {
				lambdaPTimer.Reset(lambdaPInterval)
			}
			if lambdaLFired {
				lambdaLTimer.Reset(lambdaLInterval)
			}
			if lambdaDFired {
				lambdaDTimer.Reset(lambdaDInterval)
			}
		}
	}

	// NOTREACHED
}

func (s *Session) sendFromQueueOrDecoy(loopSvc *utils.ServiceDescriptor) {
	// Attempt to send user data first, if any exists.
	// Otherwise send a drop decoy message.
	_, err := s.egressQueue.Peek()
	if err == nil {
		s.sendNext()
	} else if !s.cfg.Debug.DisableDecoyTraffic {
		s.sendLoopDecoy(loopSvc)
	}
}

func (s *Session) isDocValid(doc *pki.Document) error {
	for _, provider := range doc.Providers {
		_, ok := provider.Kaetzchen[constants.LoopService]
		if !ok {
			return errors.New("found a Provider which does not have the loop service")
		}
	}
	return nil
}

func (s *Session) setPollIntervalFromDoc(doc *pki.Document) {
	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)
}
<|endoftext|>


<commit_before>package lights

import (
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

// WorkerFunc handles incoming string messages returning an error if the
// message could not be handled.
type WorkerFunc func(message string) error

// Worker takes care of the common nsq worker tasks that all message
// driven agents must carry out. The worker takes care of bootstrapping
// the system, and automatically configures nsq according to the current
// environment.
type Worker struct {
	agent string
}

// NewWorker creates a new worker ready for configuration. Call Start() on
// the worker to begin processing messages. Returns an error if there was a
// problem creating the worker. If an ID is provided the worker will use it,
// otherwise an ID will automatically be generated using lights.NewID().
func NewWorker(agent string) (*Worker, error) {
	w := &Worker{agent: agent}
	port := w.agentPort(agent)
	if len(port) == 0 {
		return nil, errors.New("Agent " + agent + " not supported")
	}
	return w, nil
}

// Start begins processing commands blocking the thread.
func (w *Worker) Start() error {
	return http.ListenAndServe(":"+w.agentPort(w.agent), nil)
}

// Consumer creates a new API command Consumer for the worker.
func (w *Worker) Consumer(handler WorkerFunc) error {
	http.HandleFunc("/command", func(resp http.ResponseWriter, r *http.Request) {
		body, err := ioutil.ReadAll(r.Body)
		if w.errorFree(err, resp) {
			err = handler(string(body))
			if w.errorFree(err, resp) {
				io.WriteString(resp, "OK")
			}
		}
	})
	return nil
}

// Send transmits a message to an agent.
func (w *Worker) Send(agent, message string) {
	url := "http://127.0.0.1:" + w.agentPort(agent)
	log.Println("->", agent, message)
	resp, err := http.Post(url, "text/plain", strings.NewReader(message))
	if err != nil {
		log.Println("Error sending message", agent, message, err)
	} else {
		resp.Body.Close()
	}
}

// errorFree will respond correctly to clients when an error occurs.
// Returns true if there was an error for easy handling.
func (w *Worker) errorFree(err error, resp http.ResponseWriter) bool {
	if err == nil {
		return true
	}
	resp.WriteHeader(http.StatusInternalServerError)
	io.WriteString(resp, err.Error())
	return false
}

// agentPort looks up the correct port for an agent by name.
func (w *Worker) agentPort(agent string) string {
	switch agent {
	case "gateway":
		return "8001"
	case "controller":
		return "8002"
	case "gatekeeper":
		return "8003"
	case "scheduler":
		return "8004"
	case "updater":
		return "8005"
	default:
		// Default is the gateway agent
		return ""
	}
}
<commit_msg>Fix command URL error, greatly expanded debug log output<commit_after>package lights

import (
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

// WorkerFunc handles incoming string messages returning an error if the
// message could not be handled.
type WorkerFunc func(message string) error

// Worker takes care of the common nsq worker tasks that all message
// driven agents must carry out. The worker takes care of bootstrapping
// the system, and automatically configures nsq according to the current
// environment.
type Worker struct {
	agent string
}

// NewWorker creates a new worker ready for configuration. Call Start() on
// the worker to begin processing messages. Returns an error if there was a
// problem creating the worker. If an ID is provided the worker will use it,
// otherwise an ID will automatically be generated using lights.NewID().
func NewWorker(agent string) (*Worker, error) {
	w := &Worker{agent: agent}
	port := w.agentPort(agent)
	if len(port) == 0 {
		return nil, errors.New("Agent " + agent + " not supported")
	}
	return w, nil
}

// Start begins processing commands blocking the thread.
func (w *Worker) Start() error {
	host := ":" + w.agentPort(w.agent)
	log.Println("Listening for HTTP API", host)
	return http.ListenAndServe(host, nil)
}

// Consumer creates a new API command Consumer for the worker.
func (w *Worker) Consumer(handler WorkerFunc) error {
	http.HandleFunc("/command", func(resp http.ResponseWriter, r *http.Request) {
		body, err := ioutil.ReadAll(r.Body)
		log.Println("<-", string(body))
		if w.errorFree(err, resp) {
			err = handler(string(body))
			if w.errorFree(err, resp) {
				io.WriteString(resp, "OK")
			}
		}
	})
	return nil
}

// Send transmits a message to an agent.
func (w *Worker) Send(agent, message string) {
	url := "http://127.0.0.1:" + w.agentPort(agent) + "/command"
	log.Println("->", agent, message)
	resp, err := http.Post(url, "text/plain", strings.NewReader(message))
	if err != nil {
		log.Println("Error sending message", agent, message, err)
	} else {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Println("Error reading response body", err)
		} else {
			log.Println("  ", string(body))
		}
		resp.Body.Close()
	}
}

// errorFree will respond correctly to clients when an error occurs.
// Returns true if there was an error for easy handling.
func (w *Worker) errorFree(err error, resp http.ResponseWriter) bool {
	if err == nil {
		return true
	}
	resp.WriteHeader(http.StatusInternalServerError)
	io.WriteString(resp, err.Error())
	return false
}

// agentPort looks up the correct port for an agent by name.
func (w *Worker) agentPort(agent string) string {
	switch agent {
	case "gateway":
		return "8001"
	case "controller":
		return "8002"
	case "gatekeeper":
		return "8003"
	case "scheduler":
		return "8004"
	case "updater":
		return "8005"
	default:
		// Default is the gateway agent
		return ""
	}
}
<|endoftext|>


<commit_before>package speed

import (
	"errors"
	"io"
	"os"
	"path"
	"strings"
	"sync"
	"time"

	"github.com/performancecopilot/speed/bytebuffer"
)

// byte lengths of different components in an mmv file
const (
	HeaderLength         = 40
	TocLength            = 16
	MetricLength         = 104
	ValueLength          = 32
	InstanceLength       = 80
	InstanceDomainLength = 32
	StringBlockLength    = 256
)

// Writer defines the interface of a MMV file writer's properties
type Writer interface {
	io.Writer
	Registry() Registry // a writer must contain a registry of metrics and instance domains
	Start() error       // writes an mmv file
}

func mmvFileLocation(name string) (string, error) {
	if strings.ContainsRune(name, os.PathSeparator) {
		return "", errors.New("name cannot have path separator")
	}

	tdir, present := Config["PCP_TMP_DIR"]
	var loc string
	if present {
		loc = path.Join(RootPath, tdir)
	} else {
		loc = os.TempDir()
	}

	return path.Join(loc, "mmv", name), nil
}

// PCPClusterIDBitLength is the bit length of the cluster id
// for a set of PCP metrics
const PCPClusterIDBitLength = 12

// MMVFlag represents an enumerated type to represent mmv flag values
type MMVFlag int

// values for MMVFlag
const (
	NoPrefixFlag MMVFlag = 1 << iota
	ProcessFlag
	SentinelFlag
)

//go:generate stringer -type=MMVFlag

// PCPWriter implements a writer that can write PCP compatible MMV files
type PCPWriter struct {
	sync.Mutex
	loc       string       // absolute location of the mmv file
	clusterID uint32       // cluster identifier for the writer
	flag      MMVFlag      // write flag
	r         *PCPRegistry // current registry
}

// NewPCPWriter initializes a new PCPWriter object
func NewPCPWriter(name string, flag MMVFlag) (*PCPWriter, error) {
	fileLocation, err := mmvFileLocation(name)
	if err != nil {
		return nil, err
	}

	return &PCPWriter{
		loc:       fileLocation,
		r:         NewPCPRegistry(),
		clusterID: getHash(name, PCPClusterIDBitLength),
		flag:      flag,
	}, nil
}

// Registry returns a writer's registry
func (w *PCPWriter) Registry() Registry {
	w.Lock()
	defer w.Unlock()
	return w.r
}

func (w *PCPWriter) tocCount() int {
	ans := 2

	if w.Registry().InstanceCount() > 0 {
		ans += 2
	}

	return ans
}

// Length returns the byte length of data in the mmv file written by the current writer
func (w *PCPWriter) Length() int {
	w.Lock()
	defer w.Unlock()

	return HeaderLength +
		(w.tocCount() * TocLength) +
		(w.Registry().InstanceCount() * InstanceLength) +
		(w.Registry().InstanceDomainCount() * InstanceDomainLength) +
		(w.Registry().MetricCount() * (MetricLength + ValueLength))
}

func (w *PCPWriter) initializeOffsets() {
	indomoffset := HeaderLength + TocLength*w.tocCount()
	instanceoffset := indomoffset + InstanceDomainLength*w.r.InstanceDomainCount()
	metricsoffset := instanceoffset + InstanceLength*w.r.InstanceCount()
	valuesoffset := metricsoffset + MetricLength*w.r.MetricCount()

	w.r.indomoffset = indomoffset
	w.r.instanceoffset = instanceoffset
	w.r.metricsoffset = metricsoffset
	w.r.valuesoffset = valuesoffset

	for _, indom := range w.r.instanceDomains {
		indom.SetOffset(indomoffset)
		indom.instanceOffset = instanceoffset
		indomoffset += InstanceDomainLength

		for _, i := range indom.instances {
			i.SetOffset(instanceoffset)
			instanceoffset += InstanceLength
		}
	}

	for _, metric := range w.r.metrics {
		metric.desc.SetOffset(metricsoffset)
		metricsoffset += MetricLength
		metric.SetOffset(valuesoffset)
		valuesoffset += ValueLength
	}

	// TODO: string offsets
}

func (w *PCPWriter) writeHeaderBlock(buffer bytebuffer.Buffer) (gen2offset int, generation int64) {
	// tag
	buffer.WriteString("MMV")

	// version
	buffer.WriteUint32(1)

	// generation
	generation = time.Now().Unix()
	buffer.WriteInt64(generation)

	gen2offset = buffer.Pos()

	buffer.WriteInt64(0)

	// tocCount
	buffer.WriteInt(w.tocCount())

	// flag mask
	buffer.WriteInt(int(w.flag))

	// process identifier
	buffer.WriteInt(os.Getpid())

	// cluster identifier
	buffer.WriteUint32(w.clusterID)

	return
}

func (w *PCPWriter) writeTocBlock(buffer bytebuffer.Buffer) {
	tocpos := HeaderLength

	// instance domains toc
	if w.Registry().InstanceDomainCount() > 0 {
		buffer.SetPos(tocpos)
		buffer.WriteInt(1) // Instance Domain identifier
		buffer.WriteInt(w.Registry().InstanceDomainCount())
		buffer.WriteUint64(uint64(w.r.indomoffset))
		tocpos += TocLength
	}

	// instances toc
	if w.Registry().InstanceCount() > 0 {
		buffer.SetPos(tocpos)
		buffer.WriteInt(2) // Instance identifier
		buffer.WriteInt(w.Registry().InstanceCount())
		buffer.WriteUint64(uint64(w.r.instanceoffset))
		tocpos += TocLength
	}

	metricsoffset, valuesoffset := w.r.metricsoffset, w.r.valuesoffset
	if w.Registry().MetricCount() == 0 {
		metricsoffset, valuesoffset = 0, 0
	}

	// metrics and values toc
	buffer.SetPos(tocpos)
	buffer.WriteInt(3) // Metrics identifier
	buffer.WriteInt(w.Registry().MetricCount())
	buffer.WriteUint64(uint64(metricsoffset))
	tocpos += TocLength

	buffer.SetPos(tocpos)
	buffer.WriteInt(4) // Values identifier
	buffer.WriteInt(w.Registry().MetricCount())
	buffer.WriteUint64(uint64(valuesoffset))
	tocpos += TocLength

	// TODO: strings toc
}

func (w *PCPWriter) writeInstanceAndInstanceDomainBlock(buffer bytebuffer.Buffer) {
	for _, indom := range w.r.instanceDomains {
		buffer.SetPos(indom.Offset())
		buffer.WriteUint32(indom.ID())
		buffer.WriteInt(indom.InstanceCount())
		buffer.WriteInt64(int64(indom.instanceOffset))
		// TODO: write indom string descriptions offsets

		for _, i := range indom.instances {
			buffer.SetPos(i.Offset())
			buffer.WriteInt64(int64(indom.Offset()))
			buffer.WriteInt(0)
			buffer.WriteUint32(i.id)
			buffer.WriteString(i.name)
		}
	}
}

const (
	MetricNameLimit = 63
	DataValueLength = 16
)

func (w *PCPWriter) writeMetricDesc(desc *MetricDesc, buffer bytebuffer.Buffer) {
	pos := desc.Offset()
	buffer.SetPos(pos)

	buffer.WriteString(desc.name)
	buffer.Write([]byte{0})
	buffer.SetPos(pos + MetricNameLimit + 1)
	buffer.WriteUint32(desc.id)
	buffer.WriteInt32(int32(desc.t))
	buffer.WriteInt32(int32(desc.sem))
	buffer.WriteInt32(int32(desc.u)) // TODO: fix this
	if desc.indom != nil {
		buffer.WriteUint32(desc.indom.ID())
	} else {
		buffer.WriteInt32(-1)
	}
	buffer.WriteInt(0)
	// TODO: write string descriptions
}

func (w *PCPWriter) writeMetricVal(m *PCPMetric, buffer bytebuffer.Buffer) {
	pos := m.Offset()
	buffer.SetPos(pos)

	switch m.desc.t {
	case Int32Type:
		buffer.WriteInt32(m.val.(int32))
	case Int64Type:
		buffer.WriteInt64(m.val.(int64))
	case Uint32Type:
		buffer.WriteUint32(m.val.(uint32))
	case Uint64Type:
		buffer.WriteUint64(m.val.(uint64))
	}

	buffer.SetPos(pos + DataValueLength)
	buffer.WriteInt64(int64(m.desc.Offset()))
	buffer.WriteInt64(int64(m.desc.indom.(*PCPInstanceDomain).instanceOffset))
}

func (w *PCPWriter) writeMetricsAndValuesBlock(buffer bytebuffer.Buffer) {
	for _, metric := range w.r.metrics {
		w.writeMetricDesc(metric.desc, buffer)
		w.writeMetricVal(metric, buffer)
	}
}

// fillData will fill a byte slice with the mmv file
// data as long as something doesn't go wrong
func (w *PCPWriter) fillData(buffer bytebuffer.Buffer) error {
	gen2offset, generation := w.writeHeaderBlock(buffer)
	w.writeTocBlock(buffer)
	w.writeInstanceAndInstanceDomainBlock(buffer)
	w.writeMetricsAndValuesBlock(buffer)
	// TODO: write strings block

	buffer.SetPos(gen2offset)
	buffer.WriteUint64(uint64(generation))

	return nil
}
<commit_msg>writer: add Start and Write to write simple files<commit_after>package speed

import (
	"errors"
	"io"
	"os"
	"path"
	"strings"
	"time"

	"github.com/performancecopilot/speed/bytebuffer"
)

// byte lengths of different components in an mmv file
const (
	HeaderLength         = 40
	TocLength            = 16
	MetricLength         = 104
	ValueLength          = 32
	InstanceLength       = 80
	InstanceDomainLength = 32
	StringBlockLength    = 256
)

// Writer defines the interface of a MMV file writer's properties
type Writer interface {
	io.Writer
	Registry() Registry // a writer must contain a registry of metrics and instance domains
	Start() error       // writes an mmv file
}

func mmvFileLocation(name string) (string, error) {
	if strings.ContainsRune(name, os.PathSeparator) {
		return "", errors.New("name cannot have path separator")
	}

	tdir, present := Config["PCP_TMP_DIR"]
	var loc string
	if present {
		loc = path.Join(RootPath, tdir)
	} else {
		loc = os.TempDir()
	}

	return path.Join(loc, "mmv", name), nil
}

// PCPClusterIDBitLength is the bit length of the cluster id
// for a set of PCP metrics
const PCPClusterIDBitLength = 12

// MMVFlag represents an enumerated type to represent mmv flag values
type MMVFlag int

// values for MMVFlag
const (
	NoPrefixFlag MMVFlag = 1 << iota
	ProcessFlag
	SentinelFlag
)

//go:generate stringer -type=MMVFlag

// PCPWriter implements a writer that can write PCP compatible MMV files
type PCPWriter struct {
	loc       string       // absolute location of the mmv file
	clusterID uint32       // cluster identifier for the writer
	flag      MMVFlag      // write flag
	r         *PCPRegistry // current registry
}

// NewPCPWriter initializes a new PCPWriter object
func NewPCPWriter(name string, flag MMVFlag) (*PCPWriter, error) {
	fileLocation, err := mmvFileLocation(name)
	if err != nil {
		return nil, err
	}

	return &PCPWriter{
		loc:       fileLocation,
		r:         NewPCPRegistry(),
		clusterID: getHash(name, PCPClusterIDBitLength),
		flag:      flag,
	}, nil
}

// Registry returns a writer's registry
func (w *PCPWriter) Registry() Registry {
	return w.r
}

func (w *PCPWriter) tocCount() int {
	ans := 2

	if w.Registry().InstanceCount() > 0 {
		ans += 2
	}

	return ans
}

// Length returns the byte length of data in the mmv file written by the current writer
func (w *PCPWriter) Length() int {
	return HeaderLength +
		(w.tocCount() * TocLength) +
		(w.Registry().InstanceCount() * InstanceLength) +
		(w.Registry().InstanceDomainCount() * InstanceDomainLength) +
		(w.Registry().MetricCount() * (MetricLength + ValueLength))
}

func (w *PCPWriter) initializeOffsets() {
	indomoffset := HeaderLength + TocLength*w.tocCount()
	instanceoffset := indomoffset + InstanceDomainLength*w.r.InstanceDomainCount()
	metricsoffset := instanceoffset + InstanceLength*w.r.InstanceCount()
	valuesoffset := metricsoffset + MetricLength*w.r.MetricCount()

	w.r.indomoffset = indomoffset
	w.r.instanceoffset = instanceoffset
	w.r.metricsoffset = metricsoffset
	w.r.valuesoffset = valuesoffset

	for _, indom := range w.r.instanceDomains {
		indom.SetOffset(indomoffset)
		indom.instanceOffset = instanceoffset
		indomoffset += InstanceDomainLength

		for _, i := range indom.instances {
			i.SetOffset(instanceoffset)
			instanceoffset += InstanceLength
		}
	}

	for _, metric := range w.r.metrics {
		metric.desc.SetOffset(metricsoffset)
		metricsoffset += MetricLength
		metric.SetOffset(valuesoffset)
		valuesoffset += ValueLength
	}

	// TODO: string offsets
}

func (w *PCPWriter) writeHeaderBlock(buffer bytebuffer.Buffer) (gen2offset int, generation int64) {
	// tag
	buffer.WriteString("MMV")
	buffer.SetPos(buffer.Pos() + 1) // extra null byte is needed and \0 isn't a valid escape character in go

	// version
	buffer.WriteUint32(1)

	// generation
	generation = time.Now().Unix()
	buffer.WriteInt64(generation)

	gen2offset = buffer.Pos()

	buffer.WriteInt64(0)

	// tocCount
	buffer.WriteInt(w.tocCount())

	// flag mask
	buffer.WriteInt(int(w.flag))

	// process identifier
	buffer.WriteInt(os.Getpid())

	// cluster identifier
	buffer.WriteUint32(w.clusterID)

	return
}

func (w *PCPWriter) writeTocBlock(buffer bytebuffer.Buffer) {
	tocpos := HeaderLength

	// instance domains toc
	if w.Registry().InstanceDomainCount() > 0 {
		buffer.SetPos(tocpos)
		buffer.WriteInt(1) // Instance Domain identifier
		buffer.WriteInt(w.Registry().InstanceDomainCount())
		buffer.WriteUint64(uint64(w.r.indomoffset))
		tocpos += TocLength
	}

	// instances toc
	if w.Registry().InstanceCount() > 0 {
		buffer.SetPos(tocpos)
		buffer.WriteInt(2) // Instance identifier
		buffer.WriteInt(w.Registry().InstanceCount())
		buffer.WriteUint64(uint64(w.r.instanceoffset))
		tocpos += TocLength
	}

	metricsoffset, valuesoffset := w.r.metricsoffset, w.r.valuesoffset
	if w.Registry().MetricCount() == 0 {
		metricsoffset, valuesoffset = 0, 0
	}

	// metrics and values toc
	buffer.SetPos(tocpos)
	buffer.WriteInt(3) // Metrics identifier
	buffer.WriteInt(w.Registry().MetricCount())
	buffer.WriteUint64(uint64(metricsoffset))
	tocpos += TocLength

	buffer.SetPos(tocpos)
	buffer.WriteInt(4) // Values identifier
	buffer.WriteInt(w.Registry().MetricCount())
	buffer.WriteUint64(uint64(valuesoffset))
	tocpos += TocLength

	// TODO: strings toc
}

func (w *PCPWriter) writeInstanceAndInstanceDomainBlock(buffer bytebuffer.Buffer) {
	for _, indom := range w.r.instanceDomains {
		buffer.SetPos(indom.Offset())
		buffer.WriteUint32(indom.ID())
		buffer.WriteInt(indom.InstanceCount())
		buffer.WriteInt64(int64(indom.instanceOffset))
		// TODO: write indom string descriptions offsets

		for _, i := range indom.instances {
			buffer.SetPos(i.Offset())
			buffer.WriteInt64(int64(indom.Offset()))
			buffer.WriteInt(0)
			buffer.WriteUint32(i.id)
			buffer.WriteString(i.name)
		}
	}
}

const (
	MetricNameLimit = 63
	DataValueLength = 16
)

func (w *PCPWriter) writeMetricDesc(desc *MetricDesc, buffer bytebuffer.Buffer) {
	pos := desc.Offset()
	buffer.SetPos(pos)

	buffer.WriteString(desc.name)
	buffer.Write([]byte{0})
	buffer.SetPos(pos + MetricNameLimit + 1)
	buffer.WriteUint32(desc.id)
	buffer.WriteInt32(int32(desc.t))
	buffer.WriteInt32(int32(desc.sem))
	buffer.WriteInt32(int32(desc.u)) // TODO: fix this
	if desc.indom != nil {
		buffer.WriteUint32(desc.indom.ID())
	} else {
		buffer.WriteInt32(-1)
	}
	buffer.WriteInt(0)
	// TODO: write string descriptions
}

func (w *PCPWriter) writeMetricVal(m *PCPMetric, buffer bytebuffer.Buffer) {
	pos := m.Offset()
	buffer.SetPos(pos)

	switch m.desc.t {
	case Int32Type:
		buffer.WriteInt32(m.val.(int32))
	case Int64Type:
		buffer.WriteInt64(m.val.(int64))
	case Uint32Type:
		buffer.WriteUint32(m.val.(uint32))
	case Uint64Type:
		buffer.WriteUint64(m.val.(uint64))
	}

	buffer.SetPos(pos + DataValueLength)
	buffer.WriteInt64(int64(m.desc.Offset()))
	buffer.WriteInt64(int64(m.desc.indom.(*PCPInstanceDomain).instanceOffset))
}

func (w *PCPWriter) writeMetricsAndValuesBlock(buffer bytebuffer.Buffer) {
	for _, metric := range w.r.metrics {
		w.writeMetricDesc(metric.desc, buffer)
		w.writeMetricVal(metric, buffer)
	}
}

// fillData will fill a byte slice with the mmv file
// data as long as something doesn't go wrong
func (w *PCPWriter) fillData(buffer bytebuffer.Buffer) error {
	gen2offset, generation := w.writeHeaderBlock(buffer)
	w.writeTocBlock(buffer)
	w.writeInstanceAndInstanceDomainBlock(buffer)
	w.writeMetricsAndValuesBlock(buffer)
	// TODO: write strings block

	buffer.SetPos(gen2offset)
	buffer.WriteUint64(uint64(generation))

	return nil
}

func (w *PCPWriter) Write(data []byte) (int, error) {
	f, err := os.Create(w.loc)
	if err != nil {
		panic(err)
	}

	return f.Write(data)
}

// Start dumps existing registry data
func (w *PCPWriter) Start() {
	l := w.Length()

	w.initializeOffsets()
	buffer := bytebuffer.NewByteBuffer(l)
	w.fillData(buffer)

	w.Write(buffer.Buffer())
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Blake Smith <blakesmith0@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ar

import (
	"errors"
	"io"
	"strconv"
)

var (
	ErrWriteTooLong    = errors.New("ar: write too long")
)

// Writer provides sequential writing of an ar archive.
// An ar archive is sequence of header file pairs
// Call WriteHeader to begin writing a new file, then call Write to supply the file's data
//
// Example:
// archive := ar.NewWriter(writer)
// archive.WriteGlobalHeader()
// header := new(ar.Header)
// header.Size = 15 // bytes
// if err := archive.WriteHeader(header); err != nil {
// 	return err
// }
// io.Copy(archive, data)
type Writer struct {
	w io.Writer
	nb int64 // number of unwritten bytes for the current file entry
}

// Create a new ar writer that writes to w
func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }

func (aw *Writer) numeric(b []byte, x int64) {
	s := strconv.FormatInt(x, 10)
	for len(s) < len(b) {
		s = s + " "
	}
	copy(b, []byte(s))
}

func (aw *Writer) octal(b []byte, x int64) {
	s := "100" + strconv.FormatInt(x, 8)
	for len(s) < len(b) {
		s = s + " "
	}
	copy(b, []byte(s))
}

func (aw *Writer) string(b []byte, str string) {
	s := str
	for len(s) < len(b) {
		s = s + " "
	}
	copy(b, []byte(s))
}

// Writes to the current entry in the ar archive
// Returns ErrWriteTooLong if more than header.Size
// bytes are written after a call to WriteHeader
func (aw *Writer) Write(b []byte) (n int, err error) {
	if int64(len(b)) > aw.nb {
		b = b[0:aw.nb]
		err = ErrWriteTooLong
	}
	n, werr := aw.w.Write(b)
	aw.nb -= int64(n)
	if werr != nil {
		return n, werr
	}

	if len(b)%2 == 1 { // data size must be aligned to an even byte
		n2, _ := aw.w.Write([]byte{'\n'})
		return n+n2, err
	}

	return
}

func (aw *Writer) WriteGlobalHeader() error {
	_, err := aw.w.Write([]byte(GLOBAL_HEADER))
	return err
}

// Writes the header to the underlying writer and prepares
// to receive the file payload
func (aw *Writer) WriteHeader(hdr *Header) error {
	aw.nb = int64(hdr.Size)
	header := make([]byte, HEADER_BYTE_SIZE)
	s := slicer(header)

	aw.string(s.next(16), hdr.Name)
	aw.numeric(s.next(12), hdr.ModTime.Unix())
	aw.numeric(s.next(6), int64(hdr.Uid))
	aw.numeric(s.next(6), int64(hdr.Gid))
	aw.octal(s.next(8), hdr.Mode)
	aw.numeric(s.next(10), hdr.Size)
	aw.string(s.next(2), "`\n")

	_, err := aw.w.Write(header)

	return err
}
<commit_msg>Fix for the io.Writer interface.<commit_after>/*
Copyright (c) 2013 Blake Smith <blakesmith0@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ar

import (
	"errors"
	"io"
	"strconv"
)

var (
	ErrWriteTooLong = errors.New("ar: write too long")
)

// Writer provides sequential writing of an ar archive.
// An ar archive is sequence of header file pairs
// Call WriteHeader to begin writing a new file, then call Write to supply the file's data
//
// Example:
// archive := ar.NewWriter(writer)
// archive.WriteGlobalHeader()
// header := new(ar.Header)
// header.Size = 15 // bytes
// if err := archive.WriteHeader(header); err != nil {
// 	return err
// }
// io.Copy(archive, data)
type Writer struct {
	w  io.Writer
	nb int64 // number of unwritten bytes for the current file entry
}

// Create a new ar writer that writes to w
func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }

func (aw *Writer) numeric(b []byte, x int64) {
	s := strconv.FormatInt(x, 10)
	for len(s) < len(b) {
		s = s + " "
	}
	copy(b, []byte(s))
}

func (aw *Writer) octal(b []byte, x int64) {
	s := "100" + strconv.FormatInt(x, 8)
	for len(s) < len(b) {
		s = s + " "
	}
	copy(b, []byte(s))
}

func (aw *Writer) string(b []byte, str string) {
	s := str
	for len(s) < len(b) {
		s = s + " "
	}
	copy(b, []byte(s))
}

// Writes to the current entry in the ar archive
// Returns ErrWriteTooLong if more than header.Size
// bytes are written after a call to WriteHeader
func (aw *Writer) Write(b []byte) (n int, err error) {
	if int64(len(b)) > aw.nb {
		b = b[0:aw.nb]
		err = ErrWriteTooLong
	}
	n, werr := aw.w.Write(b)
	aw.nb -= int64(n)
	if werr != nil {
		return n, werr
	}

	if len(b)%2 == 1 { // data size must be aligned to an even byte
		if _, err := aw.w.Write([]byte{'\n'}); err != nil {
			// Return n although we actually wrote n+1 bytes.
			// This is to make io.Copy() to work correctly.
			return n, err
		}
	}

	return
}

func (aw *Writer) WriteGlobalHeader() error {
	_, err := aw.w.Write([]byte(GLOBAL_HEADER))
	return err
}

// Writes the header to the underlying writer and prepares
// to receive the file payload
func (aw *Writer) WriteHeader(hdr *Header) error {
	aw.nb = int64(hdr.Size)
	header := make([]byte, HEADER_BYTE_SIZE)
	s := slicer(header)

	aw.string(s.next(16), hdr.Name)
	aw.numeric(s.next(12), hdr.ModTime.Unix())
	aw.numeric(s.next(6), int64(hdr.Uid))
	aw.numeric(s.next(6), int64(hdr.Gid))
	aw.octal(s.next(8), hdr.Mode)
	aw.numeric(s.next(10), hdr.Size)
	aw.string(s.next(2), "`\n")

	_, err := aw.w.Write(header)

	return err
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
)

type writer struct {
	writers []io.Writer
	Wchan   chan string
}

func NewWriter() *writer {
	writer := &writer{}
	writer.Wchan = make(chan string)

	go func() {
		select {
		case str := <-writer.Wchan:
			writer.write(str)
		}
	}()
	return writer
}

func (w *writer) write(str string) {
	log.Println("Writing msg:", str)
	for _, writer := range w.writers {
		if _, err := writer.Write([]byte(str)); err != nil {
			log.Println("Could not write str to writer:", err)
		}
	}
}

func (w *writer) AddWriter(writer io.Writer) {
	w.writers = append(w.writers, writer)
}
<commit_msg>Don't write empty strings<commit_after>package main

import (
	"io"
	"log"
)

type writer struct {
	writers []io.Writer
	Wchan   chan string
}

func NewWriter() *writer {
	writer := &writer{}
	writer.Wchan = make(chan string)

	go func() {
		select {
		case str := <-writer.Wchan:
			writer.write(str)
		}
	}()
	return writer
}

func (w *writer) write(str string) {
	if str == "" {
		return
	}
	log.Println("Writing msg:", str)
	for _, writer := range w.writers {
		if _, err := writer.Write([]byte(str)); err != nil {
			log.Println("Could not write str to writer:", err)
		}
	}
}

func (w *writer) AddWriter(writer io.Writer) {
	w.writers = append(w.writers, writer)
}
<|endoftext|>


<commit_before>// Copyright 2017 Mark Nevill. All Rights Reserved.
// See LICENSE for licensing terms.

package http_prometheus

import (
	"net/http"

	"github.com/mwitkow/go-httpwares/tags"
)

type meta struct {
	name, handler, method, host, path string
}

func reqMeta(req *http.Request, opts *options, inbound bool) *meta {
	m := &meta{name: opts.name}
	if m.name == "" && inbound {
		v := http_ctxtags.ExtractInbound(req).Values()[http_ctxtags.TagForCallService]
		m.name, _ = v.(string)
	}
	if m.name == "" && !inbound {
		v := http_ctxtags.ExtractOutbound(req).Values()[http_ctxtags.TagForCallService]
		m.name, _ = v.(string)
	}
	if inbound {
		v := http_ctxtags.ExtractInbound(req).Values()[http_ctxtags.TagForHandlerName]
		hname, _ := v.(string)
		if hname != "" {
			v := http_ctxtags.ExtractInbound(req).Values()[http_ctxtags.TagForHandlerGroup]
			hgroup, _ := v.(string)
			if hgroup == "" {
				hgroup = "unknown"
			}
			m.handler = hgroup + "." + hname
		}
	}
	if opts.hosts {
		m.host = req.URL.Host
		if m.host == "" {
			m.host = req.Host
		}
	}
	if opts.paths {
		m.path = req.URL.Path
	}
	return m
}
<commit_msg>Extract tag-based metric labels for both in and outbound requests. (#28)<commit_after>// Copyright 2017 Mark Nevill. All Rights Reserved.
// See LICENSE for licensing terms.

package http_prometheus

import (
	"net/http"

	"github.com/mwitkow/go-httpwares/tags"
)

type meta struct {
	name, handler, method, host, path string
}

func reqMeta(req *http.Request, opts *options, inbound bool) *meta {
	m := &meta{name: opts.name}

	var tags map[string]interface{}
	if inbound {
		tags = http_ctxtags.ExtractInbound(req).Values()
	} else {
		tags = http_ctxtags.ExtractOutbound(req).Values()
	}
	var v interface{}
	if m.name == "" {
		v, _ = tags[http_ctxtags.TagForCallService]
		m.name, _ = v.(string)
	}
	v, _ = tags[http_ctxtags.TagForHandlerName]
	hname, _ := v.(string)
	if hname != "" {
		v, _ = tags[http_ctxtags.TagForHandlerGroup]
		hgroup, _ := v.(string)
		if hgroup == "" {
			hgroup = "unknown"
		}
		m.handler = hgroup + "." + hname
	}

	if opts.hosts {
		m.host = req.URL.Host
		if m.host == "" {
			m.host = req.Host
		}
	}
	if opts.paths {
		m.path = req.URL.Path
	}
	return m
}
<|endoftext|>


<commit_before>// Copyright 2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package secp256k1

// References:
//   [SECG]: Recommended Elliptic Curve Domain Parameters
//     https://www.secg.org/sec2-v2.pdf
//
//   [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"math/big"
	"sync"
)

// CurveParams contains the parameters for the secp256k1 curve.
type CurveParams struct {
	*elliptic.CurveParams
	H int // cofactor of the curve.

	// byteSize is simply the bit size / 8 and is provided for convenience
	// since it is calculated repeatedly.
	byteSize int
}

// Curve parameters taken from [SECG] section 2.4.1.
var curveParams = CurveParams{
	CurveParams: &elliptic.CurveParams{
		P:       fromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),
		N:       fromHex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),
		B:       fromHex("0000000000000000000000000000000000000000000000000000000000000007"),
		Gx:      fromHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
		Gy:      fromHex("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"),
		BitSize: 256,
	},
	H: 1,

	// Provided for convenience since this gets computed repeatedly.
	byteSize: 256 / 8,
}

// Params returns the secp256k1 curve parameters for convenience.
func Params() *CurveParams {
	return &curveParams
}

// KoblitzCurve provides an implementation for secp256k1 that fits the ECC Curve
// interface from crypto/elliptic.
type KoblitzCurve struct {
	*CurveParams

	// bytePoints
	bytePoints *[32][256][3]fieldVal
}

// bigAffineToJacobian takes an affine point (x, y) as big integers and converts
// it to Jacobian point with Z=1.
func bigAffineToJacobian(x, y *big.Int, result *jacobianPoint) {
	result.x.SetByteSlice(x.Bytes())
	result.y.SetByteSlice(y.Bytes())
	result.z.SetInt(1)
}

// jacobianToBigAffine takes a Jacobian point (x, y, z) as field values and
// converts it to an affine point as big integers.
func jacobianToBigAffine(point *jacobianPoint) (*big.Int, *big.Int) {
	point.ToAffine()

	// Convert the field values for the now affine point to big.Ints.
	x3, y3 := new(big.Int), new(big.Int)
	x3.SetBytes(point.x.Bytes()[:])
	y3.SetBytes(point.y.Bytes()[:])
	return x3, y3
}

// Params returns the parameters for the curve.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Params() *elliptic.CurveParams {
	return curve.CurveParams.CurveParams
}

// IsOnCurve returns whether or not the affine point (x,y) is on the curve.
//
// This is part of the elliptic.Curve interface implementation.  This function
// differs from the crypto/elliptic algorithm since a = 0 not -3.
func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool {
	// Convert big ints to a Jacobian point for faster arithmetic.
	var point jacobianPoint
	bigAffineToJacobian(x, y, &point)
	return isOnCurve(&point.x, &point.y)
}

// Add returns the sum of (x1,y1) and (x2,y2).
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
	// A point at infinity is the identity according to the group law for
	// elliptic curve cryptography.  Thus, ∞ + P = P and P + ∞ = P.
	if x1.Sign() == 0 && y1.Sign() == 0 {
		return x2, y2
	}
	if x2.Sign() == 0 && y2.Sign() == 0 {
		return x1, y1
	}

	// Convert the affine coordinates from big integers to Jacobian points,
	// do the point addition in Jacobian projective space, and convert the
	// Jacobian point back to affine big.Ints.
	var p1, p2, result jacobianPoint
	bigAffineToJacobian(x1, y1, &p1)
	bigAffineToJacobian(x2, y2, &p2)
	addJacobian(&p1, &p2, &result)
	return jacobianToBigAffine(&result)
}

// Double returns 2*(x1,y1).
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
	if y1.Sign() == 0 {
		return new(big.Int), new(big.Int)
	}

	// Convert the affine coordinates from big integers to Jacobian points,
	// do the point doubling in Jacobian projective space, and convert the
	// Jacobian point back to affine big.Ints.
	var point, result jacobianPoint
	bigAffineToJacobian(x1, y1, &point)
	doubleJacobian(&point, &result)
	return jacobianToBigAffine(&result)
}

// moduloReduce reduces k from more than 32 bytes to 32 bytes and under.  This
// is done by doing a simple modulo curve.N.  We can do this since G^N = 1 and
// thus any other valid point on the elliptic curve has the same order.
func moduloReduce(k []byte) []byte {
	// Since the order of G is curve.N, we can use a much smaller number by
	// doing modulo curve.N
	if len(k) > curveParams.byteSize {
		tmpK := new(big.Int).SetBytes(k)
		tmpK.Mod(tmpK, curveParams.N)
		return tmpK.Bytes()
	}

	return k
}

// ScalarMult returns k*(Bx, By) where k is a big endian integer.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
	// Convert the affine coordinates from big integers to Jacobian points,
	// do the multiplication in Jacobian projective space, and convert the
	// Jacobian point back to affine big.Ints.
	var kModN ModNScalar
	kModN.SetByteSlice(moduloReduce(k))
	var point, result jacobianPoint
	bigAffineToJacobian(Bx, By, &point)
	scalarMultJacobian(&kModN, &point, &result)
	return jacobianToBigAffine(&result)
}

// ScalarBaseMult returns k*G where G is the base point of the group and k is a
// big endian integer.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
	// Perform the multiplication and convert the Jacobian point back to affine
	// big.Ints.
	var kModN ModNScalar
	kModN.SetByteSlice(moduloReduce(k))
	var result jacobianPoint
	scalarBaseMultJacobian(&kModN, &result)
	return jacobianToBigAffine(&result)
}

// ToECDSA returns the public key as a *ecdsa.PublicKey.
func (p PublicKey) ToECDSA() *ecdsa.PublicKey {
	return &ecdsa.PublicKey{
		Curve: S256(),
		X:     p.x,
		Y:     p.y,
	}
}

// ToECDSA returns the private key as a *ecdsa.PrivateKey.
func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey {
	privKeyBytes := p.key.Bytes()
	var result jacobianPoint
	scalarBaseMultJacobian(&p.key, &result)
	x, y := jacobianToBigAffine(&result)
	newPrivKey := &ecdsa.PrivateKey{
		PublicKey: ecdsa.PublicKey{
			Curve: S256(),
			X:     x,
			Y:     y,
		},
		D: new(big.Int).SetBytes(privKeyBytes[:]),
	}
	zeroArray32(&privKeyBytes)
	return newPrivKey
}

// fromHex converts the passed hex string into a big integer pointer and will
// panic is there is an error.  This is only provided for the hard-coded
// constants so errors in the source code can bet detected. It will only (and
// must only) be called for initialization purposes.
func fromHex(s string) *big.Int {
	r, ok := new(big.Int).SetString(s, 16)
	if !ok {
		panic("invalid hex in source file: " + s)
	}
	return r
}

var initonce sync.Once
var secp256k1 KoblitzCurve

func initAll() {
	initS256()
}

func initS256() {
	secp256k1.CurveParams = &curveParams

	// Deserialize and set the pre-computed table used to accelerate scalar
	// base multiplication.  This is hard-coded data, so any errors are
	// panics because it means something is wrong in the source code.
	if err := loadBytePoints(); err != nil {
		panic(err)
	}
}

// S256 returns a Curve which implements secp256k1.
func S256() *KoblitzCurve {
	initonce.Do(initAll)
	return &secp256k1
}
<commit_msg>secp256k1: Improve exported curve params.<commit_after>// Copyright 2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package secp256k1

// References:
//   [SECG]: Recommended Elliptic Curve Domain Parameters
//     https://www.secg.org/sec2-v2.pdf
//
//   [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"math/big"
	"sync"
)

// CurveParams contains the parameters for the secp256k1 curve.
type CurveParams struct {
	// P is the prime used in the secp256k1 field.
	P *big.Int

	// N is the order of the secp256k1 curve group generated by the base point.
	N *big.Int

	// Gx and Gy are the x and y coordinate of the base point, respectively.
	Gx, Gy *big.Int

	// BitSize is the size of the underlying secp256k1 field in bits.
	BitSize int

	// H is the cofactor of the secp256k1 curve.
	H int

	// ByteSize is simply the bit size / 8 and is provided for convenience
	// since it is calculated repeatedly.
	ByteSize int
}

// Curve parameters taken from [SECG] section 2.4.1.
var curveParams = CurveParams{
	P:        fromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),
	N:        fromHex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),
	Gx:       fromHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
	Gy:       fromHex("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"),
	BitSize:  256,
	H:        1,
	ByteSize: 256 / 8,
}

// Params returns the secp256k1 curve parameters for convenience.
func Params() *CurveParams {
	return &curveParams
}

// KoblitzCurve provides an implementation for secp256k1 that fits the ECC Curve
// interface from crypto/elliptic.
type KoblitzCurve struct {
	*elliptic.CurveParams

	// bytePoints
	bytePoints *[32][256][3]fieldVal
}

// bigAffineToJacobian takes an affine point (x, y) as big integers and converts
// it to Jacobian point with Z=1.
func bigAffineToJacobian(x, y *big.Int, result *jacobianPoint) {
	result.x.SetByteSlice(x.Bytes())
	result.y.SetByteSlice(y.Bytes())
	result.z.SetInt(1)
}

// jacobianToBigAffine takes a Jacobian point (x, y, z) as field values and
// converts it to an affine point as big integers.
func jacobianToBigAffine(point *jacobianPoint) (*big.Int, *big.Int) {
	point.ToAffine()

	// Convert the field values for the now affine point to big.Ints.
	x3, y3 := new(big.Int), new(big.Int)
	x3.SetBytes(point.x.Bytes()[:])
	y3.SetBytes(point.y.Bytes()[:])
	return x3, y3
}

// Params returns the parameters for the curve.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Params() *elliptic.CurveParams {
	return curve.CurveParams
}

// IsOnCurve returns whether or not the affine point (x,y) is on the curve.
//
// This is part of the elliptic.Curve interface implementation.  This function
// differs from the crypto/elliptic algorithm since a = 0 not -3.
func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool {
	// Convert big ints to a Jacobian point for faster arithmetic.
	var point jacobianPoint
	bigAffineToJacobian(x, y, &point)
	return isOnCurve(&point.x, &point.y)
}

// Add returns the sum of (x1,y1) and (x2,y2).
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
	// A point at infinity is the identity according to the group law for
	// elliptic curve cryptography.  Thus, ∞ + P = P and P + ∞ = P.
	if x1.Sign() == 0 && y1.Sign() == 0 {
		return x2, y2
	}
	if x2.Sign() == 0 && y2.Sign() == 0 {
		return x1, y1
	}

	// Convert the affine coordinates from big integers to Jacobian points,
	// do the point addition in Jacobian projective space, and convert the
	// Jacobian point back to affine big.Ints.
	var p1, p2, result jacobianPoint
	bigAffineToJacobian(x1, y1, &p1)
	bigAffineToJacobian(x2, y2, &p2)
	addJacobian(&p1, &p2, &result)
	return jacobianToBigAffine(&result)
}

// Double returns 2*(x1,y1).
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
	if y1.Sign() == 0 {
		return new(big.Int), new(big.Int)
	}

	// Convert the affine coordinates from big integers to Jacobian points,
	// do the point doubling in Jacobian projective space, and convert the
	// Jacobian point back to affine big.Ints.
	var point, result jacobianPoint
	bigAffineToJacobian(x1, y1, &point)
	doubleJacobian(&point, &result)
	return jacobianToBigAffine(&result)
}

// moduloReduce reduces k from more than 32 bytes to 32 bytes and under.  This
// is done by doing a simple modulo curve.N.  We can do this since G^N = 1 and
// thus any other valid point on the elliptic curve has the same order.
func moduloReduce(k []byte) []byte {
	// Since the order of G is curve.N, we can use a much smaller number by
	// doing modulo curve.N
	if len(k) > curveParams.ByteSize {
		tmpK := new(big.Int).SetBytes(k)
		tmpK.Mod(tmpK, curveParams.N)
		return tmpK.Bytes()
	}

	return k
}

// ScalarMult returns k*(Bx, By) where k is a big endian integer.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
	// Convert the affine coordinates from big integers to Jacobian points,
	// do the multiplication in Jacobian projective space, and convert the
	// Jacobian point back to affine big.Ints.
	var kModN ModNScalar
	kModN.SetByteSlice(moduloReduce(k))
	var point, result jacobianPoint
	bigAffineToJacobian(Bx, By, &point)
	scalarMultJacobian(&kModN, &point, &result)
	return jacobianToBigAffine(&result)
}

// ScalarBaseMult returns k*G where G is the base point of the group and k is a
// big endian integer.
//
// This is part of the elliptic.Curve interface implementation.
func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
	// Perform the multiplication and convert the Jacobian point back to affine
	// big.Ints.
	var kModN ModNScalar
	kModN.SetByteSlice(moduloReduce(k))
	var result jacobianPoint
	scalarBaseMultJacobian(&kModN, &result)
	return jacobianToBigAffine(&result)
}

// ToECDSA returns the public key as a *ecdsa.PublicKey.
func (p PublicKey) ToECDSA() *ecdsa.PublicKey {
	return &ecdsa.PublicKey{
		Curve: S256(),
		X:     p.x,
		Y:     p.y,
	}
}

// ToECDSA returns the private key as a *ecdsa.PrivateKey.
func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey {
	privKeyBytes := p.key.Bytes()
	var result jacobianPoint
	scalarBaseMultJacobian(&p.key, &result)
	x, y := jacobianToBigAffine(&result)
	newPrivKey := &ecdsa.PrivateKey{
		PublicKey: ecdsa.PublicKey{
			Curve: S256(),
			X:     x,
			Y:     y,
		},
		D: new(big.Int).SetBytes(privKeyBytes[:]),
	}
	zeroArray32(&privKeyBytes)
	return newPrivKey
}

// fromHex converts the passed hex string into a big integer pointer and will
// panic is there is an error.  This is only provided for the hard-coded
// constants so errors in the source code can bet detected. It will only (and
// must only) be called for initialization purposes.
func fromHex(s string) *big.Int {
	r, ok := new(big.Int).SetString(s, 16)
	if !ok {
		panic("invalid hex in source file: " + s)
	}
	return r
}

var (
	// initonce is used to initialize the global secp256k1 koblitz curve instance
	// dynamically upon first access.
	initonce sync.Once

	// secp256k1 is a global instance of the KoblitzCurve implementation which
	// in turn embeds and implements elliptic.CurveParams.
	secp256k1 KoblitzCurve
)

// initS256 initializes the global secp256k1 instance that gets returned by the
// S256 function which provides access to the fields and methods provided by
// elliptic.CurveParms.
func initS256() {
	// Curve parameters taken from [SECG] section 2.4.1.
	secp256k1.CurveParams = &elliptic.CurveParams{
		P:       curveParams.P,
		N:       curveParams.N,
		B:       fromHex("0000000000000000000000000000000000000000000000000000000000000007"),
		Gx:      curveParams.Gx,
		Gy:      curveParams.Gy,
		BitSize: curveParams.BitSize,
		Name:    "secp256k1",
	}

	// Deserialize and set the pre-computed table used to accelerate scalar
	// base multiplication.  This is hard-coded data, so any errors are
	// panics because it means something is wrong in the source code.
	if err := loadBytePoints(); err != nil {
		panic(err)
	}
}

// S256 returns a Curve which implements secp256k1.
func S256() *KoblitzCurve {
	initonce.Do(initS256)
	return &secp256k1
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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 unimplemented provides a convenience type to stub out unimplemented
// gNMI RPCs.
package unimplemented

import (
	"context"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc"

	pb "github.com/openconfig/gnmi/proto/gnmi"
)

// Server is a type that can be embedded anonymously in a gNMI server to stub
// out all RPCs that are not implemented with a proper return code.
type Server struct{}

// Capabilities satisfies the gNMI service definition.
func (*Server) Capabilities(context.Context, *pb.CapabilityRequest) (*pb.CapabilityResponse, error) {
	return nil, grpc.Errorf(codes.Unimplemented, "Unimplemented")
}

// Get satisfies the gNMI service definition.
func (*Server) Get(context.Context, *pb.GetRequest) (*pb.GetResponse, error) {
	return nil, grpc.Errorf(codes.Unimplemented, "Unimplemented")
}

// Set satisfies the gNMI service definition.
func (*Server) Set(context.Context, *pb.SetRequest) (*pb.SetResponse, error) {
	return nil, grpc.Errorf(codes.Unimplemented, "Unimplemented")
}

// Subscribe satisfies the gNMI service defintion.
func (s *Server) Subscribe(stream pb.GNMI_SubscribeServer) error {
	return grpc.Errorf(codes.Unimplemented, "Unimplemented")
}
<commit_msg>Add an unimplemented gNMI client to use in unit tests<commit_after>/*
Copyright 2017 Google Inc.

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 unimplemented provides a convenience type to stub out unimplemented
// gNMI RPCs.
package unimplemented

import (
	"context"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc"
	"google.golang.org/grpc/status"

	pb "github.com/openconfig/gnmi/proto/gnmi"
)

// Server is a type that can be embedded anonymously in a gNMI server to stub
// out all RPCs that are not implemented with a proper return code.
type Server struct{}

// Capabilities satisfies the gNMI service definition.
func (*Server) Capabilities(context.Context, *pb.CapabilityRequest) (*pb.CapabilityResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "Unimplemented")
}

// Get satisfies the gNMI service definition.
func (*Server) Get(context.Context, *pb.GetRequest) (*pb.GetResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "Unimplemented")
}

// Set satisfies the gNMI service definition.
func (*Server) Set(context.Context, *pb.SetRequest) (*pb.SetResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "Unimplemented")
}

// Subscribe satisfies the gNMI service definition.
func (s *Server) Subscribe(stream pb.GNMI_SubscribeServer) error {
	return status.Errorf(codes.Unimplemented, "Unimplemented")
}

// Client is a type that can be embedded anonymously in a gNMI client to stub
// out all RPCs that are not implemented with a proper return code.
type Client struct{}

// Capabilities satisfies the gNMI client definition.
func (*Client) Capabilities(ctx context.Context, in *pb.CapabilityRequest, opts ...grpc.CallOption) (*pb.CapabilityResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "Unimplemented")
}

// Get satisfies the gNMI client definition.
func (*Client) Get(ctx context.Context, in *pb.GetRequest, opts ...grpc.CallOption) (*pb.GetResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "Unimplemented")
}

// Set satisfies the gNMI client definition.
func (*Client) Set(ctx context.Context, in *pb.SetRequest, opts ...grpc.CallOption) (*pb.SetResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "Unimplemented")
}

// Subscribe satisfies the gNMI client definition.
func (*Client) Subscribe(ctx context.Context, opts ...grpc.CallOption) (pb.GNMI_SubscribeClient, error) {
	return nil, status.Errorf(codes.Unimplemented, "Unimplemented")
}
<|endoftext|>