<commit_before>package main

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestLogin(t *testing.T) {
	resp, err := Login()
	authFlag := resp.Header["X-Niconico-Authflag"][0]
	if err != nil {
		assert.Equal(t, authFlag, 0)
	} else {
		assert.NotEqual(t, authFlag, 0)
	}
}
<commit_msg>Replace all unit tests with BDD style tests in user_test.go<commit_after>package main

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"net/http"
)

var _ = Describe("gonico user test", func() {

	Describe("test Login function", func() {
		var (
			resp     *http.Response
			err      error
			authFlag string
		)

		BeforeEach(func() {
			resp, err = Login()
			authFlag = resp.Header["X-Niconico-Authflag"][0]
		})

		Context("when login error occurred", func() {
			if err != nil {
				It("should return 0", func() {
					Expect(authFlag).To(Equal("0"))
				})
			}
		})

		Context("when login success occurred", func() {
			if err == nil {
				It("should not return 0", func() {
					Expect(authFlag).NotTo(Equal("0"))
				})
			}
		})

	})
})
<|endoftext|>


<commit_before>// Package accesstoken provides storage and validation of Chain Core
// credentials.
package accesstoken

import (
	"context"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"regexp"
	"strings"
	"time"

	dbm "github.com/tendermint/tmlibs/db"

	"github.com/bytom/crypto/sha3pool"
	"github.com/bytom/errors"
)

const tokenSize = 32

var (
	// ErrBadID is returned when Create is called on an invalid id string.
	ErrBadID = errors.New("invalid id")
	// ErrDuplicateID is returned when Create is called on an existing ID.
	ErrDuplicateID = errors.New("duplicate access token ID")
	// ErrBadType is returned when Create is called with a bad type.
	ErrBadType = errors.New("type must be client or network")
	// ErrNoMatchID is returned when Delete is called on nonexisting ID.
	ErrNoMatchID = errors.New("nonexisting access token ID")

	// validIDRegexp checks that all characters are alphumeric, _ or -.
	// It also must have a length of at least 1.
	validIDRegexp = regexp.MustCompile(`^[\w-]+$`)
)

// Token describe the access token.
type Token struct {
	ID      string    `json:"id"`
	Token   string    `json:"token,omitempty"`
	Type    string    `json:"type,omitempty"`
	Created time.Time `json:"created_at"`
}

// CredentialStore store user access credential.
type CredentialStore struct {
	DB dbm.DB
}

// NewStore creates and returns a new Store object.
func NewStore(db dbm.DB) *CredentialStore {
	return &CredentialStore{
		DB: db,
	}
}

// Create generates a new access token with the given ID.
func (cs *CredentialStore) Create(ctx context.Context, id, typ string) (*string, error) {
	if !validIDRegexp.MatchString(id) {
		return nil, errors.WithDetailf(ErrBadID, "invalid id %q", id)
	}

	key := []byte(id)
	if cs.DB.Get(key) != nil {
		return nil, errors.WithDetailf(ErrDuplicateID, "id %q already in use", id)
	}

	secret := make([]byte, tokenSize)
	if _, err := rand.Read(secret); err != nil {
		return nil, err
	}

	hashedSecret := make([]byte, tokenSize)
	sha3pool.Sum256(hashedSecret, secret)
	created := time.Now()

	token := &Token{
		ID:      id,
		Token:   fmt.Sprintf("%s:%x", id, hashedSecret),
		Type:    typ,
		Created: created,
	}

	value, err := json.Marshal(token)
	if err != nil {
		return nil, err
	}
	cs.DB.Set(key, value)
	hexsec := fmt.Sprintf("%s:%x", id, secret)
	return &hexsec, nil
}

// Check returns whether or not an id-secret pair is a valid access token.
func (cs *CredentialStore) Check(ctx context.Context, id, secret []byte) (bool, error) {
	if !validIDRegexp.MatchString(id) {
		return false, errors.WithDetailf(ErrBadID, "invalid id %q", id)
	}

	var toHash [tokenSize]byte
	var hashed [tokenSize]byte
	copy(toHash[:], secret)
	sha3pool.Sum256(hashed[:], toHash[:])
	inToken := fmt.Sprintf("%s:%x", id, hashed[:])

	var value []byte
	token := &Token{}

	key := []byte(id)
	if value = cs.DB.Get(key); value == nil {
		return false, errors.WithDetailf(ErrNoMatchID, "check id %q nonexisting", id)
	}
	if err := json.Unmarshal(value, token); err != nil {
		return false, err
	}

	if strings.Compare(token.Token, inToken) == 0 {
		return true, nil
	}

	return false, nil
}

// List lists all access tokens.
func (cs *CredentialStore) List(ctx context.Context) ([]*Token, error) {
	tokens := make([]*Token, 0)
	iter := cs.DB.Iterator()
	defer iter.Release()

	for iter.Next() {
		token := &Token{}
		if err := json.Unmarshal(iter.Value(), token); err != nil {
			return nil, err
		}
		tokens = append(tokens, token)
	}
	return tokens, nil
}

// Delete deletes an access token by id.
func (cs *CredentialStore) Delete(ctx context.Context, id string) error {
	if !validIDRegexp.MatchString(id) {
		return errors.WithDetailf(ErrBadID, "invalid id %q", id)
	}

	cs.DB.Delete([]byte(id))
	return nil
}
<commit_msg>correct CredentialStore#check argument type<commit_after>// Package accesstoken provides storage and validation of Chain Core
// credentials.
package accesstoken

import (
	"context"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"regexp"
	"strings"
	"time"

	dbm "github.com/tendermint/tmlibs/db"

	"github.com/bytom/crypto/sha3pool"
	"github.com/bytom/errors"
)

const tokenSize = 32

var (
	// ErrBadID is returned when Create is called on an invalid id string.
	ErrBadID = errors.New("invalid id")
	// ErrDuplicateID is returned when Create is called on an existing ID.
	ErrDuplicateID = errors.New("duplicate access token ID")
	// ErrBadType is returned when Create is called with a bad type.
	ErrBadType = errors.New("type must be client or network")
	// ErrNoMatchID is returned when Delete is called on nonexisting ID.
	ErrNoMatchID = errors.New("nonexisting access token ID")

	// validIDRegexp checks that all characters are alphumeric, _ or -.
	// It also must have a length of at least 1.
	validIDRegexp = regexp.MustCompile(`^[\w-]+$`)
)

// Token describe the access token.
type Token struct {
	ID      string    `json:"id"`
	Token   string    `json:"token,omitempty"`
	Type    string    `json:"type,omitempty"`
	Created time.Time `json:"created_at"`
}

// CredentialStore store user access credential.
type CredentialStore struct {
	DB dbm.DB
}

// NewStore creates and returns a new Store object.
func NewStore(db dbm.DB) *CredentialStore {
	return &CredentialStore{
		DB: db,
	}
}

// Create generates a new access token with the given ID.
func (cs *CredentialStore) Create(ctx context.Context, id, typ string) (*string, error) {
	if !validIDRegexp.MatchString(id) {
		return nil, errors.WithDetailf(ErrBadID, "invalid id %q", id)
	}

	key := []byte(id)
	if cs.DB.Get(key) != nil {
		return nil, errors.WithDetailf(ErrDuplicateID, "id %q already in use", id)
	}

	secret := make([]byte, tokenSize)
	if _, err := rand.Read(secret); err != nil {
		return nil, err
	}

	hashedSecret := make([]byte, tokenSize)
	sha3pool.Sum256(hashedSecret, secret)
	created := time.Now()

	token := &Token{
		ID:      id,
		Token:   fmt.Sprintf("%s:%x", id, hashedSecret),
		Type:    typ,
		Created: created,
	}

	value, err := json.Marshal(token)
	if err != nil {
		return nil, err
	}
	cs.DB.Set(key, value)
	hexsec := fmt.Sprintf("%s:%x", id, secret)
	return &hexsec, nil
}

// Check returns whether or not an id-secret pair is a valid access token.
func (cs *CredentialStore) Check(ctx context.Context, id string, secret []byte) (bool, error) {
	if !validIDRegexp.MatchString(id) {
		return false, errors.WithDetailf(ErrBadID, "invalid id %q", id)
	}

	var toHash [tokenSize]byte
	var hashed [tokenSize]byte
	copy(toHash[:], secret)
	sha3pool.Sum256(hashed[:], toHash[:])
	inToken := fmt.Sprintf("%s:%x", id, hashed[:])

	var value []byte
	token := &Token{}

	key := []byte(id)
	if value = cs.DB.Get(key); value == nil {
		return false, errors.WithDetailf(ErrNoMatchID, "check id %q nonexisting", id)
	}
	if err := json.Unmarshal(value, token); err != nil {
		return false, err
	}

	if strings.Compare(token.Token, inToken) == 0 {
		return true, nil
	}

	return false, nil
}

// List lists all access tokens.
func (cs *CredentialStore) List(ctx context.Context) ([]*Token, error) {
	tokens := make([]*Token, 0)
	iter := cs.DB.Iterator()
	defer iter.Release()

	for iter.Next() {
		token := &Token{}
		if err := json.Unmarshal(iter.Value(), token); err != nil {
			return nil, err
		}
		tokens = append(tokens, token)
	}
	return tokens, nil
}

// Delete deletes an access token by id.
func (cs *CredentialStore) Delete(ctx context.Context, id string) error {
	if !validIDRegexp.MatchString(id) {
		return errors.WithDetailf(ErrBadID, "invalid id %q", id)
	}

	cs.DB.Delete([]byte(id))
	return nil
}
<|endoftext|>


<commit_before>package lfs

import (
	"bytes"
	"fmt"
	"net/http"
	"net/url"
	"os/exec"
	"strings"
)

// getCreds gets the credentials for the given request's URL, and sets its
// Authorization header with them using Basic Authentication. This is like
// getCredsForAPI(), but skips checking the LFS url or git remote.
func getCreds(req *http.Request) (Creds, error) {
	if len(req.Header.Get("Authorization")) > 0 {
		return nil, nil
	}

	creds, err := fillCredentials(req.URL)
	if err != nil {
		return nil, Error(err)
	}

	setRequestAuth(req, creds["username"], creds["password"])
	return creds, nil
}

// getCredsForAPI gets the credentials for LFS API requests and sets the given
// request's Authorization header with them using Basic Authentication.
// 1. Check the LFS URL for authentication. Ex: http://user:pass@example.com
// 2. Check the Git remote URL for authentication IF it's the same scheme and
//    host of the LFS URL.
// 3. Ask 'git credential' to fill in the password from one of the above URLs.
//
// This prefers the Git remote URL for checking credentials so that users only
// have to enter their passwords once for Git and Git LFS. It uses the same
// URL path that Git does, in case 'useHttpPath' is enabled in the Git config.
func getCredsForAPI(req *http.Request) (Creds, error) {
	if len(req.Header.Get("Authorization")) > 0 {
		return nil, nil
	}

	credsUrl, err := getCredURLForAPI(req)
	if err != nil {
		return nil, Error(err)
	}

	if credsUrl == nil {
		return nil, nil
	}

	creds, err := fillCredentials(credsUrl)
	if err != nil {
		return nil, Error(err)
	}

	if creds != nil {
		setRequestAuth(req, creds["username"], creds["password"])
	}

	return creds, nil
}

func getCredURLForAPI(req *http.Request) (*url.URL, error) {
	apiUrl, err := Config.ObjectUrl("")
	if err != nil {
		return nil, err
	}

	// if the LFS request doesn't match the current LFS url, don't bother
	// attempting to set the Authorization header from the LFS or Git remote URLs.
	if req.URL.Scheme != apiUrl.Scheme ||
		req.URL.Host != apiUrl.Host {
		return req.URL, nil
	}

	if setRequestAuthFromUrl(req, apiUrl) {
		return nil, nil
	}

	credsUrl := apiUrl
	if len(Config.CurrentRemote) > 0 {
		if u, ok := Config.GitConfig("remote." + Config.CurrentRemote + ".url"); ok {
			gitRemoteUrl, err := url.Parse(u)
			if err != nil {
				return nil, err
			}

			if gitRemoteUrl.Scheme == apiUrl.Scheme &&
				gitRemoteUrl.Host == apiUrl.Host {

				if setRequestAuthFromUrl(req, gitRemoteUrl) {
					return nil, nil
				}

				credsUrl = gitRemoteUrl
			}
		}
	}

	return credsUrl, nil
}

func fillCredentials(u *url.URL) (Creds, error) {
	path := strings.TrimPrefix(u.Path, "/")
	creds := Creds{"protocol": u.Scheme, "host": u.Host, "path": path}
	return execCreds(creds, "fill")
}

func saveCredentials(creds Creds, res *http.Response) {
	if creds == nil {
		return
	}

	switch res.StatusCode {
	case 401, 403:
		execCreds(creds, "reject")
	default:
		if res.StatusCode < 300 {
			execCreds(creds, "approve")
		}
	}
}

type Creds map[string]string

func (c Creds) Buffer() *bytes.Buffer {
	buf := new(bytes.Buffer)

	for k, v := range c {
		buf.Write([]byte(k))
		buf.Write([]byte("="))
		buf.Write([]byte(v))
		buf.Write([]byte("\n"))
	}

	return buf
}

type credentialFunc func(Creds, string) (Creds, error)

func execCredsCommand(input Creds, subCommand string) (Creds, error) {
	output := new(bytes.Buffer)
	cmd := exec.Command("git", "credential", subCommand)
	cmd.Stdin = input.Buffer()
	cmd.Stdout = output
	/*
		There is a reason we don't hook up stderr here:
		Git's credential cache daemon helper does not close its stderr, so if this
		process is the process that fires up the daemon, it will wait forever
		(until the daemon exits, really) trying to read from stderr.

		See https://github.com/github/git-lfs/issues/117 for more details.
	*/

	err := cmd.Start()
	if err == nil {
		err = cmd.Wait()
	}

	if _, ok := err.(*exec.ExitError); ok {
		if !Config.GetenvBool("GIT_TERMINAL_PROMPT", true) {
			return nil, fmt.Errorf("Change the GIT_TERMINAL_PROMPT env var to be prompted to enter your credentials for %s://%s.",
				input["protocol"], input["host"])
		}

		// 'git credential' exits with 128 if the helper doesn't fill the username
		// and password values.
		if subCommand == "fill" && err.Error() == "exit status 128" {
			return input, nil
		}
	}

	if err != nil {
		return nil, fmt.Errorf("'git credential %s' error: %s\n", subCommand, err.Error())
	}

	creds := make(Creds)
	for _, line := range strings.Split(output.String(), "\n") {
		pieces := strings.SplitN(line, "=", 2)
		if len(pieces) < 2 {
			continue
		}
		creds[pieces[0]] = pieces[1]
	}

	return creds, nil
}

var execCreds credentialFunc = execCredsCommand
<commit_msg>アアー アアアア アー<commit_after>package lfs

import (
	"bytes"
	"fmt"
	"net/http"
	"net/url"
	"os/exec"
	"strings"
)

// getCreds gets the credentials for the given request's URL, and sets its
// Authorization header with them using Basic Authentication. This is like
// getCredsForAPI(), but skips checking the LFS url or git remote.
func getCreds(req *http.Request) (Creds, error) {
	if len(req.Header.Get("Authorization")) > 0 {
		return nil, nil
	}

	creds, err := fillCredentials(req.URL)
	if err != nil {
		return nil, Error(err)
	}

	setRequestAuth(req, creds["username"], creds["password"])
	return creds, nil
}

// getCredsForAPI gets the credentials for LFS API requests and sets the given
// request's Authorization header with them using Basic Authentication.
// 1. Check the LFS URL for authentication. Ex: http://user:pass@example.com
// 2. Check the Git remote URL for authentication IF it's the same scheme and
//    host of the LFS URL.
// 3. Ask 'git credential' to fill in the password from one of the above URLs.
//
// This prefers the Git remote URL for checking credentials so that users only
// have to enter their passwords once for Git and Git LFS. It uses the same
// URL path that Git does, in case 'useHttpPath' is enabled in the Git config.
func getCredsForAPI(req *http.Request) (Creds, error) {
	if len(req.Header.Get("Authorization")) > 0 {
		return nil, nil
	}

	credsUrl, err := getCredURLForAPI(req)
	if err != nil {
		return nil, Error(err)
	}

	if credsUrl == nil {
		return nil, nil
	}

	creds, err := fillCredentials(credsUrl)
	if err != nil {
		return nil, Error(err)
	}

	if creds != nil {
		setRequestAuth(req, creds["username"], creds["password"])
	}

	return creds, nil
}

func getCredURLForAPI(req *http.Request) (*url.URL, error) {
	apiUrl, err := Config.ObjectUrl("")
	if err != nil {
		return nil, err
	}

	// if the LFS request doesn't match the current LFS url, don't bother
	// attempting to set the Authorization header from the LFS or Git remote URLs.
	if req.URL.Scheme != apiUrl.Scheme ||
		req.URL.Host != apiUrl.Host {
		return req.URL, nil
	}

	if setRequestAuthFromUrl(req, apiUrl) {
		return nil, nil
	}

	credsUrl := apiUrl
	if len(Config.CurrentRemote) > 0 {
		if u, ok := Config.GitConfig("remote." + Config.CurrentRemote + ".url"); ok {
			gitRemoteUrl, err := url.Parse(u)
			if err != nil {
				return nil, err
			}

			if gitRemoteUrl.Scheme == apiUrl.Scheme &&
				gitRemoteUrl.Host == apiUrl.Host {

				if setRequestAuthFromUrl(req, gitRemoteUrl) {
					return nil, nil
				}

				credsUrl = gitRemoteUrl
			}
		}
	}

	return credsUrl, nil
}

func fillCredentials(u *url.URL) (Creds, error) {
	path := strings.TrimPrefix(u.Path, "/")
	creds := Creds{"protocol": u.Scheme, "host": u.Host, "path": path}
	if u.User != nil && u.User.Username() != "" {
		creds["username"] = u.User.Username()
	}
	return execCreds(creds, "fill")
}

func saveCredentials(creds Creds, res *http.Response) {
	if creds == nil {
		return
	}

	switch res.StatusCode {
	case 401, 403:
		execCreds(creds, "reject")
	default:
		if res.StatusCode < 300 {
			execCreds(creds, "approve")
		}
	}
}

type Creds map[string]string

func (c Creds) Buffer() *bytes.Buffer {
	buf := new(bytes.Buffer)

	for k, v := range c {
		buf.Write([]byte(k))
		buf.Write([]byte("="))
		buf.Write([]byte(v))
		buf.Write([]byte("\n"))
	}

	return buf
}

type credentialFunc func(Creds, string) (Creds, error)

func execCredsCommand(input Creds, subCommand string) (Creds, error) {
	output := new(bytes.Buffer)
	cmd := exec.Command("git", "credential", subCommand)
	cmd.Stdin = input.Buffer()
	cmd.Stdout = output
	/*
		There is a reason we don't hook up stderr here:
		Git's credential cache daemon helper does not close its stderr, so if this
		process is the process that fires up the daemon, it will wait forever
		(until the daemon exits, really) trying to read from stderr.

		See https://github.com/github/git-lfs/issues/117 for more details.
	*/

	err := cmd.Start()
	if err == nil {
		err = cmd.Wait()
	}

	if _, ok := err.(*exec.ExitError); ok {
		if !Config.GetenvBool("GIT_TERMINAL_PROMPT", true) {
			return nil, fmt.Errorf("Change the GIT_TERMINAL_PROMPT env var to be prompted to enter your credentials for %s://%s.",
				input["protocol"], input["host"])
		}

		// 'git credential' exits with 128 if the helper doesn't fill the username
		// and password values.
		if subCommand == "fill" && err.Error() == "exit status 128" {
			return input, nil
		}
	}

	if err != nil {
		return nil, fmt.Errorf("'git credential %s' error: %s\n", subCommand, err.Error())
	}

	creds := make(Creds)
	for _, line := range strings.Split(output.String(), "\n") {
		pieces := strings.SplitN(line, "=", 2)
		if len(pieces) < 2 {
			continue
		}
		creds[pieces[0]] = pieces[1]
	}

	return creds, nil
}

var execCreds credentialFunc = execCredsCommand
<|endoftext|>


<commit_before>package xbeeapi
/* XBEE API Mode Library
 * http://github.com/coreyshuman/xbeeapi
 * (C) 2016 Corey Shuman
 * 5/26/16
 *
 * License: MIT
 */

import (
	"github.com/coreyshuman/serial"
	"github.com/coreyshuman/srbuf"
	//"time"
	"fmt"
	//"bufio"
	//"bytes"
	"errors"
	"container/list"
	"encoding/hex"
)

// receive handler signature
type RxHandlerFunc func([]byte)

// rx handler struct
type RxHandler struct {
	name string
	frameType byte
	handlerFunc func([]byte)
}

var rxHandlerList *list.List
var quit chan bool

var txBuf *srbuf.SimpleRingBuff
var rxBuf *srbuf.SimpleRingBuff

var errHandler func(error) = nil
var serialXBEE int = -1
var err error

var _frameId int = 1

////////////////////

func Init(dev string, baud int, timeout int) (int, error) {
	txBuf = srbuf.Create(256)
	rxBuf = srbuf.Create(256)
	// initialize a serial interface to the xbee module
	serial.Init()
	serialXBEE, err = serial.Connect(dev, baud, timeout)
	quit = make(chan bool)
	rxHandlerList = list.New()
	return serialXBEE, err
}

func Begin() {
	if serialXBEE == -1 {
		return
	}

	go func() {
		for {
			select {
			case <- quit:
				return
			default:
				processRxData()
				processTxData()
			}
		}
		// if we get here, dispose and exit
		serial.Disconnect(serialXBEE)
	}()
}

func End() {
	quit <- true
}

// cts todo - avoid repeat for same framdId
func AddHandler(frameType byte, f func([]byte)) {
	var handler RxHandler
	handler.name = "test"
	handler.frameType = frameType
	handler.handlerFunc = f
	rxHandlerList.PushBack(handler)
}

func findHandler(frameType byte) RxHandlerFunc {
	for e := rxHandlerList.Front(); e != nil; e = e.Next() {
		if e.Value.(RxHandler).frameType == frameType {
			return e.Value.(RxHandler).handlerFunc
		}
	}
	return nil
}

func SetupErrorHandler(f func(error)) {
	errHandler = f
}

func processRxData() {
	var ret bool = false
	var frameId byte
	var err error
	var d []byte
	var n int

	d = make([]byte, 256)
	n,err = serial.ReadBytes(serialXBEE, d)
	// cts todo - improve this
	if err == nil && n > 0 {

		for i:=0; i<n; i++ {
			rxBuf.PutByte(d[i])
			fmt.Println(fmt.Sprintf("Read:[%02X]", d[i]))
		}
	}

	for !ret {
		avail := rxBuf.AvailByteCnt()
		if(avail < 8) { // 8 bytes is minimum for complete packet
			break
		}
		p := rxBuf.PeekBytes(3)
		if(p[0] != 0x7E) {
			rxBuf.GetByte() // skip byte, increment buffer
			continue
		}
		n := int(p[1])*256 + int(p[2])
		if(avail < n+4) { // not all data received yet, break for now
			break
		}
		ret = true
		// if we get here, packet is ready to parse
		data := rxBuf.GetBytes(n+4)
		switch(data[3]) { // Frame Type
			case 0x88 : // at command response
				frameId, data, err = ParseATCommandResponse(data)
				break

			default:
				err = errors.New("Frame Type not supported: [" + hex.Dump(data[3:4]) + "]")
				break
		}
		if(err != nil) {
			if(errHandler != nil) {
				errHandler(err)
			}
			return
		}
		// fire callback
		handler := findHandler(frameId)
		if(handler != nil) {
			handler(data)
		} else {
			fmt.Println("No Handler")
		}
	}
}

func processTxData() {
	// send data out of serial (XBEE) port
	if txBuf.AvailByteCnt() > 0 {
		data := txBuf.GetBytes(0)
		serial.SendBytes(serialXBEE, data)
	}
}

/* ***************************************************************
 * SendPacket
 * Send data packet as an RF packet to the specified destination
 *
 * 0		- Start Delimiter
 * 1-2		- Length
 * 3		- Frame Type (0x10)
 * 4		- Frame ID
 * 5 - 12	- 64-bit address MSB-LSB
 * 13 - 14	- 16-bit address MSB-LSB
 * 15		- broadcast radius
 * 16		- options
 * 17 - n	- RF data payload
 * n+1		- checksum
 * ***************************************************************/
func SendPacket(address64 []byte, address16 []byte, option byte, data []byte) (d []byte, n int, err error) {
	d = []byte{0x7E, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0xFF, 0xFE, 0x00, 0x00}

	if len(address64) != 8 {
		return d, 0, errors.New("Incorrect Address Length")
	}

	// 64-bit address
	copy(d[5:13], address64)

	if address16 != nil && len(address16) == 2 {
		copy(d[13:15], address16)
	}

	d[16] = option

	d = append(d[:], data[:]...)
	d = append(d[:], 0x00)

	n = len(d)
	d[1] = byte((n-4) / 0x100)
	d[2] = byte((n-4) % 0x100)

	d[n-1] = CalcChecksum(d[3:])

	// cts todo - improve this
	for i := 0; i<len(d); i++ {
		txBuf.PutByte(d[i])
	}

	return
}

/* ***************************************************************
 * SendATCommand
 * Send AT command to the local device and apply changes immediately
 *
 * 0		- Start Delimiter
 * 1-2		- Length
 * 3		- Frame Type (0x08)
 * 4		- Frame ID
 * 5 - 6	- AT command
 * 			- optional parameter
 * 7		- checksum
 * ***************************************************************/
func SendATCommand(command []byte, param []byte) (d []byte, n int, err error) {
	d = []byte{0x7E, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00}

	if len(command) != 2 {
		return d, 0, errors.New("Incorrect AT Command Length")
	}

	d[4] = byte(_frameId)
	_frameId ++ // cts todo - make this better
	d[5] = command[0]
	d[6] = command[1]

	// copy param if exists
	d = append(d[:], param...)
	d = append(d[:], 0x00)

	n = len(d)
	d[1] = byte((n-4) / 0x100)
	d[2] = byte((n-4) % 0x100)

	d[n-1] = CalcChecksum(d[3:])

	// cts todo - improve this
	for i := 0; i<len(d); i++ {
		txBuf.PutByte(d[i])
	}

	return
}

func CalcChecksum(data []byte)(byte) {
	n := len(data)
	var cs byte = 0

	for i := 0; i < n-1; i++ {
		cs += data[i]
	}
	return 0xFF - cs
}

/* ***************************************************************
 * ParseATCommandResponse
 * Parse an AT Command response from XBEE
 *
 * 0		- Start Delimiter
 * 1-2		- Length
 * 3		- Frame Type (0x88)
 * 4		- Frame ID
 * 5 - 6	- AT command
 * 			- optional command data
 * 7		- checksum
 * ***************************************************************/
func ParseATCommandResponse(r []byte) (frameId byte, data []byte, err error) {
	err = nil
	if(r[3] != 0x88) {
		return 0, nil, errors.New("Invalid Frame Type")
	}

	n := int(r[1])*256 + int(r[2])

	if(n != len(r) - 4) {
		return 0, nil, errors.New("Frame Length Error: " + fmt.Sprintf("%d, %d", n, len(r)-4))
	}

	check := CalcChecksum(r[3:n+3])
	if(check != r[n+3]) {
		return 0, nil, errors.New(fmt.Sprintf( "Checksum Error: calc=[%02X] read=[%02X]", check, r[n+3] ) )
	}

	// prepare return data
	frameId = r[3]

	if(n > 5) {
		data = r[8:3+n] // 8:8+n-5
	} else {
		data = nil
	}

	return
}

<commit_msg>devel<commit_after>package xbeeapi
/* XBEE API Mode Library
 * http://github.com/coreyshuman/xbeeapi
 * (C) 2016 Corey Shuman
 * 5/26/16
 *
 * License: MIT
 */

import (
	"github.com/coreyshuman/serial"
	"github.com/coreyshuman/srbuf"
	//"time"
	"fmt"
	//"bufio"
	//"bytes"
	"errors"
	"container/list"
	"encoding/hex"
)

// receive handler signature
type RxHandlerFunc func([]byte)

// rx handler struct
type RxHandler struct {
	name string
	frameType byte
	handlerFunc func([]byte)
}

var rxHandlerList *list.List
var quit chan bool

var txBuf *srbuf.SimpleRingBuff
var rxBuf *srbuf.SimpleRingBuff

var errHandler func(error) = nil
var serialXBEE int = -1
var err error

var _frameId int = 1

////////////////////

func Init(dev string, baud int, timeout int) (int, error) {
	txBuf = srbuf.Create(256)
	rxBuf = srbuf.Create(256)
	// initialize a serial interface to the xbee module
	serial.Init()
	serialXBEE, err = serial.Connect(dev, baud, timeout)
	quit = make(chan bool)
	rxHandlerList = list.New()
	return serialXBEE, err
}

func Begin() {
	if serialXBEE == -1 {
		return
	}

	go func() {
		for {
			select {
			case <- quit:
				return
			default:
				processRxData()
				processTxData()
			}
		}
		// if we get here, dispose and exit
		serial.Disconnect(serialXBEE)
	}()
}

func End() {
	quit <- true
}

// cts todo - avoid repeat for same framdId
func AddHandler(frameType byte, f func([]byte)) {
	var handler RxHandler
	handler.name = "test"
	handler.frameType = frameType
	handler.handlerFunc = f
	rxHandlerList.PushBack(handler)
}

func findHandler(frameType byte) RxHandlerFunc {
	for e := rxHandlerList.Front(); e != nil; e = e.Next() {
		if e.Value.(RxHandler).frameType == frameType {
			return e.Value.(RxHandler).handlerFunc
		}
	}
	return nil
}

func SetupErrorHandler(f func(error)) {
	errHandler = f
}

func processRxData() {
	var ret bool = false
	var frameId byte
	var err error
	var d []byte
	var n int

	d = make([]byte, 256)
	n,err = serial.ReadBytes(serialXBEE, d)
	// cts todo - improve this
	if err == nil && n > 0 {

		for i:=0; i<n; i++ {
			rxBuf.PutByte(d[i])
			fmt.Println(fmt.Sprintf("Read:[%02X]", d[i]))
		}
	}

	for !ret {
		avail := rxBuf.AvailByteCnt()
		if(avail < 8) { // 8 bytes is minimum for complete packet
			break
		}
		p := rxBuf.PeekBytes(3)
		if(p[0] != 0x7E) {
			rxBuf.GetByte() // skip byte, increment buffer
			continue
		}
		n := int(p[1])*256 + int(p[2])
		if(avail < n+4) { // not all data received yet, break for now
			break
		}
		ret = true
		// if we get here, packet is ready to parse
		data := rxBuf.GetBytes(n+4)
		switch(data[3]) { // Frame Type
			case 0x88 : // at command response
				frameId, data, err = ParseATCommandResponse(data)
				break

			default:
				err = errors.New("Frame Type not supported: [" + hex.Dump(data[3:4]) + "]")
				break
		}
		if(err != nil) {
			if(errHandler != nil) {
				errHandler(err)
			}
			return
		}
		// fire callback
		handler := findHandler(frameId)
		if(handler != nil) {
			handler(data)
		} else {
			fmt.Println("No Handler")
		}
	}
}

func processTxData() {
	// send data out of serial (XBEE) port
	if txBuf.AvailByteCnt() > 0 {
		data := txBuf.GetBytes(0)
		serial.SendBytes(serialXBEE, data)
	}
}

/* ***************************************************************
 * SendPacket
 * Send data packet as an RF packet to the specified destination
 *
 * 0		- Start Delimiter
 * 1-2		- Length
 * 3		- Frame Type (0x10)
 * 4		- Frame ID
 * 5 - 12	- 64-bit address MSB-LSB
 * 13 - 14	- 16-bit address MSB-LSB
 * 15		- broadcast radius
 * 16		- options
 * 17 - n	- RF data payload
 * n+1		- checksum
 * ***************************************************************/
func SendPacket(address64 []byte, address16 []byte, option byte, data []byte) (d []byte, n int, err error) {
	d = []byte{0x7E, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
				0xFF, 0xFE, 0x00, 0x00}

	if len(address64) != 8 {
		return d, 0, errors.New("Incorrect Address Length")
	}

	// 64-bit address
	copy(d[5:13], address64)

	if address16 != nil && len(address16) == 2 {
		copy(d[13:15], address16)
	}

	d[16] = option

	d = append(d[:], data[:]...)
	d = append(d[:], 0x00)

	n = len(d)
	d[1] = byte((n-4) / 0x100)
	d[2] = byte((n-4) % 0x100)

	d[n-1] = CalcChecksum(d[3:])

	// cts todo - improve this
	for i := 0; i<len(d); i++ {
		txBuf.PutByte(d[i])
	}

	return
}

/* ***************************************************************
 * SendATCommand
 * Send AT command to the local device and apply changes immediately
 *
 * 0		- Start Delimiter
 * 1-2		- Length
 * 3		- Frame Type (0x08)
 * 4		- Frame ID
 * 5 - 6	- AT command
 * 			- optional parameter
 * 7		- checksum
 * ***************************************************************/
func SendATCommand(command []byte, param []byte) (d []byte, n int, err error) {
	d = []byte{0x7E, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00}

	if len(command) != 2 {
		return d, 0, errors.New("Incorrect AT Command Length")
	}

	d[4] = byte(_frameId)
	_frameId ++ // cts todo - make this better
	d[5] = command[0]
	d[6] = command[1]

	// copy param if exists
	d = append(d[:], param...)
	d = append(d[:], 0x00)

	n = len(d)
	d[1] = byte((n-4) / 0x100)
	d[2] = byte((n-4) % 0x100)

	d[n-1] = CalcChecksum(d[3:])

	// cts todo - improve this
	for i := 0; i<len(d); i++ {
		txBuf.PutByte(d[i])
	}

	return
}

func CalcChecksum(data []byte)(byte) {
	n := len(data)
	var cs byte = 0

	for i := 0; i < n; i++ {
		cs += data[i]
	}
	return 0xFF - cs
}

/* ***************************************************************
 * ParseATCommandResponse
 * Parse an AT Command response from XBEE
 *
 * 0		- Start Delimiter
 * 1-2		- Length
 * 3		- Frame Type (0x88)
 * 4		- Frame ID
 * 5 - 6	- AT command
 * 			- optional command data
 * 7		- checksum
 * ***************************************************************/
func ParseATCommandResponse(r []byte) (frameId byte, data []byte, err error) {
	err = nil
	if(r[3] != 0x88) {
		return 0, nil, errors.New("Invalid Frame Type")
	}

	n := int(r[1])*256 + int(r[2])

	if(n != len(r) - 4) {
		return 0, nil, errors.New("Frame Length Error: " + fmt.Sprintf("%d, %d", n, len(r)-4))
	}

	check := CalcChecksum(r[3:n+3])
	if(check != r[n+3]) {
		return 0, nil, errors.New(fmt.Sprintf( "Checksum Error: calc=[%02X] read=[%02X]", check, r[n+3] ) )
	}

	// prepare return data
	frameId = r[3]

	if(n > 5) {
		data = r[8:3+n] // 8:8+n-5
	} else {
		data = nil
	}

	return
}

<|endoftext|>


<commit_before>package util

import (
	"io"

	util_capnp "zenhack.net/go/sandstorm/capnp/util"
)

type byteStreamPipeWriter struct {
	w        *io.PipeWriter
	isClosed bool
}

func (w *byteStreamPipeWriter) ExpectSize(p util_capnp.ByteStream_expectSize) error {
	if w.isClosed {
		return io.ErrClosedPipe
	}
	return nil
}

func (w *byteStreamPipeWriter) Write(p util_capnp.ByteStream_write) error {
	if w.isClosed {
		return io.ErrClosedPipe
	}
	data, err := p.Params.Data()
	if err != nil {
		w.w.CloseWithError(err)
		w.isClosed = true
		return err
	}
	_, err = w.w.Write(data)
	return err
}

func (w *byteStreamPipeWriter) Done(p util_capnp.ByteStream_done) error {
	if w.isClosed {
		return io.ErrClosedPipe
	}
	w.isClosed = true
	return w.w.Close()
}

func (w *byteStreamPipeWriter) Close() error {
	if !w.isClosed {
		w.w.CloseWithError(io.ErrUnexpectedEOF)
		w.isClosed = true
	}
	return nil
}

func ByteStreamPipe() (*io.PipeReader, util_capnp.ByteStream) {
	r, w := io.Pipe()
	return r, util_capnp.ByteStream_ServerToClient(&byteStreamPipeWriter{
		w:        w,
		isClosed: false,
	})
}
<commit_msg>Add docs for ByteStreamPipe<commit_after>package util

import (
	"io"

	util_capnp "zenhack.net/go/sandstorm/capnp/util"
)

// ByteStreamPipe is like io.Pipe, except that the write end is a ByteStream.
//
// The ByteStream's ExpectSize method is a noop.
//
// Once Done is called on the ByteStream, reads will return io.EOF.
//
// If all references to the ByteStream are dropped before Done is called, reads
// will return io.ErrUnexpectedEOF.
func ByteStreamPipe() (*io.PipeReader, util_capnp.ByteStream) {
	r, w := io.Pipe()
	return r, util_capnp.ByteStream_ServerToClient(&byteStreamPipeWriter{
		w:        w,
		isClosed: false,
	})
}

// The type that powers ByteStreamPipe; see the comments there for an overview.
type byteStreamPipeWriter struct {
	w        *io.PipeWriter
	isClosed bool
}

func (w *byteStreamPipeWriter) ExpectSize(p util_capnp.ByteStream_expectSize) error {
	if w.isClosed {
		return io.ErrClosedPipe
	}
	return nil
}

func (w *byteStreamPipeWriter) Write(p util_capnp.ByteStream_write) error {
	if w.isClosed {
		return io.ErrClosedPipe
	}
	data, err := p.Params.Data()
	if err != nil {
		w.w.CloseWithError(err)
		w.isClosed = true
		return err
	}
	_, err = w.w.Write(data)
	return err
}

func (w *byteStreamPipeWriter) Done(p util_capnp.ByteStream_done) error {
	if w.isClosed {
		return io.ErrClosedPipe
	}
	w.isClosed = true
	return w.w.Close()
}

func (w *byteStreamPipeWriter) Close() error {
	if !w.isClosed {
		w.w.CloseWithError(io.ErrUnexpectedEOF)
		w.isClosed = true
	}
	return nil
}
<|endoftext|>


<commit_before>/*
 * tracker.go
 *
 * The tracker code pulls double duty as both our tracker (helps peers find each other) but
 * is also the endpoint where people download torrent files.
 *
 * Copyright (c) 2014 by authors and contributors. Please see the included LICENSE file for
 * licensing information.
 *
 */

package torrent

import (
	"errors"
	"fmt"
	bencode "github.com/jackpal/bencode-go"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"time"
)

type Peer struct {
	Id   string `peer id`
	Ip   string `ip`
	Port uint16 `port`
}

type PeerResponse struct {
	Interval int    `interval`
	Peers    []Peer `peers`
}

type Tracker struct {
	// We keep a separate set of peers for each info_hash. We don't actually verify that these
	// hashes are valid; so there's a pretty easy DoS here. This system is designed to be used
	// in a production environment with good actors. TODO: harden.
	// TODO: We need a way of droppign peers that have not reported in a while.
	PeerSeen     map[string]map[string]time.Time
	PeerList     map[string]map[string]Peer
	peerListLock sync.Mutex

	// Lock used by all methods that affect the seed process.
	seedStartLock sync.Mutex

	// The key in the watchers map is how these watchers can be queried for the latest data
	// see handleServeLastUpdated()
	//
	// Careful: there is no locking here. It's assumed that the only time this is
	// written is from the very initial setup of the app and never during runtime. If that
	// changes we'll need locking. (This may actually be technically a little racy right
	// now if there's a ton of requests during power-on, since we start listening
	// before the watchers are created.)
	watchers map[string]*Watcher // List of watchers who might have files.
	ctorrent string              // path to the ctorrent executable.
}

// findFile searches all of our watchers for a given filename (FQFN). If found, it returns
// the pointer to the File structure representing this file.
func (self *Tracker) findFile(name string) *File {
	for _, watcher := range self.watchers {
		if file := watcher.GetFile(name); file != nil {
			return file
		}
	}
	return nil
}

// findLastUpdatedFile goes through all the watchers and returns the file with the latest
// modification time or nil if no such file could be found; only considers files that have
// non-nil metadata, as there are cases where we don't generate metadata for files
// that exist (e.g. 0-length)
func (self *Tracker) findLastUpdatedFile(watchers []*Watcher) *File {
	var last_updated *File = nil
	for _, watcher := range watchers {
		for _, file := range watcher.GetFiles() {
			file.Lock.Lock()
			if file.MetadataInfo == nil {
				file.Lock.Unlock()
				continue
			}
			file.Lock.Unlock()
			if last_updated == nil || file.ModTime.After(last_updated.ModTime) {
				last_updated = file
			}
		}
	}
	return last_updated
}

// startSeed attempts to start up a seeding process for a given torrent file.
func (self *Tracker) startSeed(file *File, metadata *Metadata) {
	self.seedStartLock.Lock()

	if file.SeedCommand != nil {
		self.seedStartLock.Unlock()
		return
	}

	tmp, err := ioutil.TempFile("", "distributor.")
	if err != nil {
		LogFatal("TempFile failed: %s", err)
	}
	LogDebug("Temporary file for %s: %s", file.Name, tmp.Name())

	err = bencode.Marshal(tmp, *metadata)
	if err != nil {
		self.seedStartLock.Unlock()
		LogError("Failed to bencode %s: %s", file.Name, err)
		return
	}

	err = tmp.Sync()
	if err != nil {
		self.seedStartLock.Unlock()
		LogError("Failed to fsync: %s", err)
		return
	}

	file.SeedCommand = exec.Command(
		self.ctorrent,
		"-s",
		file.FQFN,
		"-e",
		"4",
		"-p",
		"8999",
		tmp.Name())
	self.seedStartLock.Unlock()

	// TODO: Read from output pipes, because they could fill up?

	go func() {
		LogDebug("Seed starting: %s", file.Name)
		file.SeedCommand.Run()
		LogDebug("Seed exited: %s", file.Name)

		// Try to clean up temporary file.
		tmp.Close()
		os.Remove(tmp.Name())

		// Seeds exit after 4 hours. Then they get restarted if someone requests them.
		self.seedStartLock.Lock()
		file.SeedCommand = nil
		self.seedStartLock.Unlock()
	}()
}

// handleServe is the endpoint that is responsible for generating torrent files and giving them
// out to the requestors.
// TODO: how to return 404 etc from here?
func (self *Tracker) handleServe(w http.ResponseWriter, r *http.Request) {
	LogDebug("Request: %s", r.URL.RequestURI())
	pieces := strings.SplitN(r.URL.RequestURI(), "?", 2)
	if len(pieces) != 2 {
		io.WriteString(w, "invalid request")
		return
	}

	file := self.findFile(pieces[1])
	self.serveFile(w, r, file)
}

// handleServeLatest is the endpoint that is responsible for serving the latest file that was updated
func (self *Tracker) handleServeLastUpdated(w http.ResponseWriter, r *http.Request) {
	LogDebug("Request: %s", r.URL.RequestURI())

	var query_watchers []*Watcher

	pieces := strings.SplitN(r.URL.RequestURI(), "?", 2)
	if len(pieces) > 2 {
		io.WriteString(w, "invalid request")
		return
	} else if len(pieces) == 2 {
		// query the specified watcher
		watcher := self.watchers[pieces[1]]
		if watcher == nil {
			io.WriteString(w, "invalid watcher name")
			return
		}
		query_watchers = append(query_watchers, watcher)
	} else {
		// query all watchers
		for _, watcher := range self.watchers {
			query_watchers = append(query_watchers, watcher)
		}
	}

	file := self.findLastUpdatedFile(query_watchers)
	self.serveFile(w, r, file)
}

func (self *Tracker) serveFile(w http.ResponseWriter, r *http.Request, file *File) {
	if file == nil {
		http.Error(w, "File not found", 404)
		return
	}

	for {
		// TODO: This could run infinitely in a case where the file is requested and deleted or
		// replaced, so we keep checking a structure that never will get filled in since it's no
		// longer active.
		file.Lock.Lock()
		if file.MetadataInfo == nil {
			file.Lock.Unlock()
			LogDebug("Request for missing metadata on %v. Sleeping.", file.Name)
			time.Sleep(1 * time.Second)
			continue
		}
		file.Lock.Unlock()
		break
	}

	file.Lock.Lock()
	md := Metadata{
		// Using Host like this is probably safe, but is potentially a hack.
		Announce: fmt.Sprintf("http://%s/announce", r.Host),
		Info:     *file.MetadataInfo,
	}
	file.Lock.Unlock()

	if file.SeedCommand == nil {
		self.startSeed(file, &md)
	}

	err := bencode.Marshal(w, md)
	if err != nil {
		LogError("Failed to bencode %s: %s", file.Name, err)
	}
}

// parsePeer extracts a Peer structure from a query string.
func parsePeer(r *http.Request, values url.Values) (*Peer, error) {
	var peer_id, ip, strport []string
	ok := true

	// I don't know how to make this cleaner in Go. Halp. :-(
	peer_id, ok = values["peer_id"]
	if ok && len(peer_id) == 1 {
		strport, ok = values["port"]
	}
	if !ok {
		return nil, errors.New("missing required argument")
	}

	ip, ok = values["ip"]
	if !ok {
		// TODO: This seems fragile.
		addr := strings.Split(r.RemoteAddr, ":")
		if len(addr) != 2 {
			LogFatal("Got weird address: %s", r.RemoteAddr)
		}
		ip = []string{addr[0]}
	}

	port, err := strconv.ParseUint(strport[0], 10, 16)
	if err != nil {
		return nil, errors.New("port invalid")
	}

	return &Peer{
		Id:   peer_id[0],
		Ip:   ip[0],
		Port: uint16(port),
	}, nil
}

// handleAnnounce is the endpoint for torrent clients to announce themselves and request
// other peers.
func (self *Tracker) handleAnnounce(w http.ResponseWriter, r *http.Request) {
	values := r.URL.Query()

	peer, err := parsePeer(r, values)
	if err != nil {
		io.WriteString(w, err.Error())
		return
	}
	LogDebug("Request from peer at %s:%d.", peer.Ip, peer.Port)

	// Get other arguments and validate them.
	var info_hash string
	if info_hash_list, ok := values["info_hash"]; ok && len(info_hash_list) == 1 {
		info_hash = info_hash_list[0]
	}

	var event string
	if event_list, ok := values["event"]; ok && len(event_list) == 1 {
		event = event_list[0]
	}

	var numwant uint64
	if numwant_list, ok := values["numwant"]; ok && len(numwant_list) == 1 {
		numwant, err = strconv.ParseUint(numwant_list[0], 10, 8)
		if err != nil || numwant > 100 {
			numwant = 100
		}
	} else {
		numwant = 50
	}

	// Lock this now since we're validated our inputs.
	self.peerListLock.Lock()
	defer self.peerListLock.Unlock()

	peers, ok := self.PeerList[info_hash]
	if !ok {
		peers = make(map[string]Peer)
		self.PeerList[info_hash] = peers
	}

	peerseen, ok := self.PeerSeen[info_hash]
	if !ok {
		peerseen = make(map[string]time.Time)
		self.PeerSeen[info_hash] = peerseen
	}

	var peerage time.Duration
	peerlastseen, pok := peerseen[peer.Id]
	if pok {
		peerage = time.Since(peerlastseen)
	}

	// Add this peer to the set if they don't exist, plus possibly purge other peers on this IP and port.
	if _, ok := peers[peer.Id]; !ok {
		// Remove any other peers on this IP address and port. This is kind of a hack since we don't have
		// "last reported time" at the moment. If a new peer starts up on a host, then we remove
		// the other one.
		toRemove := make([]string, 0, 10)
		for id, tmpPeer := range peers {
			if (tmpPeer.Ip == peer.Ip && tmpPeer.Port == peer.Port) || (pok && peerage > 300*time.Second) {
				toRemove = append(toRemove, id)
			}
		}
		for _, id := range toRemove {
			delete(peers, id)
			delete(peerseen, id)
		}

		// Finally insert this new peer.
		peers[peer.Id] = *peer
	}

	// Always update the timestamp so we know when people report.
	peerseen[peer.Id] = time.Now()

	// If they're stopping, then remove this peer from the valid list.
	if event == "stopped" {
		LogInfo("Peer %s:%d is leaving the swarm.", peer.Ip, peer.Port)
		delete(peers, peer.Id)
		delete(peerseen, peer.Id)
	}

	// We give the user back N random peers by just picking a window into our peer list.
	ct := 0
	outPeers := make([]Peer, 0, numwant)
	for _, tmpPeer := range peers {
		if ct++; ct > cap(outPeers) {
			break
		}

		if tmpPeer.Ip == peer.Ip && tmpPeer.Port == peer.Port {
			// This helps avoid giving peers connections to their own machine, which seems
			// to confuse ctorrent. It seems to mostly affect small clusters.
			continue
		}
		outPeers = append(outPeers, tmpPeer)
		LogDebug("[%s:%d] peer %s:%d", peer.Ip, peer.Port, tmpPeer.Ip, tmpPeer.Port)
	}
	LogInfo("Giving peer %s:%d a list of %d peers (out of %d).",
		peer.Ip, peer.Port, len(outPeers), len(peers))

	// Build the output dictionary and return it.
	err = bencode.Marshal(w, PeerResponse{Interval: rand.Intn(120) + 300, Peers: outPeers})
	if err != nil {
		LogError("Failed to bencode: %s", err)
	}
}

// starTracker spins up a tracker on a given ip:port for the given set of watchers.
func StartTracker(ip string, port int,
	ctorrentPath string,
	watchers map[string]*Watcher) *Tracker {
	tracker := &Tracker{
		PeerList: make(map[string]map[string]Peer),
		PeerSeen: make(map[string]map[string]time.Time),
		watchers: watchers,
		ctorrent: ctorrentPath,
	}

	http.HandleFunc("/serve", tracker.handleServe)
	http.HandleFunc("/serve_last_updated", tracker.handleServeLastUpdated)
	http.HandleFunc("/announce", tracker.handleAnnounce)

	go func() {
		err := http.ListenAndServe(fmt.Sprintf("%s:%d", ip, port), nil)
		LogFatal("HTTP server exited: %s", err)
	}()

	return tracker
}
<commit_msg>Remove old peers<commit_after>/*
 * tracker.go
 *
 * The tracker code pulls double duty as both our tracker (helps peers find each other) but
 * is also the endpoint where people download torrent files.
 *
 * Copyright (c) 2014 by authors and contributors. Please see the included LICENSE file for
 * licensing information.
 *
 */

package torrent

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"time"

	bencode "github.com/jackpal/bencode-go"
)

type Peer struct {
	Id   string `peer id`
	Ip   string `ip`
	Port uint16 `port`
}

type PeerResponse struct {
	Interval int    `interval`
	Peers    []Peer `peers`
}

type Tracker struct {
	// We keep a separate set of peers for each info_hash. We don't actually verify that these
	// hashes are valid; so there's a pretty easy DoS here. This system is designed to be used
	// in a production environment with good actors. TODO: harden.
	// TODO: We need a way of droppign peers that have not reported in a while.
	PeerSeen     map[string]map[string]time.Time
	PeerList     map[string]map[string]Peer
	peerListLock sync.Mutex

	// Lock used by all methods that affect the seed process.
	seedStartLock sync.Mutex

	// The key in the watchers map is how these watchers can be queried for the latest data
	// see handleServeLastUpdated()
	//
	// Careful: there is no locking here. It's assumed that the only time this is
	// written is from the very initial setup of the app and never during runtime. If that
	// changes we'll need locking. (This may actually be technically a little racy right
	// now if there's a ton of requests during power-on, since we start listening
	// before the watchers are created.)
	watchers map[string]*Watcher // List of watchers who might have files.
	ctorrent string              // path to the ctorrent executable.
}

// findFile searches all of our watchers for a given filename (FQFN). If found, it returns
// the pointer to the File structure representing this file.
func (self *Tracker) findFile(name string) *File {
	for _, watcher := range self.watchers {
		if file := watcher.GetFile(name); file != nil {
			return file
		}
	}
	return nil
}

// findLastUpdatedFile goes through all the watchers and returns the file with the latest
// modification time or nil if no such file could be found; only considers files that have
// non-nil metadata, as there are cases where we don't generate metadata for files
// that exist (e.g. 0-length)
func (self *Tracker) findLastUpdatedFile(watchers []*Watcher) *File {
	var last_updated *File = nil
	for _, watcher := range watchers {
		for _, file := range watcher.GetFiles() {
			file.Lock.Lock()
			if file.MetadataInfo == nil {
				file.Lock.Unlock()
				continue
			}
			file.Lock.Unlock()
			if last_updated == nil || file.ModTime.After(last_updated.ModTime) {
				last_updated = file
			}
		}
	}
	return last_updated
}

// startSeed attempts to start up a seeding process for a given torrent file.
func (self *Tracker) startSeed(file *File, metadata *Metadata) {
	self.seedStartLock.Lock()

	if file.SeedCommand != nil {
		self.seedStartLock.Unlock()
		return
	}

	tmp, err := ioutil.TempFile("", "distributor.")
	if err != nil {
		LogFatal("TempFile failed: %s", err)
	}
	LogDebug("Temporary file for %s: %s", file.Name, tmp.Name())

	err = bencode.Marshal(tmp, *metadata)
	if err != nil {
		self.seedStartLock.Unlock()
		LogError("Failed to bencode %s: %s", file.Name, err)
		return
	}

	err = tmp.Sync()
	if err != nil {
		self.seedStartLock.Unlock()
		LogError("Failed to fsync: %s", err)
		return
	}

	file.SeedCommand = exec.Command(
		self.ctorrent,
		"-s",
		file.FQFN,
		"-e",
		"4",
		"-p",
		"8999",
		tmp.Name())
	self.seedStartLock.Unlock()

	// TODO: Read from output pipes, because they could fill up?

	go func() {
		LogDebug("Seed starting: %s", file.Name)
		file.SeedCommand.Run()
		LogDebug("Seed exited: %s", file.Name)

		// Try to clean up temporary file.
		tmp.Close()
		os.Remove(tmp.Name())

		// Seeds exit after 4 hours. Then they get restarted if someone requests them.
		self.seedStartLock.Lock()
		file.SeedCommand = nil
		self.seedStartLock.Unlock()
	}()
}

// handleServe is the endpoint that is responsible for generating torrent files and giving them
// out to the requestors.
// TODO: how to return 404 etc from here?
func (self *Tracker) handleServe(w http.ResponseWriter, r *http.Request) {
	LogDebug("Request: %s", r.URL.RequestURI())
	pieces := strings.SplitN(r.URL.RequestURI(), "?", 2)
	if len(pieces) != 2 {
		io.WriteString(w, "invalid request")
		return
	}

	file := self.findFile(pieces[1])
	self.serveFile(w, r, file)
}

// handleServeLatest is the endpoint that is responsible for serving the latest file that was updated
func (self *Tracker) handleServeLastUpdated(w http.ResponseWriter, r *http.Request) {
	LogDebug("Request: %s", r.URL.RequestURI())

	var query_watchers []*Watcher

	pieces := strings.SplitN(r.URL.RequestURI(), "?", 2)
	if len(pieces) > 2 {
		io.WriteString(w, "invalid request")
		return
	} else if len(pieces) == 2 {
		// query the specified watcher
		watcher := self.watchers[pieces[1]]
		if watcher == nil {
			io.WriteString(w, "invalid watcher name")
			return
		}
		query_watchers = append(query_watchers, watcher)
	} else {
		// query all watchers
		for _, watcher := range self.watchers {
			query_watchers = append(query_watchers, watcher)
		}
	}

	file := self.findLastUpdatedFile(query_watchers)
	self.serveFile(w, r, file)
}

func (self *Tracker) serveFile(w http.ResponseWriter, r *http.Request, file *File) {
	if file == nil {
		http.Error(w, "File not found", 404)
		return
	}

	for {
		// TODO: This could run infinitely in a case where the file is requested and deleted or
		// replaced, so we keep checking a structure that never will get filled in since it's no
		// longer active.
		file.Lock.Lock()
		if file.MetadataInfo == nil {
			file.Lock.Unlock()
			LogDebug("Request for missing metadata on %v. Sleeping.", file.Name)
			time.Sleep(1 * time.Second)
			continue
		}
		file.Lock.Unlock()
		break
	}

	file.Lock.Lock()
	md := Metadata{
		// Using Host like this is probably safe, but is potentially a hack.
		Announce: fmt.Sprintf("http://%s/announce", r.Host),
		Info:     *file.MetadataInfo,
	}
	file.Lock.Unlock()

	if file.SeedCommand == nil {
		self.startSeed(file, &md)
	}

	err := bencode.Marshal(w, md)
	if err != nil {
		LogError("Failed to bencode %s: %s", file.Name, err)
	}
}

// parsePeer extracts a Peer structure from a query string.
func parsePeer(r *http.Request, values url.Values) (*Peer, error) {
	var peer_id, ip, strport []string
	ok := true

	// I don't know how to make this cleaner in Go. Halp. :-(
	peer_id, ok = values["peer_id"]
	if ok && len(peer_id) == 1 {
		strport, ok = values["port"]
	}
	if !ok {
		return nil, errors.New("missing required argument")
	}

	ip, ok = values["ip"]
	if !ok {
		// TODO: This seems fragile.
		addr := strings.Split(r.RemoteAddr, ":")
		if len(addr) != 2 {
			LogFatal("Got weird address: %s", r.RemoteAddr)
		}
		ip = []string{addr[0]}
	}

	port, err := strconv.ParseUint(strport[0], 10, 16)
	if err != nil {
		return nil, errors.New("port invalid")
	}

	return &Peer{
		Id:   peer_id[0],
		Ip:   ip[0],
		Port: uint16(port),
	}, nil
}

// handleAnnounce is the endpoint for torrent clients to announce themselves and request
// other peers.
func (self *Tracker) handleAnnounce(w http.ResponseWriter, r *http.Request) {
	values := r.URL.Query()

	peer, err := parsePeer(r, values)
	if err != nil {
		io.WriteString(w, err.Error())
		return
	}
	LogDebug("Request from peer at %s:%d.", peer.Ip, peer.Port)

	// Get other arguments and validate them.
	var info_hash string
	if info_hash_list, ok := values["info_hash"]; ok && len(info_hash_list) == 1 {
		info_hash = info_hash_list[0]
	}

	var event string
	if event_list, ok := values["event"]; ok && len(event_list) == 1 {
		event = event_list[0]
	}

	var numwant uint64
	if numwant_list, ok := values["numwant"]; ok && len(numwant_list) == 1 {
		numwant, err = strconv.ParseUint(numwant_list[0], 10, 8)
		if err != nil || numwant > 100 {
			numwant = 100
		}
	} else {
		numwant = 50
	}

	// Lock this now since we're validated our inputs.
	self.peerListLock.Lock()
	defer self.peerListLock.Unlock()

	peers, ok := self.PeerList[info_hash]
	if !ok {
		peers = make(map[string]Peer)
		self.PeerList[info_hash] = peers
	}

	peerseen, ok := self.PeerSeen[info_hash]
	if !ok {
		peerseen = make(map[string]time.Time)
		self.PeerSeen[info_hash] = peerseen
	}

	// Add this peer to the set if they don't exist, plus possibly purge other peers on this IP and port.
	if _, ok := peers[peer.Id]; !ok {
		// Remove any other peers on this IP address and port. This is kind of a hack since we don't have
		// "last reported time" at the moment. If a new peer starts up on a host, then we remove
		// the other one.
		toRemove := make([]string, 0, 10)
		for id, tmpPeer := range peers {
			if tmpPeer.Ip == peer.Ip && tmpPeer.Port == peer.Port {
				toRemove = append(toRemove, id)
			}
		}
		for _, id := range toRemove {
			delete(peers, id)
			delete(peerseen, id)
		}

		// Finally insert this new peer.
		peers[peer.Id] = *peer
	}

	// Always update the timestamp so we know when people report.
	peerseen[peer.Id] = time.Now()

	// Remove old peers.
	for id := range peers {
		peerlastseen, pok := peerseen[id]
		if pok && time.Since(peerlastseen) > 300*time.Second {
			delete(peers, id)
			delete(peerseen, id)
		}
	}

	// If they're stopping, then remove this peer from the valid list.
	if event == "stopped" {
		LogInfo("Peer %s:%d is leaving the swarm.", peer.Ip, peer.Port)
		delete(peers, peer.Id)
		delete(peerseen, peer.Id)
	}

	// We give the user back N random peers by just picking a window into our peer list.
	ct := 0
	outPeers := make([]Peer, 0, numwant)
	for _, tmpPeer := range peers {
		if ct++; ct > cap(outPeers) {
			break
		}

		if tmpPeer.Ip == peer.Ip && tmpPeer.Port == peer.Port {
			// This helps avoid giving peers connections to their own machine, which seems
			// to confuse ctorrent. It seems to mostly affect small clusters.
			continue
		}
		outPeers = append(outPeers, tmpPeer)
		LogDebug("[%s:%d] peer %s:%d", peer.Ip, peer.Port, tmpPeer.Ip, tmpPeer.Port)
	}
	LogInfo("Giving peer %s:%d a list of %d peers (out of %d).",
		peer.Ip, peer.Port, len(outPeers), len(peers))

	// Build the output dictionary and return it.
	err = bencode.Marshal(w, PeerResponse{Interval: rand.Intn(120) + 300, Peers: outPeers})
	if err != nil {
		LogError("Failed to bencode: %s", err)
	}
}

// starTracker spins up a tracker on a given ip:port for the given set of watchers.
func StartTracker(ip string, port int,
	ctorrentPath string,
	watchers map[string]*Watcher) *Tracker {
	tracker := &Tracker{
		PeerList: make(map[string]map[string]Peer),
		PeerSeen: make(map[string]map[string]time.Time),
		watchers: watchers,
		ctorrent: ctorrentPath,
	}

	http.HandleFunc("/serve", tracker.handleServe)
	http.HandleFunc("/serve_last_updated", tracker.handleServeLastUpdated)
	http.HandleFunc("/announce", tracker.handleAnnounce)

	go func() {
		err := http.ListenAndServe(fmt.Sprintf("%s:%d", ip, port), nil)
		LogFatal("HTTP server exited: %s", err)
	}()

	return tracker
}
<|endoftext|>


<commit_before>package yum

import (
	"fmt"
	"strings"
)

type RPM interface {
	Name() string
	Version() string
	Release() int
	Epoch() int
	Flags() string
	StandardVersion() []string

	RpmName() string
	RpmFileName() string
	//Url() string
}

type rpmBase struct {
	name    string
	version string
	release int
	epoch   int
	flags   string
}

func (rpm *rpmBase) Name() string {
	return rpm.name
}

func (rpm *rpmBase) Version() string {
	return rpm.version
}

func (rpm *rpmBase) Release() int {
	return rpm.release
}

func (rpm *rpmBase) Epoch() int {
	return rpm.epoch
}

func (rpm *rpmBase) Flags() string {
	return rpm.flags
}

func (rpm *rpmBase) StandardVersion() []string {
	return strings.Split(rpm.version, ".")
}

func (rpm *rpmBase) RpmName() string {
	return fmt.Sprintf("%s-%s-%d", rpm.name, rpm.version, rpm.release)
}

func (rpm *rpmBase) RpmFileName() string {
	return fmt.Sprintf("%s-%s-%d.rpm", rpm.name, rpm.version, rpm.release)
}

func (rpm *rpmBase) ProvideMatches(p RPM) bool {

	if p.Name() != rpm.Name() {
		return false
	}

	if rpm.Version() == "" {
		return true
	}

	switch rpm.Flags() {
	case "EQ", "eq", "==":
		return RpmEqual(rpm, p)
	case "LT", "lt", "<":
		return RpmLessThan(rpm, p)
	case "GT", "gt", ">":
		return !(RpmEqual(rpm, p) || RpmLessThan(rpm, p))
	case "LE", "le", "<=":
		return RpmEqual(rpm, p) || RpmLessThan(rpm, p)
	case "GE", "ge", ">=":
		return !RpmLessThan(rpm, p)
	default:
		panic(fmt.Errorf("invalid Flags %q (package=%v)", rpm.Flags(), rpm.Name()))
	}

	return false
}

func RpmEqual(i, j RPM) bool {
	if i.Name() != j.Name() {
		return false
	}
	if i.Version() != j.Version() {
		return false
	}

	// if i or j misses a releases number, ignore release number
	if i.Release() == 0 || j.Release() == 0 {
		return true
	}

	return i.Release() == j.Release()
}

func RpmLessThan(i, j RPM) bool {
	if i.Name() != j.Name() {
		return i.Name() < j.Name()
	}

	if i.Version() != j.Version() {
		//FIXME: more thorough ?
		return i.Version() < j.Version()
	}

	// if i or j misses a releases number, ignore release number
	if i.Release() == 0 || j.Release() == 0 {
		return i.Version() < j.Version()
	}
	return i.Release() < j.Release()
}

// Provides represents a functionality provided by a RPM package
type Provides struct {
	rpmBase
	pkg RPM // pkg is the package Provides provides for.
}

func NewProvides(name, version string, release, epoch int, flags string, pkg RPM) *Provides {
	return &Provides{
		rpmBase: rpmBase{
			name:    name,
			version: version,
			release: release,
			epoch:   epoch,
			flags:   flags,
		},
		pkg: pkg,
	}
}

// Requires represents a functionality required by a RPM package
type Requires struct {
	rpmBase
	pre string // pre is the prequisite required by a RPM package
}

func NewRequires(name, version string, release, epoch int, flags string, pre string) *Requires {
	return &Requires{
		rpmBase: rpmBase{
			name:    name,
			version: version,
			release: release,
			epoch:   epoch,
			flags:   flags,
		},
		pre: pre,
	}
}

// Package represents a RPM package in a YUM repository
type Package struct {
	rpmBase

	group      string
	arch       string
	location   string
	requires   []RPM
	provides   []RPM
	repository *Repository
}

// NewPackage creates a new RPM package
func NewPackage(name, version string, release, epoch int) *Package {
	pkg := Package{
		rpmBase: rpmBase{
			name:    name,
			version: version,
			release: release,
			epoch:   epoch,
		},
		requires: make([]RPM, 0),
		provides: make([]RPM, 0),
	}

	return &pkg
}

func (pkg *Package) String() string {
	str := []string{
		fmt.Sprintf(
			"Package: %s-%s-%s\t%s",
			pkg.Name(),
			pkg.Version(),
			pkg.Release(),
			pkg.Group(),
		),
	}

	if len(pkg.provides) > 0 {
		str = append(str, "Provides:")
		for _, p := range pkg.provides {
			str = append(str, fmt.Sprintf("\t%s-%s-%s", p.Name(), p.Version(), p.Release()))
		}
	}

	if len(pkg.requires) > 0 {
		str = append(str, "Requires:")
		for _, p := range pkg.requires {
			str = append(str, fmt.Sprintf("\t%s-%s-%s\t%s", p.Name(), p.Version(), p.Release(), p.Flags()))
		}
	}

	return strings.Join(str, "\n")
}

func (pkg *Package) Group() string {
	return pkg.group
}

func (pkg *Package) Arch() string {
	return pkg.arch
}

func (pkg *Package) Location() string {
	return pkg.location
}

func (pkg *Package) Requires() []RPM {
	return pkg.requires
}

func (pkg *Package) Provides() []RPM {
	return pkg.provides
}

func (pkg *Package) Repository() *Repository {
	return pkg.repository
}

func (pkg *Package) Url() string {
	return pkg.repository.RepoUrl + "/" + pkg.location
}

type Packages []*Package
func (p Packages) Len() int {
	return len(p)
}

func (p Packages) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func (p Packages) Less(i,j int) bool {
	pi := p[i]
	pj := p[j]

	return RpmLessThan(pi, pj)
}

type RPMSlice []RPM
func (p RPMSlice) Len() int {
	return len(p)
}

func (p RPMSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func (p RPMSlice) Less(i,j int) bool {
	pi := p[i]
	pj := p[j]

	return RpmLessThan(pi, pj)
}
<commit_msg>yum.rmp: Provides holds a concrete *Package (instead of RPM)<commit_after>package yum

import (
	"fmt"
	"strings"
)

type RPM interface {
	Name() string
	Version() string
	Release() int
	Epoch() int
	Flags() string
	StandardVersion() []string

	RpmName() string
	RpmFileName() string
	//Url() string
}

type rpmBase struct {
	name    string
	version string
	release int
	epoch   int
	flags   string
}

func (rpm *rpmBase) Name() string {
	return rpm.name
}

func (rpm *rpmBase) Version() string {
	return rpm.version
}

func (rpm *rpmBase) Release() int {
	return rpm.release
}

func (rpm *rpmBase) Epoch() int {
	return rpm.epoch
}

func (rpm *rpmBase) Flags() string {
	return rpm.flags
}

func (rpm *rpmBase) StandardVersion() []string {
	return strings.Split(rpm.version, ".")
}

func (rpm *rpmBase) RpmName() string {
	return fmt.Sprintf("%s-%s-%d", rpm.name, rpm.version, rpm.release)
}

func (rpm *rpmBase) RpmFileName() string {
	return fmt.Sprintf("%s-%s-%d.rpm", rpm.name, rpm.version, rpm.release)
}

func (rpm *rpmBase) ProvideMatches(p RPM) bool {

	if p.Name() != rpm.Name() {
		return false
	}

	if rpm.Version() == "" {
		return true
	}

	switch rpm.Flags() {
	case "EQ", "eq", "==":
		return RpmEqual(rpm, p)
	case "LT", "lt", "<":
		return RpmLessThan(rpm, p)
	case "GT", "gt", ">":
		return !(RpmEqual(rpm, p) || RpmLessThan(rpm, p))
	case "LE", "le", "<=":
		return RpmEqual(rpm, p) || RpmLessThan(rpm, p)
	case "GE", "ge", ">=":
		return !RpmLessThan(rpm, p)
	default:
		panic(fmt.Errorf("invalid Flags %q (package=%v)", rpm.Flags(), rpm.Name()))
	}

	return false
}

func RpmEqual(i, j RPM) bool {
	if i.Name() != j.Name() {
		return false
	}
	if i.Version() != j.Version() {
		return false
	}

	// if i or j misses a releases number, ignore release number
	if i.Release() == 0 || j.Release() == 0 {
		return true
	}

	return i.Release() == j.Release()
}

func RpmLessThan(i, j RPM) bool {
	if i.Name() != j.Name() {
		return i.Name() < j.Name()
	}

	if i.Version() != j.Version() {
		//FIXME: more thorough ?
		return i.Version() < j.Version()
	}

	// if i or j misses a releases number, ignore release number
	if i.Release() == 0 || j.Release() == 0 {
		return i.Version() < j.Version()
	}
	return i.Release() < j.Release()
}

// Provides represents a functionality provided by a RPM package
type Provides struct {
	rpmBase
	Package *Package // pkg is the package Provides provides for.
}

func NewProvides(name, version string, release, epoch int, flags string, pkg *Package) *Provides {
	return &Provides{
		rpmBase: rpmBase{
			name:    name,
			version: version,
			release: release,
			epoch:   epoch,
			flags:   flags,
		},
		Package: pkg,
	}
}

// Requires represents a functionality required by a RPM package
type Requires struct {
	rpmBase
	pre string // pre is the prequisite required by a RPM package
}

func NewRequires(name, version string, release, epoch int, flags string, pre string) *Requires {
	return &Requires{
		rpmBase: rpmBase{
			name:    name,
			version: version,
			release: release,
			epoch:   epoch,
			flags:   flags,
		},
		pre: pre,
	}
}

// Package represents a RPM package in a YUM repository
type Package struct {
	rpmBase

	group      string
	arch       string
	location   string
	requires   []RPM
	provides   []RPM
	repository *Repository
}

// NewPackage creates a new RPM package
func NewPackage(name, version string, release, epoch int) *Package {
	pkg := Package{
		rpmBase: rpmBase{
			name:    name,
			version: version,
			release: release,
			epoch:   epoch,
		},
		requires: make([]RPM, 0),
		provides: make([]RPM, 0),
	}

	return &pkg
}

func (pkg *Package) String() string {
	str := []string{
		fmt.Sprintf(
			"Package: %s-%s-%s\t%s",
			pkg.Name(),
			pkg.Version(),
			pkg.Release(),
			pkg.Group(),
		),
	}

	if len(pkg.provides) > 0 {
		str = append(str, "Provides:")
		for _, p := range pkg.provides {
			str = append(str, fmt.Sprintf("\t%s-%s-%s", p.Name(), p.Version(), p.Release()))
		}
	}

	if len(pkg.requires) > 0 {
		str = append(str, "Requires:")
		for _, p := range pkg.requires {
			str = append(str, fmt.Sprintf("\t%s-%s-%s\t%s", p.Name(), p.Version(), p.Release(), p.Flags()))
		}
	}

	return strings.Join(str, "\n")
}

func (pkg *Package) Group() string {
	return pkg.group
}

func (pkg *Package) Arch() string {
	return pkg.arch
}

func (pkg *Package) Location() string {
	return pkg.location
}

func (pkg *Package) Requires() []RPM {
	return pkg.requires
}

func (pkg *Package) Provides() []RPM {
	return pkg.provides
}

func (pkg *Package) Repository() *Repository {
	return pkg.repository
}

func (pkg *Package) Url() string {
	return pkg.repository.RepoUrl + "/" + pkg.location
}

type Packages []*Package
func (p Packages) Len() int {
	return len(p)
}

func (p Packages) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func (p Packages) Less(i,j int) bool {
	pi := p[i]
	pj := p[j]

	return RpmLessThan(pi, pj)
}

type RPMSlice []RPM
func (p RPMSlice) Len() int {
	return len(p)
}

func (p RPMSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func (p RPMSlice) Less(i,j int) bool {
	pi := p[i]
	pj := p[j]

	return RpmLessThan(pi, pj)
}
<|endoftext|>


<commit_before>package model

import (
	"fmt"
	"github.com/imdario/mergo"
	"gopkg.in/go-playground/pool.v3"
	"io/ioutil"
	"path"
	"path/filepath"
	"strings"
)

type ProjectConfig struct {
	UserToken `yaml:",inline"`
	Project   `yaml:",inline"`
	AuthToken `yaml:",inline"`
	Resources []ProjectResource `yaml:"Files,omitempty"`
	Locales   map[string]string `yaml:"Locales,omitempty"`
}

func (c *ProjectConfig) Merge(delta *ProjectConfig) error {
	return mergo.MapWithOverwrite(c, delta)
}

func (c *ProjectConfig) LocaleFor(localeID string) string {
	locale := c.Locales[localeID]

	if locale != "" {
		return c.Locales[localeID]
	}

	return localeID
}

func (c *ProjectConfig) FileURI(filename string) string {
	if c.Alias != "" {
		return path.Join(c.Alias, filename)
	}

	return filename
}

func (c *ProjectConfig) FilePath(filename string) string {
	return strings.Trim(strings.TrimPrefix(filename, c.Alias), fmt.Sprintf("%c", filepath.Separator))
}

func (c *ProjectConfig) SaveFile(file *File, resource *ProjectResource) error {
	var (
		err      error
		filename string
	)

	locale := c.LocaleFor(file.LocaleID)

	if filename, err = resource.PathFor(c.FilePath(file.Path), locale); err == nil {
		if filename, err = filepath.Abs(filename); err == nil {
			err = ioutil.WriteFile(filename, file.Content, 0644)
		}
	}

	return err
}

func (c *ProjectConfig) SaveAllFiles(files []*File, resource *ProjectResource) {
	p := pool.New()

	defer p.Close()

	batch := p.Batch()

	go func() {
		for _, file := range files {
			batch.Queue(c.saveFileJob(file, resource))
		}

		batch.QueueComplete()
	}()
}

func (c *ProjectConfig) saveFileJob(file *File, resource *ProjectResource) pool.WorkFunc {
	return func(wu pool.WorkUnit) (interface{}, error) {
		if wu.IsCancelled() {
			return nil, nil
		}

		return nil, c.SaveFile(file, resource)
	}
}
<commit_msg>fix(ProjectConfig): now `Save Files` waits for when all jobs would be completed<commit_after>package model

import (
	"fmt"
	"github.com/imdario/mergo"
	"gopkg.in/go-playground/pool.v3"
	"io/ioutil"
	"path"
	"path/filepath"
	"strings"
)

type ProjectConfig struct {
	UserToken `yaml:",inline"`
	Project   `yaml:",inline"`
	AuthToken `yaml:",inline"`
	Resources []ProjectResource `yaml:"Files,omitempty"`
	Locales   map[string]string `yaml:"Locales,omitempty"`
}

func (c *ProjectConfig) Merge(delta *ProjectConfig) error {
	return mergo.MapWithOverwrite(c, delta)
}

func (c *ProjectConfig) LocaleFor(localeID string) string {
	locale := c.Locales[localeID]

	if locale != "" {
		return c.Locales[localeID]
	}

	return localeID
}

func (c *ProjectConfig) FileURI(filename string) string {
	if c.Alias != "" {
		return path.Join(c.Alias, filename)
	}

	return filename
}

func (c *ProjectConfig) FilePath(filename string) string {
	return strings.Trim(strings.TrimPrefix(filename, c.Alias), fmt.Sprintf("%c", filepath.Separator))
}

func (c *ProjectConfig) SaveFile(file *File, resource *ProjectResource) error {
	var (
		err      error
		filename string
	)

	locale := c.LocaleFor(file.LocaleID)

	if filename, err = resource.PathFor(c.FilePath(file.Path), locale); err == nil {
		if filename, err = filepath.Abs(filename); err == nil {
			err = ioutil.WriteFile(filename, file.Content, 0644)
		}
	}

	return err
}

func (c *ProjectConfig) SaveAllFiles(files []*File, resource *ProjectResource) {
	p := pool.New()

	defer p.Close()

	batch := p.Batch()

	go func() {
		for _, file := range files {
			batch.Queue(c.saveFileJob(file, resource))
		}

		batch.QueueComplete()
	}()

	batch.WaitAll()
}

func (c *ProjectConfig) saveFileJob(file *File, resource *ProjectResource) pool.WorkFunc {
	return func(wu pool.WorkUnit) (interface{}, error) {
		if wu.IsCancelled() {
			return nil, nil
		}

		return nil, c.SaveFile(file, resource)
	}
}
<|endoftext|>


<commit_before>package models

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
	"time"

	"github.com/gorilla/mux"
)

func TestPurchasesByArgument(t *testing.T) {
	// Imitating a third party API. Unlike the real one this always
	// returns the same JSON response.
	r := mux.NewRouter()
	a := r.Path("/api/").Subrouter()
	a.HandleFunc("/purchases/by_user/test", http.NotFoundHandler().ServeHTTP)
	a.HandleFunc("/purchases/by_user/empty", emptyH)
	a.HandleFunc("/purchases/by_user/{id}", testPurchasesByArgH)
	a.HandleFunc("/purchases/by_product/{id}", testPurchasesByArgH)

	// Creating a test server with the API.
	s := httptest.NewServer(a)
	defer s.Close()

	// Setting the API's URI.
	Init(s.URL + "/api/")

	// Check the case when the API's response is a valid JSON.
	for i, fn := range []func(string, uint) ([]Purchase, error){
		PurchasesByUsername,
		PurchasesByProductID,
	} {
		ps, err := fn("xxx", 0)
		if err != nil || !reflect.DeepEqual(ps, testPurchases) {
			t.Errorf(`Test %d: Expected %#v, "nil". Got %#v, "%v".`, i, testPurchases, ps, err)
		}
	}

	// Check all possible errors, including:
	// 1. incorrect response status.
	// 2. invalid JSON.
	for i, arg := range []string{"test", "empty"} {
		ps, err := PurchasesByUsername(arg, 0)
		if ps != nil || err == nil {
			t.Errorf(`Test %d: Expected no result and an error. Got %v, "%v".`, i, ps, err)
		}
	}
}

// testPurchasesByArgH is a handler that imitates the third
// party API that provides purchases by username / id.
var testPurchasesByArgH = func(w http.ResponseWriter, r *http.Request) {
	// Transform the test list of purchases into JSON.
	res, err := json.Marshal(testPurchases)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// Render the result.
	w.Header().Add("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(res)
}

// emptyH is a handler that renders an empty page.
var emptyH = func(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
}

var testPurchases = []Purchase{
	{123, 321, "JohnDoe", time.Now().Local().Round(time.Minute)},
	{222, 444, "Mr.X", time.Now().Local().Round(time.Minute)},
}
<commit_msg>Replace reflect.DeepEqual by a custom function<commit_after>package models

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/gorilla/mux"
)

func TestPurchasesByArgument(t *testing.T) {
	// Imitating a third party API. Unlike the real one this always
	// returns the same JSON response.
	r := mux.NewRouter()
	a := r.Path("/api/").Subrouter()
	a.HandleFunc("/purchases/by_user/test", http.NotFoundHandler().ServeHTTP)
	a.HandleFunc("/purchases/by_user/empty", emptyH)
	a.HandleFunc("/purchases/by_user/{id}", testPurchasesByArgH)
	a.HandleFunc("/purchases/by_product/{id}", testPurchasesByArgH)

	// Creating a test server with the API.
	s := httptest.NewServer(a)
	defer s.Close()

	// Setting the API's URI.
	Init(s.URL + "/api/")

	// Check the case when the API's response is a valid JSON.
	for i, fn := range []func(string, uint) ([]Purchase, error){
		PurchasesByUsername,
		PurchasesByProductID,
	} {
		ps, err := fn("xxx", 0)
		if err != nil || !deepEqualPurchases(testPurchases, ps) {
			t.Errorf(`Test %d: Expected %#v, "nil". Got %#v, "%v".`, i, testPurchases, ps, err)
		}
	}

	// Check all possible errors, including:
	// 1. incorrect response status.
	// 2. invalid JSON.
	for i, arg := range []string{"test", "empty"} {
		ps, err := PurchasesByUsername(arg, 0)
		if ps != nil || err == nil {
			t.Errorf(`Test %d: Expected no result and an error. Got %v, "%v".`, i, ps, err)
		}
	}
}

// deepEqualPurchases compares two sets of purchases and makes sure they are equal
// to each other. reflect.Deep is not an option as Location field
// of Date parameter is a pointer that will be different in the original
// and marshalled objects.
func deepEqualPurchases(ps1, ps2 []Purchase) bool {
	if len(ps1) != len(ps2) {
		return false
	}
	for i := 0; i < len(ps1); i++ {
		if ps1[i].ID != ps2[i].ID || ps1[i].ProductID != ps2[i].ProductID ||
			ps1[i].Username != ps2[i].Username || ps1[i].Date.String() != ps2[i].Date.String() {

			return false
		}
	}
	return true
}

// testPurchasesByArgH is a handler that imitates the third
// party API that provides purchases by username / id.
var testPurchasesByArgH = func(w http.ResponseWriter, r *http.Request) {
	// Transform the test list of purchases into JSON.
	res, err := json.Marshal(testPurchases)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// Render the result.
	w.Header().Add("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(res)
}

// emptyH is a handler that renders an empty page.
var emptyH = func(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
}

var testPurchases = []Purchase{
	{123, 321, "JohnDoe", time.Now().Local().Round(time.Minute)},
	{222, 444, "Mr.X", time.Now().Local().Round(time.Minute)},
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// 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 linux

// Errno represents a Linux errno value.
type Errno struct {
	number int
	name   string
}

// Number returns the errno number.
func (e *Errno) Number() int {
	return e.number
}

// Error implements error.Error.
func (e *Errno) Error() string {
	return e.name
}

// Errno values from include/uapi/asm-generic/errno-base.h.
var (
	EPERM   = &Errno{1, "operation not permitted"}
	ENOENT  = &Errno{2, "no such file or directory"}
	ESRCH   = &Errno{3, "no such process"}
	EINTR   = &Errno{4, "interrupted system call"}
	EIO     = &Errno{5, "I/O error"}
	ENXIO   = &Errno{6, "no such device or address"}
	E2BIG   = &Errno{7, "argument list too long"}
	ENOEXEC = &Errno{8, "exec format error"}
	EBADF   = &Errno{9, "bad file number"}
	ECHILD  = &Errno{10, "no child processes"}
	EAGAIN  = &Errno{11, "try again"}
	ENOMEM  = &Errno{12, "out of memory"}
	EACCES  = &Errno{13, "permission denied"}
	EFAULT  = &Errno{14, "bad address"}
	ENOTBLK = &Errno{15, "block device required"}
	EBUSY   = &Errno{16, "device or resource busy"}
	EEXIST  = &Errno{17, "file exists"}
	EXDEV   = &Errno{18, "cross-device link"}
	ENODEV  = &Errno{19, "no such device"}
	ENOTDIR = &Errno{20, "not a directory"}
	EISDIR  = &Errno{21, "is a directory"}
	EINVAL  = &Errno{22, "invalid argument"}
	ENFILE  = &Errno{23, "file table overflow"}
	EMFILE  = &Errno{24, "too many open files"}
	ENOTTY  = &Errno{25, "not a typewriter"}
	ETXTBSY = &Errno{26, "text file busy"}
	EFBIG   = &Errno{27, "file too large"}
	ENOSPC  = &Errno{28, "no space left on device"}
	ESPIPE  = &Errno{29, "illegal seek"}
	EROFS   = &Errno{30, "read-only file system"}
	EMLINK  = &Errno{31, "too many links"}
	EPIPE   = &Errno{32, "broken pipe"}
	EDOM    = &Errno{33, "math argument out of domain of func"}
	ERANGE  = &Errno{34, "math result not representable"}
)

// Errno values from include/uapi/asm-generic/errno.h.
var (
	EDEADLK         = &Errno{35, "resource deadlock would occur"}
	ENAMETOOLONG    = &Errno{36, "file name too long"}
	ENOLCK          = &Errno{37, "no record locks available"}
	ENOSYS          = &Errno{38, "invalid system call number"}
	ENOTEMPTY       = &Errno{39, "directory not empty"}
	ELOOP           = &Errno{40, "too many symbolic links encountered"}
	EWOULDBLOCK     = &Errno{EAGAIN.number, "operation would block"}
	ENOMSG          = &Errno{42, "no message of desired type"}
	EIDRM           = &Errno{43, "identifier removed"}
	ECHRNG          = &Errno{44, "channel number out of range"}
	EL2NSYNC        = &Errno{45, "level 2 not synchronized"}
	EL3HLT          = &Errno{46, "level 3 halted"}
	EL3RST          = &Errno{47, "level 3 reset"}
	ELNRNG          = &Errno{48, "link number out of range"}
	EUNATCH         = &Errno{49, "protocol driver not attached"}
	ENOCSI          = &Errno{50, "no CSI structure available"}
	EL2HLT          = &Errno{51, "level 2 halted"}
	EBADE           = &Errno{52, "invalid exchange"}
	EBADR           = &Errno{53, "invalid request descriptor"}
	EXFULL          = &Errno{54, "exchange full"}
	ENOANO          = &Errno{55, "no anode"}
	EBADRQC         = &Errno{56, "invalid request code"}
	EBADSLT         = &Errno{57, "invalid slot"}
	EDEADLOCK       = EDEADLK
	EBFONT          = &Errno{59, "bad font file format"}
	ENOSTR          = &Errno{60, "device not a stream"}
	ENODATA         = &Errno{61, "no data available"}
	ETIME           = &Errno{62, "timer expired"}
	ENOSR           = &Errno{63, "out of streams resources"}
	ENONET          = &Errno{64, "machine is not on the network"}
	ENOPKG          = &Errno{65, "package not installed"}
	EREMOTE         = &Errno{66, "object is remote"}
	ENOLINK         = &Errno{67, "link has been severed"}
	EADV            = &Errno{68, "advertise error"}
	ESRMNT          = &Errno{69, "srmount error"}
	ECOMM           = &Errno{70, "communication error on send"}
	EPROTO          = &Errno{71, "protocol error"}
	EMULTIHOP       = &Errno{72, "multihop attempted"}
	EDOTDOT         = &Errno{73, "RFS specific error"}
	EBADMSG         = &Errno{74, "not a data message"}
	EOVERFLOW       = &Errno{75, "value too large for defined data type"}
	ENOTUNIQ        = &Errno{76, "name not unique on network"}
	EBADFD          = &Errno{77, "file descriptor in bad state"}
	EREMCHG         = &Errno{78, "remote address changed"}
	ELIBACC         = &Errno{79, "can not access a needed shared library"}
	ELIBBAD         = &Errno{80, "accessing a corrupted shared library"}
	ELIBSCN         = &Errno{81, ".lib section in a.out corrupted"}
	ELIBMAX         = &Errno{82, "attempting to link in too many shared libraries"}
	ELIBEXEC        = &Errno{83, "cannot exec a shared library directly"}
	EILSEQ          = &Errno{84, "illegal byte sequence"}
	ERESTART        = &Errno{85, "interrupted system call should be restarted"}
	ESTRPIPE        = &Errno{86, "streams pipe error"}
	EUSERS          = &Errno{87, "too many users"}
	ENOTSOCK        = &Errno{88, "socket operation on non-socket"}
	EDESTADDRREQ    = &Errno{89, "destination address required"}
	EMSGSIZE        = &Errno{90, "message too long"}
	EPROTOTYPE      = &Errno{91, "protocol wrong type for socket"}
	ENOPROTOOPT     = &Errno{92, "protocol not available"}
	EPROTONOSUPPORT = &Errno{93, "protocol not supported"}
	ESOCKTNOSUPPORT = &Errno{94, "socket type not supported"}
	EOPNOTSUPP      = &Errno{95, "operation not supported on transport endpoint"}
	EPFNOSUPPORT    = &Errno{96, "protocol family not supported"}
	EAFNOSUPPORT    = &Errno{97, "address family not supported by protocol"}
	EADDRINUSE      = &Errno{98, "address already in use"}
	EADDRNOTAVAIL   = &Errno{99, "cannot assign requested address"}
	ENETDOWN        = &Errno{100, "network is down"}
	ENETUNREACH     = &Errno{101, "network is unreachable"}
	ENETRESET       = &Errno{102, "network dropped connection because of reset"}
	ECONNABORTED    = &Errno{103, "software caused connection abort"}
	ECONNRESET      = &Errno{104, "connection reset by peer"}
	ENOBUFS         = &Errno{105, "no buffer space available"}
	EISCONN         = &Errno{106, "transport endpoint is already connected"}
	ENOTCONN        = &Errno{107, "transport endpoint is not connected"}
	ESHUTDOWN       = &Errno{108, "cannot send after transport endpoint shutdown"}
	ETOOMANYREFS    = &Errno{109, "too many references: cannot splice"}
	ETIMEDOUT       = &Errno{110, "connection timed out"}
	ECONNREFUSED    = &Errno{111, "connection refused"}
	EHOSTDOWN       = &Errno{112, "host is down"}
	EHOSTUNREACH    = &Errno{113, "no route to host"}
	EALREADY        = &Errno{114, "operation already in progress"}
	EINPROGRESS     = &Errno{115, "operation now in progress"}
	ESTALE          = &Errno{116, "stale file handle"}
	EUCLEAN         = &Errno{117, "structure needs cleaning"}
	ENOTNAM         = &Errno{118, "not a XENIX named type file"}
	ENAVAIL         = &Errno{119, "no XENIX semaphores available"}
	EISNAM          = &Errno{120, "is a named type file"}
	EREMOTEIO       = &Errno{121, "remote I/O error"}
	EDQUOT          = &Errno{122, "quota exceeded"}
	ENOMEDIUM       = &Errno{123, "no medium found"}
	EMEDIUMTYPE     = &Errno{124, "wrong medium type"}
	ECANCELED       = &Errno{125, "operation Canceled"}
	ENOKEY          = &Errno{126, "required key not available"}
	EKEYEXPIRED     = &Errno{127, "key has expired"}
	EKEYREVOKED     = &Errno{128, "key has been revoked"}
	EKEYREJECTED    = &Errno{129, "key was rejected by service"}
	EOWNERDEAD      = &Errno{130, "owner died"}
	ENOTRECOVERABLE = &Errno{131, "state not recoverable"}
	ERFKILL         = &Errno{132, "operation not possible due to RF-kill"}
	EHWPOISON       = &Errno{133, "memory page has hardware error"}
)
<commit_msg>Rename linux.Errno.Error to linux.Errno.String.<commit_after>// Copyright 2018 Google LLC
//
// 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 linux

// Errno represents a Linux errno value.
type Errno struct {
	number int
	name   string
}

// Number returns the errno number.
func (e *Errno) Number() int {
	return e.number
}

// String implements fmt.Stringer.String.
func (e *Errno) String() string {
	return e.name
}

// Errno values from include/uapi/asm-generic/errno-base.h.
var (
	EPERM   = &Errno{1, "operation not permitted"}
	ENOENT  = &Errno{2, "no such file or directory"}
	ESRCH   = &Errno{3, "no such process"}
	EINTR   = &Errno{4, "interrupted system call"}
	EIO     = &Errno{5, "I/O error"}
	ENXIO   = &Errno{6, "no such device or address"}
	E2BIG   = &Errno{7, "argument list too long"}
	ENOEXEC = &Errno{8, "exec format error"}
	EBADF   = &Errno{9, "bad file number"}
	ECHILD  = &Errno{10, "no child processes"}
	EAGAIN  = &Errno{11, "try again"}
	ENOMEM  = &Errno{12, "out of memory"}
	EACCES  = &Errno{13, "permission denied"}
	EFAULT  = &Errno{14, "bad address"}
	ENOTBLK = &Errno{15, "block device required"}
	EBUSY   = &Errno{16, "device or resource busy"}
	EEXIST  = &Errno{17, "file exists"}
	EXDEV   = &Errno{18, "cross-device link"}
	ENODEV  = &Errno{19, "no such device"}
	ENOTDIR = &Errno{20, "not a directory"}
	EISDIR  = &Errno{21, "is a directory"}
	EINVAL  = &Errno{22, "invalid argument"}
	ENFILE  = &Errno{23, "file table overflow"}
	EMFILE  = &Errno{24, "too many open files"}
	ENOTTY  = &Errno{25, "not a typewriter"}
	ETXTBSY = &Errno{26, "text file busy"}
	EFBIG   = &Errno{27, "file too large"}
	ENOSPC  = &Errno{28, "no space left on device"}
	ESPIPE  = &Errno{29, "illegal seek"}
	EROFS   = &Errno{30, "read-only file system"}
	EMLINK  = &Errno{31, "too many links"}
	EPIPE   = &Errno{32, "broken pipe"}
	EDOM    = &Errno{33, "math argument out of domain of func"}
	ERANGE  = &Errno{34, "math result not representable"}
)

// Errno values from include/uapi/asm-generic/errno.h.
var (
	EDEADLK         = &Errno{35, "resource deadlock would occur"}
	ENAMETOOLONG    = &Errno{36, "file name too long"}
	ENOLCK          = &Errno{37, "no record locks available"}
	ENOSYS          = &Errno{38, "invalid system call number"}
	ENOTEMPTY       = &Errno{39, "directory not empty"}
	ELOOP           = &Errno{40, "too many symbolic links encountered"}
	EWOULDBLOCK     = &Errno{EAGAIN.number, "operation would block"}
	ENOMSG          = &Errno{42, "no message of desired type"}
	EIDRM           = &Errno{43, "identifier removed"}
	ECHRNG          = &Errno{44, "channel number out of range"}
	EL2NSYNC        = &Errno{45, "level 2 not synchronized"}
	EL3HLT          = &Errno{46, "level 3 halted"}
	EL3RST          = &Errno{47, "level 3 reset"}
	ELNRNG          = &Errno{48, "link number out of range"}
	EUNATCH         = &Errno{49, "protocol driver not attached"}
	ENOCSI          = &Errno{50, "no CSI structure available"}
	EL2HLT          = &Errno{51, "level 2 halted"}
	EBADE           = &Errno{52, "invalid exchange"}
	EBADR           = &Errno{53, "invalid request descriptor"}
	EXFULL          = &Errno{54, "exchange full"}
	ENOANO          = &Errno{55, "no anode"}
	EBADRQC         = &Errno{56, "invalid request code"}
	EBADSLT         = &Errno{57, "invalid slot"}
	EDEADLOCK       = EDEADLK
	EBFONT          = &Errno{59, "bad font file format"}
	ENOSTR          = &Errno{60, "device not a stream"}
	ENODATA         = &Errno{61, "no data available"}
	ETIME           = &Errno{62, "timer expired"}
	ENOSR           = &Errno{63, "out of streams resources"}
	ENONET          = &Errno{64, "machine is not on the network"}
	ENOPKG          = &Errno{65, "package not installed"}
	EREMOTE         = &Errno{66, "object is remote"}
	ENOLINK         = &Errno{67, "link has been severed"}
	EADV            = &Errno{68, "advertise error"}
	ESRMNT          = &Errno{69, "srmount error"}
	ECOMM           = &Errno{70, "communication error on send"}
	EPROTO          = &Errno{71, "protocol error"}
	EMULTIHOP       = &Errno{72, "multihop attempted"}
	EDOTDOT         = &Errno{73, "RFS specific error"}
	EBADMSG         = &Errno{74, "not a data message"}
	EOVERFLOW       = &Errno{75, "value too large for defined data type"}
	ENOTUNIQ        = &Errno{76, "name not unique on network"}
	EBADFD          = &Errno{77, "file descriptor in bad state"}
	EREMCHG         = &Errno{78, "remote address changed"}
	ELIBACC         = &Errno{79, "can not access a needed shared library"}
	ELIBBAD         = &Errno{80, "accessing a corrupted shared library"}
	ELIBSCN         = &Errno{81, ".lib section in a.out corrupted"}
	ELIBMAX         = &Errno{82, "attempting to link in too many shared libraries"}
	ELIBEXEC        = &Errno{83, "cannot exec a shared library directly"}
	EILSEQ          = &Errno{84, "illegal byte sequence"}
	ERESTART        = &Errno{85, "interrupted system call should be restarted"}
	ESTRPIPE        = &Errno{86, "streams pipe error"}
	EUSERS          = &Errno{87, "too many users"}
	ENOTSOCK        = &Errno{88, "socket operation on non-socket"}
	EDESTADDRREQ    = &Errno{89, "destination address required"}
	EMSGSIZE        = &Errno{90, "message too long"}
	EPROTOTYPE      = &Errno{91, "protocol wrong type for socket"}
	ENOPROTOOPT     = &Errno{92, "protocol not available"}
	EPROTONOSUPPORT = &Errno{93, "protocol not supported"}
	ESOCKTNOSUPPORT = &Errno{94, "socket type not supported"}
	EOPNOTSUPP      = &Errno{95, "operation not supported on transport endpoint"}
	EPFNOSUPPORT    = &Errno{96, "protocol family not supported"}
	EAFNOSUPPORT    = &Errno{97, "address family not supported by protocol"}
	EADDRINUSE      = &Errno{98, "address already in use"}
	EADDRNOTAVAIL   = &Errno{99, "cannot assign requested address"}
	ENETDOWN        = &Errno{100, "network is down"}
	ENETUNREACH     = &Errno{101, "network is unreachable"}
	ENETRESET       = &Errno{102, "network dropped connection because of reset"}
	ECONNABORTED    = &Errno{103, "software caused connection abort"}
	ECONNRESET      = &Errno{104, "connection reset by peer"}
	ENOBUFS         = &Errno{105, "no buffer space available"}
	EISCONN         = &Errno{106, "transport endpoint is already connected"}
	ENOTCONN        = &Errno{107, "transport endpoint is not connected"}
	ESHUTDOWN       = &Errno{108, "cannot send after transport endpoint shutdown"}
	ETOOMANYREFS    = &Errno{109, "too many references: cannot splice"}
	ETIMEDOUT       = &Errno{110, "connection timed out"}
	ECONNREFUSED    = &Errno{111, "connection refused"}
	EHOSTDOWN       = &Errno{112, "host is down"}
	EHOSTUNREACH    = &Errno{113, "no route to host"}
	EALREADY        = &Errno{114, "operation already in progress"}
	EINPROGRESS     = &Errno{115, "operation now in progress"}
	ESTALE          = &Errno{116, "stale file handle"}
	EUCLEAN         = &Errno{117, "structure needs cleaning"}
	ENOTNAM         = &Errno{118, "not a XENIX named type file"}
	ENAVAIL         = &Errno{119, "no XENIX semaphores available"}
	EISNAM          = &Errno{120, "is a named type file"}
	EREMOTEIO       = &Errno{121, "remote I/O error"}
	EDQUOT          = &Errno{122, "quota exceeded"}
	ENOMEDIUM       = &Errno{123, "no medium found"}
	EMEDIUMTYPE     = &Errno{124, "wrong medium type"}
	ECANCELED       = &Errno{125, "operation Canceled"}
	ENOKEY          = &Errno{126, "required key not available"}
	EKEYEXPIRED     = &Errno{127, "key has expired"}
	EKEYREVOKED     = &Errno{128, "key has been revoked"}
	EKEYREJECTED    = &Errno{129, "key was rejected by service"}
	EOWNERDEAD      = &Errno{130, "owner died"}
	ENOTRECOVERABLE = &Errno{131, "state not recoverable"}
	ERFKILL         = &Errno{132, "operation not possible due to RF-kill"}
	EHWPOISON       = &Errno{133, "memory page has hardware error"}
)
<|endoftext|>