<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 main

import (
	"flag"
	"fmt"
	"github.com/jacobsa/aws/s3"
	"github.com/jacobsa/aws/sdb"
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/crypto"
	"github.com/jacobsa/comeback/config"
	"github.com/jacobsa/comeback/fs"
	s3_kv "github.com/jacobsa/comeback/kv/s3"
	"github.com/jacobsa/comeback/sys"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"time"
)

var g_configFile = flag.String("config", "", "Path to config file.")
var g_jobName = flag.String("job", "", "Job name within the config file.")

func main() {
	var err error
	flag.Parse()

	// Attempt to read the user's config data.
	if *g_configFile == "" {
		fmt.Println("You must set -config.")
		os.Exit(1)
	}

	configData, err := ioutil.ReadFile(*g_configFile)
	if err != nil {
		fmt.Println("Error reading config file:", err)
		os.Exit(1)
	}

	// Parse the config file.
	cfg, err := config.Parse(configData)
	if err != nil {
		fmt.Println("Parsing config file:", err)
		os.Exit(1)
	}

	// Validate the config file.
	if err := config.Validate(cfg); err != nil {
		fmt.Printf("Config file invalid: %v", err)
		os.Exit(1)
	}

	// Look for the specified job.
	if *g_jobName == "" {
		fmt.Println("You must set -job.")
		os.Exit(1)
	}

	job, ok := cfg.Jobs[*g_jobName]
	if !ok {
		fmt.Println("Unknown job:", *g_jobName)
		os.Exit(1)
	}

	// Create a user registry.
	userRegistry, err := sys.NewUserRegistry()
	if err != nil {
		log.Fatalf("Creating user registry: %v", err)
	}

	// Create a group registry.
	groupRegistry, err := sys.NewGroupRegistry()
	if err != nil {
		log.Fatalf("Creating group registry: %v", err)
	}

	// Create a file system.
	fileSystem, err := fs.NewFileSystem(userRegistry, groupRegistry)
	if err != nil {
		log.Fatalf("Creating file system: %v", err)
	}

	// Open a connection to SimpleDB.
	db, err := sdb.NewSimpleDB(cfg.SdbRegion, cfg.AccessKey)
	if err != nil {
		log.Fatalf("Creating SimpleDB: %v", err)
	}

	// Open a connection to S3.
	bucket, err := s3.OpenBucket(cfg.S3Bucket, cfg.S3Region, cfg.AccessKey)
	if err != nil {
		log.Fatalf("Creating bucket: %v", err)
	}

	// Create the crypter.
	crypter, err := crypto.NewCrypter(cryptoKey)
	if err != nil {
		log.Fatalf("Creating crypter: %v", err)
	}

	// Create the backup registry.
	randSrc := rand.New(rand.NewSource(time.Now().UnixNano()))
	registry, err := backup.NewRegistry(db, cfg.SdbDomain, crypter, randSrc)
	if err != nil {
		log.Fatalf("Creating registry: %v", err)
	}

	// Create the kv store.
	kvStore, err := s3_kv.NewS3KvStore(bucket)
	if err != nil {
		log.Fatalf("Creating kv store: %v", err)
	}

	// Create the blob store.
	blobStore := blob.NewKvBasedBlobStore(kvStore)
	blobStore = blob.NewCheckingStore(blobStore)
	blobStore = blob.NewEncryptingStore(crypter, blobStore)

	// Create the file saver.
	fileSaver, err := backup.NewFileSaver(blobStore, 1<<24)
	if err != nil {
		log.Fatalf("Creating file saver: %v", err)
	}

	// Create a directory saver.
	dirSaver, err := backup.NewDirectorySaver(
		blobStore,
		fileSystem,
		fileSaver)

	if err != nil {
		log.Fatalf("Creating directory saver: %v", err)
	}

	// Run the job.
	score, err := dirSaver.Save(job.BasePath, "", job.Excludes)
	if err != nil {
		log.Fatalf("Saving: %v", err)
	}

	// Print the score.
	fmt.Printf("Score: %s\n", score.Hex())
}
<commit_msg>Made more updates.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 main

import (
	"flag"
	"fmt"
	"github.com/jacobsa/aws/s3"
	"github.com/jacobsa/aws/sdb"
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/crypto"
	"github.com/jacobsa/comeback/config"
	"github.com/jacobsa/comeback/fs"
	s3_kv "github.com/jacobsa/comeback/kv/s3"
	"github.com/jacobsa/comeback/sys"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"time"
)

var g_configFile = flag.String("config", "", "Path to config file.")
var g_jobName = flag.String("job", "", "Job name within the config file.")

func randUint64(randSrc *rand.Rand) uint64

func main() {
	var err error
	flag.Parse()

	// Attempt to read the user's config data.
	if *g_configFile == "" {
		fmt.Println("You must set -config.")
		os.Exit(1)
	}

	configData, err := ioutil.ReadFile(*g_configFile)
	if err != nil {
		fmt.Println("Error reading config file:", err)
		os.Exit(1)
	}

	// Parse the config file.
	cfg, err := config.Parse(configData)
	if err != nil {
		fmt.Println("Parsing config file:", err)
		os.Exit(1)
	}

	// Validate the config file.
	if err := config.Validate(cfg); err != nil {
		fmt.Printf("Config file invalid: %v", err)
		os.Exit(1)
	}

	// Look for the specified job.
	if *g_jobName == "" {
		fmt.Println("You must set -job.")
		os.Exit(1)
	}

	job, ok := cfg.Jobs[*g_jobName]
	if !ok {
		fmt.Println("Unknown job:", *g_jobName)
		os.Exit(1)
	}

	// Create a user registry.
	userRegistry, err := sys.NewUserRegistry()
	if err != nil {
		log.Fatalf("Creating user registry: %v", err)
	}

	// Create a group registry.
	groupRegistry, err := sys.NewGroupRegistry()
	if err != nil {
		log.Fatalf("Creating group registry: %v", err)
	}

	// Create a file system.
	fileSystem, err := fs.NewFileSystem(userRegistry, groupRegistry)
	if err != nil {
		log.Fatalf("Creating file system: %v", err)
	}

	// Open a connection to SimpleDB.
	db, err := sdb.NewSimpleDB(cfg.SdbRegion, cfg.AccessKey)
	if err != nil {
		log.Fatalf("Creating SimpleDB: %v", err)
	}

	// Open a connection to S3.
	bucket, err := s3.OpenBucket(cfg.S3Bucket, cfg.S3Region, cfg.AccessKey)
	if err != nil {
		log.Fatalf("Creating bucket: %v", err)
	}

	// Create the crypter.
	crypter, err := crypto.NewCrypter(cryptoKey)
	if err != nil {
		log.Fatalf("Creating crypter: %v", err)
	}

	// Create the backup registry.
	randSrc := rand.New(rand.NewSource(time.Now().UnixNano()))
	registry, err := backup.NewRegistry(db, cfg.SdbDomain, crypter, randSrc)
	if err != nil {
		log.Fatalf("Creating registry: %v", err)
	}

	// Create the kv store.
	kvStore, err := s3_kv.NewS3KvStore(bucket)
	if err != nil {
		log.Fatalf("Creating kv store: %v", err)
	}

	// Create the blob store.
	blobStore := blob.NewKvBasedBlobStore(kvStore)
	blobStore = blob.NewCheckingStore(blobStore)
	blobStore = blob.NewEncryptingStore(crypter, blobStore)

	// Create the file saver.
	fileSaver, err := backup.NewFileSaver(blobStore, 1<<24)
	if err != nil {
		log.Fatalf("Creating file saver: %v", err)
	}

	// Create a directory saver.
	dirSaver, err := backup.NewDirectorySaver(
		blobStore,
		fileSystem,
		fileSaver)

	if err != nil {
		log.Fatalf("Creating directory saver: %v", err)
	}

	// Run the job.
	score, err := dirSaver.Save(job.BasePath, "", job.Excludes)
	if err != nil {
		log.Fatalf("Saving: %v", err)
	}

	// Register the successful backup.
	completedJob := backup.CompletedJob{
		Id: randUint64(randSrc),
		Name: cfg.JobName,
		StartTime: startTime,
		Score: score,
	}

	if err = registry.RecordBackup(completedJob); err != nil {
		log.Fatalf("Recoding to registry: %v", err)
	}

	fmt.Printf("Successfully backed up. ID: %16x\n", completedJob.Id)
}
<|endoftext|>


<commit_before>package bosh

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/clientcredentials"
)

type Client interface {
	UpdateCloudConfig(yaml []byte) error
	Info() (Info, error)
}

type Info struct {
	Name    string `json:"name"`
	UUID    string `json:"uuid"`
	Version string `json:"version"`
}

type client struct {
	jumpbox         bool
	directorAddress string
	username        string
	password        string
	caCert          string
	httpClient      *http.Client
}

func NewClient(httpClient *http.Client, credhub bool, directorAddress, username, password, caCert string) Client {
	return client{
		directorAddress: directorAddress,
		username:        username,
		password:        password,
		caCert:          caCert,
		jumpbox:         credhub,
		httpClient:      httpClient,
	}
}

func (c client) Info() (Info, error) {
	request, err := http.NewRequest("GET", fmt.Sprintf("%s/info", c.directorAddress), strings.NewReader(""))
	if err != nil {
		return Info{}, err
	}

	response, err := c.httpClient.Do(request)
	if err != nil {
		return Info{}, err
	}

	if response.StatusCode != http.StatusOK {
		return Info{}, fmt.Errorf("unexpected http response %d %s", response.StatusCode, http.StatusText(response.StatusCode))
	}

	var info Info
	if err := json.NewDecoder(response.Body).Decode(&info); err != nil {
		return Info{}, err
	}

	return info, nil
}

func (c client) UpdateCloudConfig(yaml []byte) error {
	request, err := http.NewRequest("POST", fmt.Sprintf("%s/cloud_configs", c.directorAddress), bytes.NewBuffer(yaml))
	if err != nil {
		return err
	}

	request.Header.Set("Content-Type", "text/yaml")

	var response *http.Response
	if c.jumpbox {
		urlParts, err := url.Parse(c.directorAddress)
		if err != nil {
			return err //not tested
		}

		boshHost, _, err := net.SplitHostPort(urlParts.Host)
		if err != nil {
			return err //not tested
		}

		ctx := context.Background()
		ctx = context.WithValue(ctx, oauth2.HTTPClient, c.httpClient)

		conf := &clientcredentials.Config{
			ClientID:     c.username,
			ClientSecret: c.password,
			TokenURL:     fmt.Sprintf("https://%s:8443/oauth/token", boshHost),
		}

		httpClient := conf.Client(ctx)

		response, err = httpClient.Do(request)
		if err != nil {
			return err
		}
	} else {
		request.SetBasicAuth(c.username, c.password)

		var err error
		response, err = c.httpClient.Do(request)
		if err != nil {
			return err
		}

	}

	if response.StatusCode != http.StatusCreated {
		return fmt.Errorf("unexpected http response %d %s", response.StatusCode, http.StatusText(response.StatusCode))
	}

	return nil
}
<commit_msg>Authenticate info requests to director.<commit_after>package bosh

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/clientcredentials"
)

type Client interface {
	UpdateCloudConfig(yaml []byte) error
	Info() (Info, error)
}

type Info struct {
	Name    string `json:"name"`
	UUID    string `json:"uuid"`
	Version string `json:"version"`
}

type client struct {
	jumpbox         bool
	directorAddress string
	username        string
	password        string
	caCert          string
	httpClient      *http.Client
}

func NewClient(httpClient *http.Client, credhub bool, directorAddress, username, password, caCert string) Client {
	return client{
		directorAddress: directorAddress,
		username:        username,
		password:        password,
		caCert:          caCert,
		jumpbox:         credhub,
		httpClient:      httpClient,
	}
}

func (c client) Info() (Info, error) {
	request, err := http.NewRequest("GET", fmt.Sprintf("%s/info", c.directorAddress), strings.NewReader(""))
	if err != nil {
		return Info{}, err
	}

	response, err := c.makeRequest(request)
	if err != nil {
		return Info{}, err
	}

	if response.StatusCode != http.StatusOK {
		return Info{}, fmt.Errorf("unexpected http response %d %s", response.StatusCode, http.StatusText(response.StatusCode))
	}

	var info Info
	if err := json.NewDecoder(response.Body).Decode(&info); err != nil {
		return Info{}, err
	}

	return info, nil
}

func (c client) UpdateCloudConfig(yaml []byte) error {
	request, err := http.NewRequest("POST", fmt.Sprintf("%s/cloud_configs", c.directorAddress), bytes.NewBuffer(yaml))
	if err != nil {
		return err
	}

	request.Header.Set("Content-Type", "text/yaml")
	response, err := c.makeRequest(request)
	if err != nil {
		return err
	}

	if response.StatusCode != http.StatusCreated {
		return fmt.Errorf("unexpected http response %d %s", response.StatusCode, http.StatusText(response.StatusCode))
	}

	return nil
}

func (c client) makeRequest(request *http.Request) (*http.Response, error) {
	if c.jumpbox {
		urlParts, err := url.Parse(c.directorAddress)
		if err != nil {
			return &http.Response{}, err //not tested
		}

		boshHost, _, err := net.SplitHostPort(urlParts.Host)
		if err != nil {
			return &http.Response{}, err //not tested
		}

		ctx := context.Background()
		ctx = context.WithValue(ctx, oauth2.HTTPClient, c.httpClient)

		conf := &clientcredentials.Config{
			ClientID:     c.username,
			ClientSecret: c.password,
			TokenURL:     fmt.Sprintf("https://%s:8443/oauth/token", boshHost),
		}

		httpClient := conf.Client(ctx)
		return httpClient.Do(request)
	} else {
		request.SetBasicAuth(c.username, c.password)
		return c.httpClient.Do(request)
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3
package dsa

import (
	"errors"
	"io"
	"math/big"
)

// Parameters represents the domain parameters for a key. These parameters can
// be shared across many keys. The bit length of Q must be a multiple of 8.
type Parameters struct {
	P, Q, G *big.Int
}

// PublicKey represents a DSA public key.
type PublicKey struct {
	Parameters
	Y *big.Int
}

// PrivateKey represents a DSA private key.
type PrivateKey struct {
	PublicKey
	X *big.Int
}

// ErrInvalidPublicKey results when a public key is not usable by this code.
// FIPS is quite strict about the format of DSA keys, but other code may be
// less so. Thus, when using keys which may have been generated by other code,
// this error must be handled.
var ErrInvalidPublicKey = errors.New("crypto/dsa: invalid public key")

// ParameterSizes is a enumeration of the acceptable bit lengths of the primes
// in a set of DSA parameters. See FIPS 186-3, section 4.2.
type ParameterSizes int

const (
	L1024N160 ParameterSizes = iota
	L2048N224
	L2048N256
	L3072N256
)

// numMRTests is the number of Miller-Rabin primality tests that we perform. We
// pick the largest recommended number from table C.1 of FIPS 186-3.
const numMRTests = 64

// GenerateParameters puts a random, valid set of DSA parameters into params.
// This function takes many seconds, even on fast machines.
func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err error) {
	// This function doesn't follow FIPS 186-3 exactly in that it doesn't
	// use a verification seed to generate the primes. The verification
	// seed doesn't appear to be exported or used by other code and
	// omitting it makes the code cleaner.

	var L, N int
	switch sizes {
	case L1024N160:
		L = 1024
		N = 160
	case L2048N224:
		L = 2048
		N = 224
	case L2048N256:
		L = 2048
		N = 256
	case L3072N256:
		L = 3072
		N = 256
	default:
		return errors.New("crypto/dsa: invalid ParameterSizes")
	}

	qBytes := make([]byte, N/8)
	pBytes := make([]byte, L/8)

	q := new(big.Int)
	p := new(big.Int)
	rem := new(big.Int)
	one := new(big.Int)
	one.SetInt64(1)

GeneratePrimes:
	for {
		_, err = io.ReadFull(rand, qBytes)
		if err != nil {
			return
		}

		qBytes[len(qBytes)-1] |= 1
		qBytes[0] |= 0x80
		q.SetBytes(qBytes)

		if !q.ProbablyPrime(numMRTests) {
			continue
		}

		for i := 0; i < 4*L; i++ {
			_, err = io.ReadFull(rand, pBytes)
			if err != nil {
				return
			}

			pBytes[len(pBytes)-1] |= 1
			pBytes[0] |= 0x80

			p.SetBytes(pBytes)
			rem.Mod(p, q)
			rem.Sub(rem, one)
			p.Sub(p, rem)
			if p.BitLen() < L {
				continue
			}

			if !p.ProbablyPrime(numMRTests) {
				continue
			}

			params.P = p
			params.Q = q
			break GeneratePrimes
		}
	}

	h := new(big.Int)
	h.SetInt64(2)
	g := new(big.Int)

	pm1 := new(big.Int).Sub(p, one)
	e := new(big.Int).Div(pm1, q)

	for {
		g.Exp(h, e, p)
		if g.Cmp(one) == 0 {
			h.Add(h, one)
			continue
		}

		params.G = g
		return
	}

	panic("unreachable")
}

// GenerateKey generates a public&private key pair. The Parameters of the
// PrivateKey must already be valid (see GenerateParameters).
func GenerateKey(priv *PrivateKey, rand io.Reader) error {
	if priv.P == nil || priv.Q == nil || priv.G == nil {
		return errors.New("crypto/dsa: parameters not set up before generating key")
	}

	x := new(big.Int)
	xBytes := make([]byte, priv.Q.BitLen()/8)

	for {
		_, err := io.ReadFull(rand, xBytes)
		if err != nil {
			return err
		}
		x.SetBytes(xBytes)
		if x.Sign() != 0 && x.Cmp(priv.Q) < 0 {
			break
		}
	}

	priv.X = x
	priv.Y = new(big.Int)
	priv.Y.Exp(priv.G, x, priv.P)
	return nil
}

// Sign signs an arbitrary length hash (which should be the result of hashing a
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
// rand.
//
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
// to the byte-length of the subgroup. This function does not perform that
// truncation itself.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	// FIPS 186-3, section 4.6

	n := priv.Q.BitLen()
	if n&7 != 0 {
		err = ErrInvalidPublicKey
		return
	}
	n >>= 3

	for {
		k := new(big.Int)
		buf := make([]byte, n)
		for {
			_, err = io.ReadFull(rand, buf)
			if err != nil {
				return
			}
			k.SetBytes(buf)
			if k.Sign() > 0 && k.Cmp(priv.Q) < 0 {
				break
			}
		}

		kInv := new(big.Int).ModInverse(k, priv.Q)

		r = new(big.Int).Exp(priv.G, k, priv.P)
		r.Mod(r, priv.Q)

		if r.Sign() == 0 {
			continue
		}

		z := k.SetBytes(hash)

		s = new(big.Int).Mul(priv.X, r)
		s.Add(s, z)
		s.Mod(s, priv.Q)
		s.Mul(s, kInv)
		s.Mod(s, priv.Q)

		if s.Sign() != 0 {
			break
		}
	}

	return
}

// Verify verifies the signature in r, s of hash using the public key, pub. It
// reports whether the signature is valid.
//
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
// to the byte-length of the subgroup. This function does not perform that
// truncation itself.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	// FIPS 186-3, section 4.7

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

	w := new(big.Int).ModInverse(s, pub.Q)

	n := pub.Q.BitLen()
	if n&7 != 0 {
		return false
	}
	z := new(big.Int).SetBytes(hash)

	u1 := new(big.Int).Mul(z, w)
	u1.Mod(u1, pub.Q)
	u2 := w.Mul(r, w)
	u2.Mod(u2, pub.Q)
	v := u1.Exp(pub.G, u1, pub.P)
	u2.Exp(pub.Y, u2, pub.P)
	v.Mul(v, u2)
	v.Mod(v, pub.P)
	v.Mod(v, pub.Q)

	return v.Cmp(r) == 0
}
<commit_msg>crypto/dsa: add missing period in package comment<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3.
package dsa

import (
	"errors"
	"io"
	"math/big"
)

// Parameters represents the domain parameters for a key. These parameters can
// be shared across many keys. The bit length of Q must be a multiple of 8.
type Parameters struct {
	P, Q, G *big.Int
}

// PublicKey represents a DSA public key.
type PublicKey struct {
	Parameters
	Y *big.Int
}

// PrivateKey represents a DSA private key.
type PrivateKey struct {
	PublicKey
	X *big.Int
}

// ErrInvalidPublicKey results when a public key is not usable by this code.
// FIPS is quite strict about the format of DSA keys, but other code may be
// less so. Thus, when using keys which may have been generated by other code,
// this error must be handled.
var ErrInvalidPublicKey = errors.New("crypto/dsa: invalid public key")

// ParameterSizes is a enumeration of the acceptable bit lengths of the primes
// in a set of DSA parameters. See FIPS 186-3, section 4.2.
type ParameterSizes int

const (
	L1024N160 ParameterSizes = iota
	L2048N224
	L2048N256
	L3072N256
)

// numMRTests is the number of Miller-Rabin primality tests that we perform. We
// pick the largest recommended number from table C.1 of FIPS 186-3.
const numMRTests = 64

// GenerateParameters puts a random, valid set of DSA parameters into params.
// This function takes many seconds, even on fast machines.
func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err error) {
	// This function doesn't follow FIPS 186-3 exactly in that it doesn't
	// use a verification seed to generate the primes. The verification
	// seed doesn't appear to be exported or used by other code and
	// omitting it makes the code cleaner.

	var L, N int
	switch sizes {
	case L1024N160:
		L = 1024
		N = 160
	case L2048N224:
		L = 2048
		N = 224
	case L2048N256:
		L = 2048
		N = 256
	case L3072N256:
		L = 3072
		N = 256
	default:
		return errors.New("crypto/dsa: invalid ParameterSizes")
	}

	qBytes := make([]byte, N/8)
	pBytes := make([]byte, L/8)

	q := new(big.Int)
	p := new(big.Int)
	rem := new(big.Int)
	one := new(big.Int)
	one.SetInt64(1)

GeneratePrimes:
	for {
		_, err = io.ReadFull(rand, qBytes)
		if err != nil {
			return
		}

		qBytes[len(qBytes)-1] |= 1
		qBytes[0] |= 0x80
		q.SetBytes(qBytes)

		if !q.ProbablyPrime(numMRTests) {
			continue
		}

		for i := 0; i < 4*L; i++ {
			_, err = io.ReadFull(rand, pBytes)
			if err != nil {
				return
			}

			pBytes[len(pBytes)-1] |= 1
			pBytes[0] |= 0x80

			p.SetBytes(pBytes)
			rem.Mod(p, q)
			rem.Sub(rem, one)
			p.Sub(p, rem)
			if p.BitLen() < L {
				continue
			}

			if !p.ProbablyPrime(numMRTests) {
				continue
			}

			params.P = p
			params.Q = q
			break GeneratePrimes
		}
	}

	h := new(big.Int)
	h.SetInt64(2)
	g := new(big.Int)

	pm1 := new(big.Int).Sub(p, one)
	e := new(big.Int).Div(pm1, q)

	for {
		g.Exp(h, e, p)
		if g.Cmp(one) == 0 {
			h.Add(h, one)
			continue
		}

		params.G = g
		return
	}

	panic("unreachable")
}

// GenerateKey generates a public&private key pair. The Parameters of the
// PrivateKey must already be valid (see GenerateParameters).
func GenerateKey(priv *PrivateKey, rand io.Reader) error {
	if priv.P == nil || priv.Q == nil || priv.G == nil {
		return errors.New("crypto/dsa: parameters not set up before generating key")
	}

	x := new(big.Int)
	xBytes := make([]byte, priv.Q.BitLen()/8)

	for {
		_, err := io.ReadFull(rand, xBytes)
		if err != nil {
			return err
		}
		x.SetBytes(xBytes)
		if x.Sign() != 0 && x.Cmp(priv.Q) < 0 {
			break
		}
	}

	priv.X = x
	priv.Y = new(big.Int)
	priv.Y.Exp(priv.G, x, priv.P)
	return nil
}

// Sign signs an arbitrary length hash (which should be the result of hashing a
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
// rand.
//
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
// to the byte-length of the subgroup. This function does not perform that
// truncation itself.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	// FIPS 186-3, section 4.6

	n := priv.Q.BitLen()
	if n&7 != 0 {
		err = ErrInvalidPublicKey
		return
	}
	n >>= 3

	for {
		k := new(big.Int)
		buf := make([]byte, n)
		for {
			_, err = io.ReadFull(rand, buf)
			if err != nil {
				return
			}
			k.SetBytes(buf)
			if k.Sign() > 0 && k.Cmp(priv.Q) < 0 {
				break
			}
		}

		kInv := new(big.Int).ModInverse(k, priv.Q)

		r = new(big.Int).Exp(priv.G, k, priv.P)
		r.Mod(r, priv.Q)

		if r.Sign() == 0 {
			continue
		}

		z := k.SetBytes(hash)

		s = new(big.Int).Mul(priv.X, r)
		s.Add(s, z)
		s.Mod(s, priv.Q)
		s.Mul(s, kInv)
		s.Mod(s, priv.Q)

		if s.Sign() != 0 {
			break
		}
	}

	return
}

// Verify verifies the signature in r, s of hash using the public key, pub. It
// reports whether the signature is valid.
//
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
// to the byte-length of the subgroup. This function does not perform that
// truncation itself.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	// FIPS 186-3, section 4.7

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

	w := new(big.Int).ModInverse(s, pub.Q)

	n := pub.Q.BitLen()
	if n&7 != 0 {
		return false
	}
	z := new(big.Int).SetBytes(hash)

	u1 := new(big.Int).Mul(z, w)
	u1.Mod(u1, pub.Q)
	u2 := w.Mul(r, w)
	u2.Mod(u2, pub.Q)
	v := u1.Exp(pub.G, u1, pub.P)
	u2.Exp(pub.Y, u2, pub.P)
	v.Mul(v, u2)
	v.Mod(v, pub.P)
	v.Mod(v, pub.Q)

	return v.Cmp(r) == 0
}
<|endoftext|>


<commit_before>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	The netchan package implements type-safe networked channels:
	it allows the two ends of a channel to appear on different
	computers connected by a network.  It does this by transporting
	data sent to a channel on one machine so it can be recovered
	by a receive of a channel of the same type on the other.

	An exporter publishes a set of channels by name.  An importer
	connects to the exporting machine and imports the channels
	by name. After importing the channels, the two machines can
	use the channels in the usual way.

	Networked channels are not synchronized; they always behave
	as if they are buffered channels of at least one element.
*/
package netchan

// BUG: can't use range clause to receive when using ImportNValues to limit the count.

import (
	"log"
	"net"
	"os"
	"reflect"
	"sync"
)

// Export

// expLog is a logging convenience function.  The first argument must be a string.
func expLog(args ...interface{}) {
	args[0] = "netchan export: " + args[0].(string)
	log.Print(args...)
}

// An Exporter allows a set of channels to be published on a single
// network port.  A single machine may have multiple Exporters
// but they must use different ports.
type Exporter struct {
	*clientSet
	listener net.Listener
}

type expClient struct {
	*encDec
	exp     *Exporter
	mu      sync.Mutex // protects remaining fields
	errored bool       // client has been sent an error
	seqNum  int64      // sequences messages sent to client; has value of highest sent
	ackNum  int64      // highest sequence number acknowledged
}

func newClient(exp *Exporter, conn net.Conn) *expClient {
	client := new(expClient)
	client.exp = exp
	client.encDec = newEncDec(conn)
	client.seqNum = 0
	client.ackNum = 0
	return client

}

func (client *expClient) sendError(hdr *header, err string) {
	error := &error{err}
	expLog("sending error to client:", error.error)
	client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
	client.mu.Lock()
	client.errored = true
	client.mu.Unlock()
}

func (client *expClient) getChan(hdr *header, dir Dir) *chanDir {
	exp := client.exp
	exp.mu.Lock()
	ech, ok := exp.chans[hdr.name]
	exp.mu.Unlock()
	if !ok {
		client.sendError(hdr, "no such channel: "+hdr.name)
		return nil
	}
	if ech.dir != dir {
		client.sendError(hdr, "wrong direction for channel: "+hdr.name)
		return nil
	}
	return ech
}

// The function run manages sends and receives for a single client.  For each
// (client Recv) request, this will launch a serveRecv goroutine to deliver
// the data for that channel, while (client Send) requests are handled as
// data arrives from the client.
func (client *expClient) run() {
	hdr := new(header)
	hdrValue := reflect.NewValue(hdr)
	req := new(request)
	reqValue := reflect.NewValue(req)
	error := new(error)
	for {
		*hdr = header{}
		if err := client.decode(hdrValue); err != nil {
			expLog("error decoding client header:", err)
			break
		}
		switch hdr.payloadType {
		case payRequest:
			*req = request{}
			if err := client.decode(reqValue); err != nil {
				expLog("error decoding client request:", err)
				break
			}
			switch req.dir {
			case Recv:
				go client.serveRecv(*hdr, req.count)
			case Send:
				// Request to send is clear as a matter of protocol
				// but not actually used by the implementation.
				// The actual sends will have payload type payData.
				// TODO: manage the count?
			default:
				error.error = "request: can't handle channel direction"
				expLog(error.error, req.dir)
				client.encode(hdr, payError, error)
			}
		case payData:
			client.serveSend(*hdr)
		case payClosed:
			client.serveClosed(*hdr)
		case payAck:
			client.mu.Lock()
			if client.ackNum != hdr.seqNum-1 {
				// Since the sequence number is incremented and the message is sent
				// in a single instance of locking client.mu, the messages are guaranteed
				// to be sent in order.  Therefore receipt of acknowledgement N means
				// all messages <=N have been seen by the recipient.  We check anyway.
				expLog("sequence out of order:", client.ackNum, hdr.seqNum)
			}
			if client.ackNum < hdr.seqNum { // If there has been an error, don't back up the count.
				client.ackNum = hdr.seqNum
			}
			client.mu.Unlock()
		default:
			log.Exit("netchan export: unknown payload type", hdr.payloadType)
		}
	}
	client.exp.delClient(client)
}

// Send all the data on a single channel to a client asking for a Recv.
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveRecv(hdr header, count int64) {
	ech := client.getChan(&hdr, Send)
	if ech == nil {
		return
	}
	for {
		val := ech.ch.Recv()
		if ech.ch.Closed() {
			if err := client.encode(&hdr, payClosed, nil); err != nil {
				expLog("error encoding server closed message:", err)
			}
			break
		}
		// We hold the lock during transmission to guarantee messages are
		// sent in sequence number order.  Also, we increment first so the
		// value of client.seqNum is the value of the highest used sequence
		// number, not one beyond.
		client.mu.Lock()
		client.seqNum++
		hdr.seqNum = client.seqNum
		err := client.encode(&hdr, payData, val.Interface())
		client.mu.Unlock()
		if err != nil {
			expLog("error encoding client response:", err)
			client.sendError(&hdr, err.String())
			break
		}
		// Negative count means run forever.
		if count >= 0 {
			if count--; count <= 0 {
				break
			}
		}
	}
}

// Receive and deliver locally one item from a client asking for a Send
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveSend(hdr header) {
	ech := client.getChan(&hdr, Recv)
	if ech == nil {
		return
	}
	// Create a new value for each received item.
	val := reflect.MakeZero(ech.ch.Type().(*reflect.ChanType).Elem())
	if err := client.decode(val); err != nil {
		expLog("value decode:", err)
		return
	}
	ech.ch.Send(val)
}

// Report that client has closed the channel that is sending to us.
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveClosed(hdr header) {
	ech := client.getChan(&hdr, Recv)
	if ech == nil {
		return
	}
	ech.ch.Close()
}

func (client *expClient) unackedCount() int64 {
	client.mu.Lock()
	n := client.seqNum - client.ackNum
	client.mu.Unlock()
	return n
}

func (client *expClient) seq() int64 {
	client.mu.Lock()
	n := client.seqNum
	client.mu.Unlock()
	return n
}

func (client *expClient) ack() int64 {
	client.mu.Lock()
	n := client.seqNum
	client.mu.Unlock()
	return n
}

// Wait for incoming connections, start a new runner for each
func (exp *Exporter) listen() {
	for {
		conn, err := exp.listener.Accept()
		if err != nil {
			expLog("listen:", err)
			break
		}
		client := exp.addClient(conn)
		go client.run()
	}
}

// NewExporter creates a new Exporter to export channels
// on the network and local address defined as in net.Listen.
func NewExporter(network, localaddr string) (*Exporter, os.Error) {
	listener, err := net.Listen(network, localaddr)
	if err != nil {
		return nil, err
	}
	e := &Exporter{
		listener: listener,
		clientSet: &clientSet{
			chans:   make(map[string]*chanDir),
			clients: make(map[unackedCounter]bool),
		},
	}
	go e.listen()
	return e, nil
}

// addClient creates a new expClient and records its existence
func (exp *Exporter) addClient(conn net.Conn) *expClient {
	client := newClient(exp, conn)
	exp.clients[client] = true
	exp.mu.Unlock()
	return client
}

// delClient forgets the client existed
func (exp *Exporter) delClient(client *expClient) {
	exp.mu.Lock()
	exp.clients[client] = false, false
	exp.mu.Unlock()
}

// Drain waits until all messages sent from this exporter/importer, including
// those not yet sent to any client and possibly including those sent while
// Drain was executing, have been received by the importer.  In short, it
// waits until all the exporter's messages have been received by a client.
// If the timeout (measured in nanoseconds) is positive and Drain takes
// longer than that to complete, an error is returned.
func (exp *Exporter) Drain(timeout int64) os.Error {
	// This wrapper function is here so the method's comment will appear in godoc.
	return exp.clientSet.drain(timeout)
}

// Sync waits until all clients of the exporter have received the messages
// that were sent at the time Sync was invoked.  Unlike Drain, it does not
// wait for messages sent while it is running or messages that have not been
// dispatched to any client.  If the timeout (measured in nanoseconds) is
// positive and Sync takes longer than that to complete, an error is
// returned.
func (exp *Exporter) Sync(timeout int64) os.Error {
	// This wrapper function is here so the method's comment will appear in godoc.
	return exp.clientSet.sync(timeout)
}

// Addr returns the Exporter's local network address.
func (exp *Exporter) Addr() net.Addr { return exp.listener.Addr() }

func checkChan(chT interface{}, dir Dir) (*reflect.ChanValue, os.Error) {
	chanType, ok := reflect.Typeof(chT).(*reflect.ChanType)
	if !ok {
		return nil, os.ErrorString("not a channel")
	}
	if dir != Send && dir != Recv {
		return nil, os.ErrorString("unknown channel direction")
	}
	switch chanType.Dir() {
	case reflect.BothDir:
	case reflect.SendDir:
		if dir != Recv {
			return nil, os.ErrorString("to import/export with Send, must provide <-chan")
		}
	case reflect.RecvDir:
		if dir != Send {
			return nil, os.ErrorString("to import/export with Recv, must provide chan<-")
		}
	}
	return reflect.NewValue(chT).(*reflect.ChanValue), nil
}

// Export exports a channel of a given type and specified direction.  The
// channel to be exported is provided in the call and may be of arbitrary
// channel type.
// Despite the literal signature, the effective signature is
//	Export(name string, chT chan T, dir Dir)
func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
	ch, err := checkChan(chT, dir)
	if err != nil {
		return err
	}
	exp.mu.Lock()
	defer exp.mu.Unlock()
	_, present := exp.chans[name]
	if present {
		return os.ErrorString("channel name already being exported:" + name)
	}
	exp.chans[name] = &chanDir{ch, dir}
	return nil
}

// Hangup disassociates the named channel from the Exporter and closes
// the channel.  Messages in flight for the channel may be dropped.
func (exp *Exporter) Hangup(name string) os.Error {
	exp.mu.Lock()
	chDir, ok := exp.chans[name]
	if ok {
		exp.chans[name] = nil, false
	}
	exp.mu.Unlock()
	if !ok {
		return os.ErrorString("netchan export: hangup: no such channel: " + name)
	}
	chDir.ch.Close()
	return nil
}
<commit_msg>netchan: fix locking bug. There's no need to hold the client mutex when calling encode, since encode itself uses a mutex to make the writes atomic.  However, we need to keep the messages ordered, so add a mutex for that purpose alone. Fixes #1244.<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	The netchan package implements type-safe networked channels:
	it allows the two ends of a channel to appear on different
	computers connected by a network.  It does this by transporting
	data sent to a channel on one machine so it can be recovered
	by a receive of a channel of the same type on the other.

	An exporter publishes a set of channels by name.  An importer
	connects to the exporting machine and imports the channels
	by name. After importing the channels, the two machines can
	use the channels in the usual way.

	Networked channels are not synchronized; they always behave
	as if they are buffered channels of at least one element.
*/
package netchan

// BUG: can't use range clause to receive when using ImportNValues to limit the count.

import (
	"log"
	"net"
	"os"
	"reflect"
	"sync"
)

// Export

// expLog is a logging convenience function.  The first argument must be a string.
func expLog(args ...interface{}) {
	args[0] = "netchan export: " + args[0].(string)
	log.Print(args...)
}

// An Exporter allows a set of channels to be published on a single
// network port.  A single machine may have multiple Exporters
// but they must use different ports.
type Exporter struct {
	*clientSet
	listener net.Listener
}

type expClient struct {
	*encDec
	exp     *Exporter
	mu      sync.Mutex // protects remaining fields
	errored bool       // client has been sent an error
	seqNum  int64      // sequences messages sent to client; has value of highest sent
	ackNum  int64      // highest sequence number acknowledged
	seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
}

func newClient(exp *Exporter, conn net.Conn) *expClient {
	client := new(expClient)
	client.exp = exp
	client.encDec = newEncDec(conn)
	client.seqNum = 0
	client.ackNum = 0
	return client

}

func (client *expClient) sendError(hdr *header, err string) {
	error := &error{err}
	expLog("sending error to client:", error.error)
	client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
	client.mu.Lock()
	client.errored = true
	client.mu.Unlock()
}

func (client *expClient) getChan(hdr *header, dir Dir) *chanDir {
	exp := client.exp
	exp.mu.Lock()
	ech, ok := exp.chans[hdr.name]
	exp.mu.Unlock()
	if !ok {
		client.sendError(hdr, "no such channel: "+hdr.name)
		return nil
	}
	if ech.dir != dir {
		client.sendError(hdr, "wrong direction for channel: "+hdr.name)
		return nil
	}
	return ech
}

// The function run manages sends and receives for a single client.  For each
// (client Recv) request, this will launch a serveRecv goroutine to deliver
// the data for that channel, while (client Send) requests are handled as
// data arrives from the client.
func (client *expClient) run() {
	hdr := new(header)
	hdrValue := reflect.NewValue(hdr)
	req := new(request)
	reqValue := reflect.NewValue(req)
	error := new(error)
	for {
		*hdr = header{}
		if err := client.decode(hdrValue); err != nil {
			expLog("error decoding client header:", err)
			break
		}
		switch hdr.payloadType {
		case payRequest:
			*req = request{}
			if err := client.decode(reqValue); err != nil {
				expLog("error decoding client request:", err)
				break
			}
			switch req.dir {
			case Recv:
				go client.serveRecv(*hdr, req.count)
			case Send:
				// Request to send is clear as a matter of protocol
				// but not actually used by the implementation.
				// The actual sends will have payload type payData.
				// TODO: manage the count?
			default:
				error.error = "request: can't handle channel direction"
				expLog(error.error, req.dir)
				client.encode(hdr, payError, error)
			}
		case payData:
			client.serveSend(*hdr)
		case payClosed:
			client.serveClosed(*hdr)
		case payAck:
			client.mu.Lock()
			if client.ackNum != hdr.seqNum-1 {
				// Since the sequence number is incremented and the message is sent
				// in a single instance of locking client.mu, the messages are guaranteed
				// to be sent in order.  Therefore receipt of acknowledgement N means
				// all messages <=N have been seen by the recipient.  We check anyway.
				expLog("sequence out of order:", client.ackNum, hdr.seqNum)
			}
			if client.ackNum < hdr.seqNum { // If there has been an error, don't back up the count.
				client.ackNum = hdr.seqNum
			}
			client.mu.Unlock()
		default:
			log.Exit("netchan export: unknown payload type", hdr.payloadType)
		}
	}
	client.exp.delClient(client)
}

// Send all the data on a single channel to a client asking for a Recv.
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveRecv(hdr header, count int64) {
	ech := client.getChan(&hdr, Send)
	if ech == nil {
		return
	}
	for {
		val := ech.ch.Recv()
		if ech.ch.Closed() {
			if err := client.encode(&hdr, payClosed, nil); err != nil {
				expLog("error encoding server closed message:", err)
			}
			break
		}
		// We hold the lock during transmission to guarantee messages are
		// sent in sequence number order.  Also, we increment first so the
		// value of client.seqNum is the value of the highest used sequence
		// number, not one beyond.
		client.mu.Lock()
		client.seqNum++
		hdr.seqNum = client.seqNum
		client.seqLock.Lock() // guarantee ordering of messages
		client.mu.Unlock()
		err := client.encode(&hdr, payData, val.Interface())
		client.seqLock.Unlock()
		if err != nil {
			expLog("error encoding client response:", err)
			client.sendError(&hdr, err.String())
			break
		}
		// Negative count means run forever.
		if count >= 0 {
			if count--; count <= 0 {
				break
			}
		}
	}
}

// Receive and deliver locally one item from a client asking for a Send
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveSend(hdr header) {
	ech := client.getChan(&hdr, Recv)
	if ech == nil {
		return
	}
	// Create a new value for each received item.
	val := reflect.MakeZero(ech.ch.Type().(*reflect.ChanType).Elem())
	if err := client.decode(val); err != nil {
		expLog("value decode:", err)
		return
	}
	ech.ch.Send(val)
}

// Report that client has closed the channel that is sending to us.
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveClosed(hdr header) {
	ech := client.getChan(&hdr, Recv)
	if ech == nil {
		return
	}
	ech.ch.Close()
}

func (client *expClient) unackedCount() int64 {
	client.mu.Lock()
	n := client.seqNum - client.ackNum
	client.mu.Unlock()
	return n
}

func (client *expClient) seq() int64 {
	client.mu.Lock()
	n := client.seqNum
	client.mu.Unlock()
	return n
}

func (client *expClient) ack() int64 {
	client.mu.Lock()
	n := client.seqNum
	client.mu.Unlock()
	return n
}

// Wait for incoming connections, start a new runner for each
func (exp *Exporter) listen() {
	for {
		conn, err := exp.listener.Accept()
		if err != nil {
			expLog("listen:", err)
			break
		}
		client := exp.addClient(conn)
		go client.run()
	}
}

// NewExporter creates a new Exporter to export channels
// on the network and local address defined as in net.Listen.
func NewExporter(network, localaddr string) (*Exporter, os.Error) {
	listener, err := net.Listen(network, localaddr)
	if err != nil {
		return nil, err
	}
	e := &Exporter{
		listener: listener,
		clientSet: &clientSet{
			chans:   make(map[string]*chanDir),
			clients: make(map[unackedCounter]bool),
		},
	}
	go e.listen()
	return e, nil
}

// addClient creates a new expClient and records its existence
func (exp *Exporter) addClient(conn net.Conn) *expClient {
	client := newClient(exp, conn)
	exp.clients[client] = true
	exp.mu.Unlock()
	return client
}

// delClient forgets the client existed
func (exp *Exporter) delClient(client *expClient) {
	exp.mu.Lock()
	exp.clients[client] = false, false
	exp.mu.Unlock()
}

// Drain waits until all messages sent from this exporter/importer, including
// those not yet sent to any client and possibly including those sent while
// Drain was executing, have been received by the importer.  In short, it
// waits until all the exporter's messages have been received by a client.
// If the timeout (measured in nanoseconds) is positive and Drain takes
// longer than that to complete, an error is returned.
func (exp *Exporter) Drain(timeout int64) os.Error {
	// This wrapper function is here so the method's comment will appear in godoc.
	return exp.clientSet.drain(timeout)
}

// Sync waits until all clients of the exporter have received the messages
// that were sent at the time Sync was invoked.  Unlike Drain, it does not
// wait for messages sent while it is running or messages that have not been
// dispatched to any client.  If the timeout (measured in nanoseconds) is
// positive and Sync takes longer than that to complete, an error is
// returned.
func (exp *Exporter) Sync(timeout int64) os.Error {
	// This wrapper function is here so the method's comment will appear in godoc.
	return exp.clientSet.sync(timeout)
}

// Addr returns the Exporter's local network address.
func (exp *Exporter) Addr() net.Addr { return exp.listener.Addr() }

func checkChan(chT interface{}, dir Dir) (*reflect.ChanValue, os.Error) {
	chanType, ok := reflect.Typeof(chT).(*reflect.ChanType)
	if !ok {
		return nil, os.ErrorString("not a channel")
	}
	if dir != Send && dir != Recv {
		return nil, os.ErrorString("unknown channel direction")
	}
	switch chanType.Dir() {
	case reflect.BothDir:
	case reflect.SendDir:
		if dir != Recv {
			return nil, os.ErrorString("to import/export with Send, must provide <-chan")
		}
	case reflect.RecvDir:
		if dir != Send {
			return nil, os.ErrorString("to import/export with Recv, must provide chan<-")
		}
	}
	return reflect.NewValue(chT).(*reflect.ChanValue), nil
}

// Export exports a channel of a given type and specified direction.  The
// channel to be exported is provided in the call and may be of arbitrary
// channel type.
// Despite the literal signature, the effective signature is
//	Export(name string, chT chan T, dir Dir)
func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
	ch, err := checkChan(chT, dir)
	if err != nil {
		return err
	}
	exp.mu.Lock()
	defer exp.mu.Unlock()
	_, present := exp.chans[name]
	if present {
		return os.ErrorString("channel name already being exported:" + name)
	}
	exp.chans[name] = &chanDir{ch, dir}
	return nil
}

// Hangup disassociates the named channel from the Exporter and closes
// the channel.  Messages in flight for the channel may be dropped.
func (exp *Exporter) Hangup(name string) os.Error {
	exp.mu.Lock()
	chDir, ok := exp.chans[name]
	if ok {
		exp.chans[name] = nil, false
	}
	exp.mu.Unlock()
	if !ok {
		return os.ErrorString("netchan export: hangup: no such channel: " + name)
	}
	chDir.ch.Close()
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package runtime contains operations that interact with Go's runtime system,
	such as functions to control goroutines. It also includes the low-level type information
	used by the reflect package; see reflect's documentation for the programmable
	interface to the run-time type system.
*/
package runtime

// Gosched yields the processor, allowing other goroutines to run.  It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched()

// Goexit terminates the goroutine that calls it.  No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine.
func Goexit()

// Caller reports file and line number information about function invocations on
// the calling goroutine's stack.  The argument skip is the number of stack frames
// to ascend, with 1 identifying the caller of Caller.  (For historical reasons the
// meaning of skip differs between Caller and Callers.) The return values report the
// program counter, file name, and line number within the file of the corresponding
// call.  The boolean ok is false if it was not possible to recover the information.
func Caller(skip int) (pc uintptr, file string, line int, ok bool)

// Callers fills the slice pc with the program counters of function invocations
// on the calling goroutine's stack.  The argument skip is the number of stack frames
// to skip before recording in pc, with 0 starting at the caller of Callers.
// It returns the number of entries written to pc.
func Callers(skip int, pc []uintptr) int

type Func struct { // Keep in sync with runtime.h:struct Func
	name   string
	typ    string  // go type string
	src    string  // src file name
	pcln   []byte  // pc/ln tab for this func
	entry  uintptr // entry pc
	pc0    uintptr // starting pc, ln for table
	ln0    int32
	frame  int32 // stack frame size
	args   int32 // number of 32-bit in/out args
	locals int32 // number of 32-bit locals
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func

// Name returns the name of the function.
func (f *Func) Name() string { return f.name }

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr { return f.entry }

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	return funcline_go(f, pc)
}

// implemented in symtab.c
func funcline_go(*Func, uintptr) (string, int)

// mid returns the current os thread (m) id.
func mid() uint32

// SetFinalizer sets the finalizer associated with x to f.
// When the garbage collector finds an unreachable block
// with an associated finalizer, it clears the association and runs
// f(x) in a separate goroutine.  This makes x reachable again, but
// now without an associated finalizer.  Assuming that SetFinalizer
// is not called again, the next time the garbage collector sees
// that x is unreachable, it will free x.
//
// SetFinalizer(x, nil) clears any finalizer associated with x.
//
// The argument x must be a pointer to an object allocated by
// calling new or by taking the address of a composite literal.
// The argument f must be a function that takes a single argument
// of x's type and can have arbitrary ignored return values.
// If either of these is not true, SetFinalizer aborts the program.
//
// Finalizers are run in dependency order: if A points at B, both have
// finalizers, and they are otherwise unreachable, only the finalizer
// for A runs; once A is freed, the finalizer for B can run.
// If a cyclic structure includes a block with a finalizer, that
// cycle is not guaranteed to be garbage collected and the finalizer
// is not guaranteed to run, because there is no ordering that
// respects the dependencies.
//
// The finalizer for x is scheduled to run at some arbitrary time after
// x becomes unreachable.
// There is no guarantee that finalizers will run before a program exits,
// so typically they are useful only for releasing non-memory resources
// associated with an object during a long-running program.
// For example, an os.File object could use a finalizer to close the
// associated operating system file descriptor when a program discards
// an os.File without calling Close, but it would be a mistake
// to depend on a finalizer to flush an in-memory I/O buffer such as a
// bufio.Writer, because the buffer would not be flushed at program exit.
//
// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
func SetFinalizer(x, f interface{})

func getgoroot() string

// GOROOT returns the root of the Go tree.
// It uses the GOROOT environment variable, if set,
// or else the root used during the Go build.
func GOROOT() string {
	s := getgoroot()
	if s != "" {
		return s
	}
	return defaultGoroot
}

// Version returns the Go tree's version string.
// It is either a sequence number or, when possible,
// a release tag like "release.2010-03-04".
// A trailing + indicates that the tree had local modifications
// at the time of the build.
func Version() string {
	return theVersion
}

// GOOS is the running program's operating system target:
// one of darwin, freebsd, linux, and so on.
const GOOS string = theGoos

// GOARCH is the running program's architecture target:
// 386, amd64, or arm.
const GOARCH string = theGoarch
<commit_msg>runtime: fix docs for Caller and Callers The previous attempt to explain this got it backwards (all the more reason to be sad we couldn't make the two functions behave the same).<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package runtime contains operations that interact with Go's runtime system,
	such as functions to control goroutines. It also includes the low-level type information
	used by the reflect package; see reflect's documentation for the programmable
	interface to the run-time type system.
*/
package runtime

// Gosched yields the processor, allowing other goroutines to run.  It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched()

// Goexit terminates the goroutine that calls it.  No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine.
func Goexit()

// Caller reports file and line number information about function invocations on
// the calling goroutine's stack.  The argument skip is the number of stack frames
// to ascend, with 0 identifying the caller of Caller.  (For historical reasons the
// meaning of skip differs between Caller and Callers.) The return values report the
// program counter, file name, and line number within the file of the corresponding
// call.  The boolean ok is false if it was not possible to recover the information.
func Caller(skip int) (pc uintptr, file string, line int, ok bool)

// Callers fills the slice pc with the program counters of function invocations
// on the calling goroutine's stack.  The argument skip is the number of stack frames
// to skip before recording in pc, with 0 identifying the frame for Callers itself and
// 1 identifying the caller of Callers.
// It returns the number of entries written to pc.
func Callers(skip int, pc []uintptr) int

type Func struct { // Keep in sync with runtime.h:struct Func
	name   string
	typ    string  // go type string
	src    string  // src file name
	pcln   []byte  // pc/ln tab for this func
	entry  uintptr // entry pc
	pc0    uintptr // starting pc, ln for table
	ln0    int32
	frame  int32 // stack frame size
	args   int32 // number of 32-bit in/out args
	locals int32 // number of 32-bit locals
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func

// Name returns the name of the function.
func (f *Func) Name() string { return f.name }

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr { return f.entry }

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	return funcline_go(f, pc)
}

// implemented in symtab.c
func funcline_go(*Func, uintptr) (string, int)

// mid returns the current os thread (m) id.
func mid() uint32

// SetFinalizer sets the finalizer associated with x to f.
// When the garbage collector finds an unreachable block
// with an associated finalizer, it clears the association and runs
// f(x) in a separate goroutine.  This makes x reachable again, but
// now without an associated finalizer.  Assuming that SetFinalizer
// is not called again, the next time the garbage collector sees
// that x is unreachable, it will free x.
//
// SetFinalizer(x, nil) clears any finalizer associated with x.
//
// The argument x must be a pointer to an object allocated by
// calling new or by taking the address of a composite literal.
// The argument f must be a function that takes a single argument
// of x's type and can have arbitrary ignored return values.
// If either of these is not true, SetFinalizer aborts the program.
//
// Finalizers are run in dependency order: if A points at B, both have
// finalizers, and they are otherwise unreachable, only the finalizer
// for A runs; once A is freed, the finalizer for B can run.
// If a cyclic structure includes a block with a finalizer, that
// cycle is not guaranteed to be garbage collected and the finalizer
// is not guaranteed to run, because there is no ordering that
// respects the dependencies.
//
// The finalizer for x is scheduled to run at some arbitrary time after
// x becomes unreachable.
// There is no guarantee that finalizers will run before a program exits,
// so typically they are useful only for releasing non-memory resources
// associated with an object during a long-running program.
// For example, an os.File object could use a finalizer to close the
// associated operating system file descriptor when a program discards
// an os.File without calling Close, but it would be a mistake
// to depend on a finalizer to flush an in-memory I/O buffer such as a
// bufio.Writer, because the buffer would not be flushed at program exit.
//
// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
func SetFinalizer(x, f interface{})

func getgoroot() string

// GOROOT returns the root of the Go tree.
// It uses the GOROOT environment variable, if set,
// or else the root used during the Go build.
func GOROOT() string {
	s := getgoroot()
	if s != "" {
		return s
	}
	return defaultGoroot
}

// Version returns the Go tree's version string.
// It is either a sequence number or, when possible,
// a release tag like "release.2010-03-04".
// A trailing + indicates that the tree had local modifications
// at the time of the build.
func Version() string {
	return theVersion
}

// GOOS is the running program's operating system target:
// one of darwin, freebsd, linux, and so on.
const GOOS string = theGoos

// GOARCH is the running program's architecture target:
// 386, amd64, or arm.
const GOARCH string = theGoarch
<|endoftext|>


<commit_before>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import (
	"unsafe"
)

func concatstrings(a []string) string {
	idx := 0
	l := 0
	count := 0
	for i, x := range a {
		n := len(x)
		if n == 0 {
			continue
		}
		if l+n < l {
			panic("string concatenation too long")
		}
		l += n
		count++
		idx = i
	}
	if count == 0 {
		return ""
	}
	if count == 1 {
		return a[idx]
	}
	s, b := rawstring(l)
	l = 0
	for _, x := range a {
		copy(b[l:], x)
		l += len(x)
	}
	return s
}

//go:nosplit
func concatstring2(a [2]string) string {
	return concatstrings(a[:])
}

//go:nosplit
func concatstring3(a [3]string) string {
	return concatstrings(a[:])
}

//go:nosplit
func concatstring4(a [4]string) string {
	return concatstrings(a[:])
}

//go:nosplit
func concatstring5(a [5]string) string {
	return concatstrings(a[:])
}

func slicebytetostring(b []byte) string {
	if raceenabled && len(b) > 0 {
		fn := slicebytetostring
		racereadrangepc(unsafe.Pointer(&b[0]),
			len(b),
			getcallerpc(unsafe.Pointer(&b)),
			**(**uintptr)(unsafe.Pointer(&fn)))
	}
	s, c := rawstring(len(b))
	copy(c, b)
	return s
}

func slicebytetostringtmp(b []byte) string {
	// Return a "string" referring to the actual []byte bytes.
	// This is only for use by internal compiler optimizations
	// that know that the string form will be discarded before
	// the calling goroutine could possibly modify the original
	// slice or synchronize with another goroutine.
	// Today, the only such case is a m[string(k)] lookup where
	// m is a string-keyed map and k is a []byte.

	if raceenabled && len(b) > 0 {
		fn := slicebytetostringtmp
		racereadrangepc(unsafe.Pointer(&b[0]),
			len(b),
			getcallerpc(unsafe.Pointer(&b)),
			**(**uintptr)(unsafe.Pointer(&fn)))
	}
	return *(*string)(unsafe.Pointer(&b))
}

func stringtoslicebyte(s string) []byte {
	b := rawbyteslice(len(s))
	copy(b, s)
	return b
}

func stringtoslicerune(s string) []rune {
	// two passes.
	// unlike slicerunetostring, no race because strings are immutable.
	n := 0
	t := s
	for len(s) > 0 {
		_, k := charntorune(s)
		s = s[k:]
		n++
	}
	a := rawruneslice(n)
	n = 0
	for len(t) > 0 {
		r, k := charntorune(t)
		t = t[k:]
		a[n] = r
		n++
	}
	return a
}

func slicerunetostring(a []rune) string {
	if raceenabled && len(a) > 0 {
		fn := slicerunetostring
		racereadrangepc(unsafe.Pointer(&a[0]),
			len(a)*int(unsafe.Sizeof(a[0])),
			getcallerpc(unsafe.Pointer(&a)),
			**(**uintptr)(unsafe.Pointer(&fn)))
	}
	var dum [4]byte
	size1 := 0
	for _, r := range a {
		size1 += runetochar(dum[:], r)
	}
	s, b := rawstring(size1 + 3)
	size2 := 0
	for _, r := range a {
		// check for race
		if size2 >= size1 {
			break
		}
		size2 += runetochar(b[size2:], r)
	}
	return s[:size2]
}

type stringStruct struct {
	str unsafe.Pointer
	len int
}

func cstringToGo(str unsafe.Pointer) (s string) {
	i := 0
	for ; ; i++ {
		if *(*byte)(unsafe.Pointer(uintptr(str) + uintptr(i))) == 0 {
			break
		}
	}
	t := (*stringStruct)(unsafe.Pointer(&s))
	t.str = unsafe.Pointer(str)
	t.len = i
	return
}

func intstring(v int64) string {
	s, b := rawstring(4)
	n := runetochar(b, rune(v))
	return s[:n]
}

// stringiter returns the index of the next
// rune after the rune that starts at s[k].
func stringiter(s string, k int) int {
	if k >= len(s) {
		// 0 is end of iteration
		return 0
	}

	c := s[k]
	if c < runeself {
		return k + 1
	}

	// multi-char rune
	_, n := charntorune(s[k:])
	return k + n
}

// stringiter2 returns the rune that starts at s[k]
// and the index where the next rune starts.
func stringiter2(s string, k int) (int, rune) {
	if k >= len(s) {
		// 0 is end of iteration
		return 0, 0
	}

	c := s[k]
	if c < runeself {
		return k + 1, rune(c)
	}

	// multi-char rune
	r, n := charntorune(s[k:])
	return k + n, r
}

// rawstring allocates storage for a new string. The returned
// string and byte slice both refer to the same storage.
// The storage is not zeroed. Callers should use
// b to set the string contents and then drop b.
func rawstring(size int) (s string, b []byte) {
	p := gomallocgc(uintptr(size), nil, flagNoScan|flagNoZero)

	(*stringStruct)(unsafe.Pointer(&s)).str = p
	(*stringStruct)(unsafe.Pointer(&s)).len = size

	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
	(*slice)(unsafe.Pointer(&b)).len = uint(size)
	(*slice)(unsafe.Pointer(&b)).cap = uint(size)

	for {
		ms := maxstring
		if uintptr(size) <= uintptr(ms) || casuintptr((*uintptr)(unsafe.Pointer(&maxstring)), uintptr(ms), uintptr(size)) {
			return
		}
	}
}

// rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
func rawbyteslice(size int) (b []byte) {
	cap := goroundupsize(uintptr(size))
	p := gomallocgc(cap, nil, flagNoScan|flagNoZero)
	if cap != uintptr(size) {
		memclr(add(p, uintptr(size)), cap-uintptr(size))
	}

	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
	(*slice)(unsafe.Pointer(&b)).len = uint(size)
	(*slice)(unsafe.Pointer(&b)).cap = uint(cap)
	return
}

// rawruneslice allocates a new rune slice. The rune slice is not zeroed.
func rawruneslice(size int) (b []rune) {
	if uintptr(size) > maxMem/4 {
		gothrow("out of memory")
	}
	mem := goroundupsize(uintptr(size) * 4)
	p := gomallocgc(mem, nil, flagNoScan|flagNoZero)
	if mem != uintptr(size)*4 {
		memclr(add(p, uintptr(size)*4), mem-uintptr(size)*4)
	}

	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
	(*slice)(unsafe.Pointer(&b)).len = uint(size)
	(*slice)(unsafe.Pointer(&b)).cap = uint(mem / 4)
	return
}
<commit_msg>runtime: change concatstring panic to gothrow<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import (
	"unsafe"
)

func concatstrings(a []string) string {
	idx := 0
	l := 0
	count := 0
	for i, x := range a {
		n := len(x)
		if n == 0 {
			continue
		}
		if l+n < l {
			gothrow("string concatenation too long")
		}
		l += n
		count++
		idx = i
	}
	if count == 0 {
		return ""
	}
	if count == 1 {
		return a[idx]
	}
	s, b := rawstring(l)
	l = 0
	for _, x := range a {
		copy(b[l:], x)
		l += len(x)
	}
	return s
}

//go:nosplit
func concatstring2(a [2]string) string {
	return concatstrings(a[:])
}

//go:nosplit
func concatstring3(a [3]string) string {
	return concatstrings(a[:])
}

//go:nosplit
func concatstring4(a [4]string) string {
	return concatstrings(a[:])
}

//go:nosplit
func concatstring5(a [5]string) string {
	return concatstrings(a[:])
}

func slicebytetostring(b []byte) string {
	if raceenabled && len(b) > 0 {
		fn := slicebytetostring
		racereadrangepc(unsafe.Pointer(&b[0]),
			len(b),
			getcallerpc(unsafe.Pointer(&b)),
			**(**uintptr)(unsafe.Pointer(&fn)))
	}
	s, c := rawstring(len(b))
	copy(c, b)
	return s
}

func slicebytetostringtmp(b []byte) string {
	// Return a "string" referring to the actual []byte bytes.
	// This is only for use by internal compiler optimizations
	// that know that the string form will be discarded before
	// the calling goroutine could possibly modify the original
	// slice or synchronize with another goroutine.
	// Today, the only such case is a m[string(k)] lookup where
	// m is a string-keyed map and k is a []byte.

	if raceenabled && len(b) > 0 {
		fn := slicebytetostringtmp
		racereadrangepc(unsafe.Pointer(&b[0]),
			len(b),
			getcallerpc(unsafe.Pointer(&b)),
			**(**uintptr)(unsafe.Pointer(&fn)))
	}
	return *(*string)(unsafe.Pointer(&b))
}

func stringtoslicebyte(s string) []byte {
	b := rawbyteslice(len(s))
	copy(b, s)
	return b
}

func stringtoslicerune(s string) []rune {
	// two passes.
	// unlike slicerunetostring, no race because strings are immutable.
	n := 0
	t := s
	for len(s) > 0 {
		_, k := charntorune(s)
		s = s[k:]
		n++
	}
	a := rawruneslice(n)
	n = 0
	for len(t) > 0 {
		r, k := charntorune(t)
		t = t[k:]
		a[n] = r
		n++
	}
	return a
}

func slicerunetostring(a []rune) string {
	if raceenabled && len(a) > 0 {
		fn := slicerunetostring
		racereadrangepc(unsafe.Pointer(&a[0]),
			len(a)*int(unsafe.Sizeof(a[0])),
			getcallerpc(unsafe.Pointer(&a)),
			**(**uintptr)(unsafe.Pointer(&fn)))
	}
	var dum [4]byte
	size1 := 0
	for _, r := range a {
		size1 += runetochar(dum[:], r)
	}
	s, b := rawstring(size1 + 3)
	size2 := 0
	for _, r := range a {
		// check for race
		if size2 >= size1 {
			break
		}
		size2 += runetochar(b[size2:], r)
	}
	return s[:size2]
}

type stringStruct struct {
	str unsafe.Pointer
	len int
}

func cstringToGo(str unsafe.Pointer) (s string) {
	i := 0
	for ; ; i++ {
		if *(*byte)(unsafe.Pointer(uintptr(str) + uintptr(i))) == 0 {
			break
		}
	}
	t := (*stringStruct)(unsafe.Pointer(&s))
	t.str = unsafe.Pointer(str)
	t.len = i
	return
}

func intstring(v int64) string {
	s, b := rawstring(4)
	n := runetochar(b, rune(v))
	return s[:n]
}

// stringiter returns the index of the next
// rune after the rune that starts at s[k].
func stringiter(s string, k int) int {
	if k >= len(s) {
		// 0 is end of iteration
		return 0
	}

	c := s[k]
	if c < runeself {
		return k + 1
	}

	// multi-char rune
	_, n := charntorune(s[k:])
	return k + n
}

// stringiter2 returns the rune that starts at s[k]
// and the index where the next rune starts.
func stringiter2(s string, k int) (int, rune) {
	if k >= len(s) {
		// 0 is end of iteration
		return 0, 0
	}

	c := s[k]
	if c < runeself {
		return k + 1, rune(c)
	}

	// multi-char rune
	r, n := charntorune(s[k:])
	return k + n, r
}

// rawstring allocates storage for a new string. The returned
// string and byte slice both refer to the same storage.
// The storage is not zeroed. Callers should use
// b to set the string contents and then drop b.
func rawstring(size int) (s string, b []byte) {
	p := gomallocgc(uintptr(size), nil, flagNoScan|flagNoZero)

	(*stringStruct)(unsafe.Pointer(&s)).str = p
	(*stringStruct)(unsafe.Pointer(&s)).len = size

	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
	(*slice)(unsafe.Pointer(&b)).len = uint(size)
	(*slice)(unsafe.Pointer(&b)).cap = uint(size)

	for {
		ms := maxstring
		if uintptr(size) <= uintptr(ms) || casuintptr((*uintptr)(unsafe.Pointer(&maxstring)), uintptr(ms), uintptr(size)) {
			return
		}
	}
}

// rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
func rawbyteslice(size int) (b []byte) {
	cap := goroundupsize(uintptr(size))
	p := gomallocgc(cap, nil, flagNoScan|flagNoZero)
	if cap != uintptr(size) {
		memclr(add(p, uintptr(size)), cap-uintptr(size))
	}

	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
	(*slice)(unsafe.Pointer(&b)).len = uint(size)
	(*slice)(unsafe.Pointer(&b)).cap = uint(cap)
	return
}

// rawruneslice allocates a new rune slice. The rune slice is not zeroed.
func rawruneslice(size int) (b []rune) {
	if uintptr(size) > maxMem/4 {
		gothrow("out of memory")
	}
	mem := goroundupsize(uintptr(size) * 4)
	p := gomallocgc(mem, nil, flagNoScan|flagNoZero)
	if mem != uintptr(size)*4 {
		memclr(add(p, uintptr(size)*4), mem-uintptr(size)*4)
	}

	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
	(*slice)(unsafe.Pointer(&b)).len = uint(size)
	(*slice)(unsafe.Pointer(&b)).cap = uint(mem / 4)
	return
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package time_test

import (
	"testing"
	. "time"
)

func TestTicker(t *testing.T) {
	const Count = 10
	Delta := 100 * Millisecond
	if testing.Short() {
		Delta = 20 * Millisecond
	}
	ticker := NewTicker(Delta)
	t0 := Now()
	for i := 0; i < Count; i++ {
		<-ticker.C
	}
	ticker.Stop()
	t1 := Now()
	dt := t1.Sub(t0)
	target := Delta * Count
	slop := target * 2 / 10
	if dt < target-slop || dt > target+slop {
		t.Fatalf("%d %s ticks took %s, expected [%s,%s]", Count, Delta, dt, target-slop, target+slop)
	}
	// Now test that the ticker stopped
	Sleep(2 * Delta)
	select {
	case <-ticker.C:
		t.Fatal("Ticker did not shut down")
	default:
		// ok
	}
}

// Test that a bug tearing down a ticker has been fixed.  This routine should not deadlock.
func TestTeardown(t *testing.T) {
	Delta := 100 * Millisecond
	if testing.Short() {
		Delta = 20 * Millisecond
	}
	for i := 0; i < 3; i++ {
		ticker := NewTicker(Delta)
		<-ticker.C
		ticker.Stop()
	}
}

func BenchmarkTicker(b *testing.B) {
	ticker := NewTicker(1)
	b.ResetTimer()
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		<-ticker.C
	}
	b.StopTimer()
	ticker.Stop()
}
<commit_msg>time: run full TestTicker test even during short tests<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package time_test

import (
	"testing"
	. "time"
)

func TestTicker(t *testing.T) {
	const Count = 10
	Delta := 100 * Millisecond
	ticker := NewTicker(Delta)
	t0 := Now()
	for i := 0; i < Count; i++ {
		<-ticker.C
	}
	ticker.Stop()
	t1 := Now()
	dt := t1.Sub(t0)
	target := Delta * Count
	slop := target * 2 / 10
	if dt < target-slop || dt > target+slop {
		t.Fatalf("%d %s ticks took %s, expected [%s,%s]", Count, Delta, dt, target-slop, target+slop)
	}
	// Now test that the ticker stopped
	Sleep(2 * Delta)
	select {
	case <-ticker.C:
		t.Fatal("Ticker did not shut down")
	default:
		// ok
	}
}

// Test that a bug tearing down a ticker has been fixed.  This routine should not deadlock.
func TestTeardown(t *testing.T) {
	Delta := 100 * Millisecond
	if testing.Short() {
		Delta = 20 * Millisecond
	}
	for i := 0; i < 3; i++ {
		ticker := NewTicker(Delta)
		<-ticker.C
		ticker.Stop()
	}
}

func BenchmarkTicker(b *testing.B) {
	ticker := NewTicker(1)
	b.ResetTimer()
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		<-ticker.C
	}
	b.StopTimer()
	ticker.Stop()
}
<|endoftext|>


<commit_before>package consultant_test

import (
	"fmt"
	"strconv"
	"sync"
	"testing"
	"time"
	"net/http"

	"github.com/hashicorp/consul/api"
	"github.com/hashicorp/consul/testutil"
	"github.com/hashicorp/consul/watch"
	"github.com/myENA/consultant"
	"github.com/stretchr/testify/require"
	"github.com/stretchr/testify/suite"
)

const (
	// Test prefix monitoring
	prefix = "test/"

	key1   = "key1"
	val1   = "value 1"
	val1b  = "value 1 after change"

	key2   = "key2"
	val2   = 2
	val2b  = 42

	// Service monitoring
	serviceName = "myservice"
	serviceTag1 = "tag1"
	serviceTag2 = "tag2"
	servicePort = 3000
	servicePath = "/check"

)

func ExampleConfigurator() {
	// minimal implementation
	c := &config{}
	consul,err := consultant.NewDefaultClient()
	if err != nil {
		panic("no consul")
	}

	// initialize config from consul and set up watchers
	wp, err := consul.KVPrefixConfigurator(c, prefix)
	if err != nil {
		panic("trouble configurating")
	}

	// ensure that reads from the config are thread safe
	cc := c.copy() // work with a copy of the configuration
	fmt.Printf("var1=%s", cc.var1)

	wp.Stop()
}

func TestConfigurator(t *testing.T) {
	suite.Run(t, &ConfiguratorTestSuite{})
}

// Implement the Configurator interface
type config struct {
	var1 string
	var2 int
	service []*api.ServiceEntry
	t    *testing.T
	sync.RWMutex
}

// Update() handles both the initial settings and updates when anything under the prefix changes
func (c *config) Update(_ uint64, data interface{}) {

	var err error

	// Code accessing "config" should grab a read lock or use sync/atomic to achieve thread safety
	c.Lock()
	defer c.Unlock()

	// We may consider using Update() for services and other updates
	switch data.(type) {

	case api.KVPairs:
		kvps := data.(api.KVPairs)
		c.t.Logf("Update received %d KV pairs", len(kvps))
		for _, kvp := range kvps {
			c.t.Logf("key=%s, val=%s", kvp.Key, kvp.Value)
			switch kvp.Key {
			case prefix + key1:
				c.var1 = string(kvp.Value)
				c.t.Logf("c.var1=%s", c.var1)
			case prefix + key2:
				c.var2, err = strconv.Atoi(string(kvp.Value))
				if err != nil {
					c.t.Logf("key %s is not an int", key2)
				}
			}
		}

	case []*api.ServiceEntry:
		c.service = data.([]*api.ServiceEntry)
		c.t.Logf("Update: I have %d services in my list", len(c.service))

	default:
		c.t.Log("Typecast failed")
		c.t.Fail()
	}
}

func (c *config) copy() *config {
	c.RLock()
	defer c.RUnlock()
	cc := *c
	return &cc
}

// 1. Test that the consul KV config is transferred correctly
// 2. Verify that an update is reflected in the config object
func (cs *ConfiguratorTestSuite) TestKVInit() {
	var err error

	cs.buildKVTestData()

	config := &config{
		t: cs.T(),
	}

	var wp *watch.Plan
	wp, err = cs.client.KVPrefixConfigurator(config, prefix)

	require.Nil(cs.T(), err, "InitConfigurator(..., %s) failed: %s", prefix, err)

	// Check that config has what we expect
	require.Equal(cs.T(), val1, config.var1, "the initialized val1 is not what I expected")
	require.Equal(cs.T(), val2, config.var2, "the initialized val2 is not what I expected")

	kv1 := &api.KVPair{Key: prefix + key1, Value: []byte(val1b)}
	_, err = cs.client.KV().Put(kv1, nil)
	require.Nil(cs.T(), err, "Trouble changing the value of %s", key1)
	time.Sleep(time.Second)
	require.Equal(cs.T(), val1b, config.var1, "var1 is not what i expected after updating in consul")

	kv2 := &api.KVPair{Key: prefix + key2, Value: []byte(fmt.Sprintf("%d", val2b))}
	_, err = cs.client.KV().Put(kv2, nil)
	require.Nil(cs.T(), err, "Trouble changing the value of %s", key2)
	time.Sleep(time.Second)
	require.Equal(cs.T(), val2b, config.var2, "var2 is not what i expected after updating in consul")

	time.Sleep(time.Second)

	// report what is actually in the kv prefix now:
	kvps, _, err := cs.client.KV().List(prefix, nil)
	config.Update(0, kvps)
	cs.T().Logf("config after manual update: %+v", config)

	wp.Stop()
}

func (cs *ConfiguratorTestSuite) TestServiceInit() {

	// Fire up a simple health check
	portString := fmt.Sprintf(":%d",servicePort)
	http.HandleFunc(servicePath, func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "Hello")
	})
	go http.ListenAndServe(portString, nil)

	// Register a service
	sr := &consultant.SimpleServiceRegistration{
		Name: serviceName,
		Port: servicePort,
		Address: "localhost",
		RandomID: true,
		Tags: []string{serviceTag1,serviceTag2},
		CheckPath: servicePath,
		Interval: "5s",
	}
	serviceID, err := cs.client.SimpleServiceRegister(sr)
	require.Nil(cs.T(), err, "Trouble registering the test service")
	cs.T().Logf("serviceID=%s",serviceID)

	config := &config{
		t: cs.T(),
	}

	wp, err := cs.client.ConfigureService(config, serviceName, serviceTag1, false,nil)
	require.Nil(cs.T(), err, "Unable to configure the service")

	cc := config.copy()
	require.Equal(cs.T(), 1, len(cc.service), "Expecting exactly one service here")

	se := cc.service[0]
	for _,check := range se.Checks {
		cs.T().Logf("check[%s]=%s",check.Name,check.Status)
	}

	time.Sleep(10*time.Second)

	// should be passing now
	cc = config.copy()
	require.Equal(cs.T(), 1, len(cc.service), "Expecting exactly one service here")

	se = cc.service[0]
	for _,check := range se.Checks {
		cs.T().Logf("check[%s]=%s",check.Name,check.Status)
	}

	wp.Stop()
}

func (cs *ConfiguratorTestSuite) buildKVTestData() {
	var err error

	kv1 := &api.KVPair{Key: prefix + key1, Value: []byte(val1)}
	_, err = cs.client.KV().Put(kv1, nil)
	require.Nil(cs.T(), err, "Failed storing key1/val1: %s", err)

	kv2 := &api.KVPair{Key: prefix + key2, Value: []byte(fmt.Sprintf("%d", val2))}
	_, err = cs.client.KV().Put(kv2, nil)
	require.Nil(cs.T(), err, "Failed storing key2/val2: %s", err)
}

type ConfiguratorTestSuite struct {
	suite.Suite

	// these values are cyclical, and should be re-defined per test method
	server *testutil.TestServer
	client *consultant.Client
}

// SetupTest is called before each method is run.
func (cs *ConfiguratorTestSuite) SetupTest() {
	cs.server, cs.client = makeServerAndClient(cs.T(), nil)
}

// TearDownTest is called after each method has been run.
func (cs *ConfiguratorTestSuite) TearDownTest() {
	if nil != cs.client {
		cs.client = nil
	}
	if nil != cs.server {
		// TODO: Stop seems to return an error when the process is killed...
		cs.server.Stop()
		cs.server = nil
	}
}

func (cs *ConfiguratorTestSuite) TearDownSuite() {
	cs.TearDownTest()
}
<commit_msg>in working condition<commit_after>package consultant_test

// Test this aspect of consultant with `go test -run Configurator -v`

import (
	"fmt"
	"strconv"
	"sync"
	"testing"
	"time"
	"net/http"

	"github.com/hashicorp/consul/api"
	"github.com/hashicorp/consul/testutil"
	"github.com/hashicorp/consul/watch"
	"github.com/myENA/consultant"
	"github.com/stretchr/testify/require"
	"github.com/stretchr/testify/suite"
)

const (
	// Test prefix monitoring
	prefix = "test/"

	key1   = "key1"
	val1   = "value 1"
	val1b  = "value 1 after change"

	key2   = "key2"
	val2   = 2
	val2b  = 42

	// Service monitoring
	serviceName = "myservice"
	serviceTag1 = "tag1"
	serviceTag2 = "tag2"
	servicePort = 3000
	servicePath = "/check"

)

func ExampleConfigurator() {
	// minimal implementation
	c := &config{}
	consul,err := consultant.NewDefaultClient()
	if err != nil {
		panic("no consul")
	}

	// initialize config from consul and set up watchers
	wp, err := consul.KVPrefixConfigurator(c, prefix)
	if err != nil {
		panic("trouble configurating")
	}

	// ensure that reads from the config are thread safe
	cc := c.copy() // work with a copy of the configuration
	fmt.Printf("var1=%s", cc.var1)

	wp.Stop()
}

func TestConfigurator(t *testing.T) {
	suite.Run(t, &ConfiguratorTestSuite{})
}

// Implement the Configurator interface
type config struct {
	var1 string
	var2 int
	service []*api.ServiceEntry
	t    *testing.T
	sync.RWMutex
}

// Update() handles both the initial settings and updates when anything under the prefix changes
// or when there are changes to any registered services.
func (c *config) Update(_ uint64, data interface{}) {

	var err error

	// Code accessing "config" should grab a read lock or use sync/atomic to achieve thread safety
	c.Lock()
	defer c.Unlock()

	// We may consider using Update() for services and other updates
	switch data.(type) {

	case api.KVPairs:
		kvps := data.(api.KVPairs)
		c.t.Logf("Update received %d KV pairs", len(kvps))
		for _, kvp := range kvps {
			c.t.Logf("key=%s, val=%s", kvp.Key, kvp.Value)
			switch kvp.Key {
			case prefix + key1:
				c.var1 = string(kvp.Value)
				c.t.Logf("c.var1=%s", c.var1)
			case prefix + key2:
				c.var2, err = strconv.Atoi(string(kvp.Value))
				if err != nil {
					c.t.Logf("key %s is not an int", key2)
				}
			}
		}

	case []*api.ServiceEntry:
		c.service = data.([]*api.ServiceEntry)
		c.t.Logf("Update: I have %d services in my list", len(c.service))

	default:
		c.t.Log("Typecast failed")
		c.t.Fail()
	}
}

func (c *config) copy() *config {
	c.RLock()
	defer c.RUnlock()
	cc := *c
	return &cc
}

// 1. Test that the consul KV config is transferred correctly
// 2. Verify that an update is reflected in the config object
func (cs *ConfiguratorTestSuite) TestKVInit() {
	var err error

	cs.buildKVTestData()

	config := &config{
		t: cs.T(),
	}

	var wp *watch.Plan
	wp, err = cs.client.KVPrefixConfigurator(config, prefix)

	require.Nil(cs.T(), err, "InitConfigurator(..., %s) failed: %s", prefix, err)

	// Check that config has what we expect
	require.Equal(cs.T(), val1, config.var1, "the initialized val1 is not what I expected")
	require.Equal(cs.T(), val2, config.var2, "the initialized val2 is not what I expected")

	kv1 := &api.KVPair{Key: prefix + key1, Value: []byte(val1b)}
	_, err = cs.client.KV().Put(kv1, nil)
	require.Nil(cs.T(), err, "Trouble changing the value of %s", key1)
	time.Sleep(time.Second)
	require.Equal(cs.T(), val1b, config.var1, "var1 is not what i expected after updating in consul")

	kv2 := &api.KVPair{Key: prefix + key2, Value: []byte(fmt.Sprintf("%d", val2b))}
	_, err = cs.client.KV().Put(kv2, nil)
	require.Nil(cs.T(), err, "Trouble changing the value of %s", key2)
	time.Sleep(time.Second)
	require.Equal(cs.T(), val2b, config.var2, "var2 is not what i expected after updating in consul")

	time.Sleep(time.Second)

	// report what is actually in the kv prefix now:
	kvps, _, err := cs.client.KV().List(prefix, nil)
	config.Update(0, kvps)
	cs.T().Logf("config after manual update: %+v", config)

	wp.Stop()
}

// 1. Start a web service that provides a health check
// 2. Register the service with consul
// 3. Verify that we can see the service before it starts passing it's health check
// 4. Observe the service as it starts passing in consul.
func (cs *ConfiguratorTestSuite) TestServiceInit() {

	cs.buildTestService()

	config := &config{
		t: cs.T(),
	}

	// Initialize config and start a service watcher
	wp, err := cs.client.ServiceConfigurator(config, serviceName, serviceTag1, false,nil)
	require.Nil(cs.T(), err, "Unable to configure the service")

	cc := config.copy()
	require.Equal(cs.T(), 1, len(cc.service), "Expecting exactly one service here")

	// List the health checks before the service can be expected to pass
	se := cc.service[0]
	for _,check := range se.Checks {
		cs.T().Logf("check[%s]=%s",check.Name,check.Status)
	}

	// Wait for consul to do a health check
	time.Sleep(10*time.Second)

	// The service should be passing now
	cc = config.copy()
	require.Equal(cs.T(), 1, len(cc.service), "Expecting exactly one service here")

	se = cc.service[0]
	for _,check := range se.Checks {
		cs.T().Logf("check[%s]=%s",check.Name,check.Status)
	}

	// Clean up
	wp.Stop()
}

// buildKVTestData populates a kv path with some data
func (cs *ConfiguratorTestSuite) buildKVTestData() {
	var err error

	kv1 := &api.KVPair{Key: prefix + key1, Value: []byte(val1)}
	_, err = cs.client.KV().Put(kv1, nil)
	require.Nil(cs.T(), err, "Failed storing key1/val1: %s", err)

	kv2 := &api.KVPair{Key: prefix + key2, Value: []byte(fmt.Sprintf("%d", val2))}
	_, err = cs.client.KV().Put(kv2, nil)
	require.Nil(cs.T(), err, "Failed storing key2/val2: %s", err)
}

// create a consul service to test with
func (cs *ConfiguratorTestSuite) buildTestService() {
	// Fire up a simple health check
	portString := fmt.Sprintf(":%d",servicePort)
	http.HandleFunc(servicePath, func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "Hello")
	})
	go http.ListenAndServe(portString, nil)

	// Register a service
	sr := &consultant.SimpleServiceRegistration{
		Name: serviceName,
		Port: servicePort,
		Address: "localhost",
		RandomID: true,
		Tags: []string{serviceTag1,serviceTag2},
		CheckPath: servicePath,
		Interval: "5s",
	}
	serviceID, err := cs.client.SimpleServiceRegister(sr)
	require.Nil(cs.T(), err, "Trouble registering the test service")
	cs.T().Logf("serviceID=%s",serviceID)
}

type ConfiguratorTestSuite struct {
	suite.Suite

	// these values are cyclical, and should be re-defined per test method
	server *testutil.TestServer
	client *consultant.Client
}

// SetupTest is called before each method is run.
func (cs *ConfiguratorTestSuite) SetupTest() {
	cs.server, cs.client = makeServerAndClient(cs.T(), nil)
}

// TearDownTest is called after each method has been run.
func (cs *ConfiguratorTestSuite) TearDownTest() {
	if nil != cs.client {
		cs.client = nil
	}
	if nil != cs.server {
		// TODO: Stop seems to return an error when the process is killed...
		cs.server.Stop()
		cs.server = nil
	}
}

func (cs *ConfiguratorTestSuite) TearDownSuite() {
	cs.TearDownTest()
}
<|endoftext|>


<commit_before><commit_msg>:penguin: DRY'ing stuff up<commit_after><|endoftext|>


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


<commit_before><commit_msg>fix test suite import<commit_after><|endoftext|>


<commit_before>package connectors

import (
	"github.com/SlyMarbo/rss"
	"github.com/kennygrant/sanitize"
	"github.com/mmcquillan/bambooapi"
	"github.com/projectjane/jane/models"
	"html"
	"log"
	"strconv"
	"strings"
	"time"
)

type Bamboo struct {
}

func (x Bamboo) Listen(commandMsgs chan<- models.Message, connector models.Connector) {
	defer Recovery(connector)
	now := time.Now()
	buildMarker := ""
	deployMarker := strconv.FormatInt(now.Unix(), 10) + "000"
	for {
		buildMarker = listenBuilds(buildMarker, commandMsgs, connector)
		deployMarker = listenDeploys(deployMarker, commandMsgs, connector)
		time.Sleep(120 * time.Second)
	}
}

func (x Bamboo) Command(message models.Message, publishMsgs chan<- models.Message, connector models.Connector) {
	if strings.HasPrefix(message.In.Text, "bamboo status") {
		commandDeployStatus(message, publishMsgs, connector)
		commandBuildStatus(message, publishMsgs, connector)
	}
	if strings.HasPrefix(message.In.Text, "bamboo build") {
		commandBuild(message, publishMsgs, connector)
	}
}

func (x Bamboo) Publish(connector models.Connector, message models.Message, target string) {
	return
}

func (x Bamboo) Help(connector models.Connector) (help string) {
	help += "bamboo build <build key>\n"
	help += "bamboo status <environment or build key>\n"
	return help
}

func listenDeploys(lastMarker string, commandMsgs chan<- models.Message, connector models.Connector) (nextMarker string) {
	now := time.Now()
	nextMarker = strconv.FormatInt(now.Unix(), 10) + "000"
	if connector.Debug {
		log.Print("Calling deploy results with last marker: " + lastMarker)
	}
	d := bambooapi.DeployResults(connector.Server, connector.Login, connector.Pass)
	for _, de := range d {
		for _, e := range de.Environmentstatuses {
			buildTime := strconv.FormatInt(e.Deploymentresult.Finisheddate, 10)
			if e.Deploymentresult.ID > 0 && buildTime > lastMarker {
				var m models.Message
				m.Routes = connector.Routes
				m.In.Process = false
				m.Out.Text = "Bamboo Deploy " + e.Deploymentresult.Deploymentstate
				m.Out.Detail = "Deployed " + e.Deploymentresult.Deploymentversion.Name + " to " + e.Environment.Name
				m.Out.Link = "https://" + connector.Server + "/builds/deploy/viewDeploymentResult.action?deploymentResultId=" + strconv.Itoa(e.Deploymentresult.ID)
				if e.Deploymentresult.Deploymentstate == "SUCCESS" {
					m.Out.Status = "SUCCESS"
				} else {
					m.Out.Status = "FAIL"
				}
				commandMsgs <- m
			}
		}
	}
	return nextMarker
}

func commandBuild(message models.Message, publishMsgs chan<- models.Message, connector models.Connector) {
	tokens := strings.Split(message.In.Text, " ")
	queue := bambooapi.Queue(connector.Server, connector.Login, connector.Pass, tokens[2])
	log.Printf("%+v", queue)
	if queue.StatusCode > 0 {
		message.Out.Text = "Problem queueing build: " + tokens[2]
	} else {
		message.Out.Text = "Queued build for " + queue.Plankey
		message.Out.Detail = "Build #" + strconv.Itoa(queue.Buildnumber)
		message.Out.Link = queue.Link.Href
	}
	publishMsgs <- message
}

func commandDeployStatus(message models.Message, publishMsgs chan<- models.Message, connector models.Connector) {
	tokens := strings.Split(message.In.Text, " ")
	d := bambooapi.DeployResults(connector.Server, connector.Login, connector.Pass)
	for _, de := range d {
		for _, e := range de.Environmentstatuses {
			detail := "Deployed " + e.Deploymentresult.Deploymentversion.Name + " to " + e.Environment.Name
			if strings.Contains(strings.ToLower(detail), strings.ToLower(tokens[2])) {
				message.Out.Text = "Bamboo Deploy " + e.Deploymentresult.Deploymentstate
				message.Out.Detail = detail
				message.Out.Link = "https://" + connector.Server + "/builds/deploy/viewDeploymentResult.action?deploymentResultId=" + strconv.Itoa(e.Deploymentresult.ID)
				if e.Deploymentresult.Deploymentstate == "SUCCESS" {
					message.Out.Status = "SUCCESS"
				} else {
					message.Out.Status = "FAIL"
				}
				publishMsgs <- message
			}
		}
	}
}

func commandBuildStatus(message models.Message, publishMsgs chan<- models.Message, connector models.Connector) {
	tokens := strings.Split(message.In.Text, " ")
	b := bambooapi.BuildResults(connector.Server, connector.Login, connector.Pass)
	for _, be := range b.Results.Result {
		if strings.Contains(strings.ToLower(be.Plan.Shortname), strings.ToLower(tokens[2])) {
			message.Out.Text = "Bamboo Build " + be.Plan.Shortname
			message.Out.Detail = be.Plan.Name + " #" + strconv.Itoa(be.Buildnumber)
			message.Out.Link = be.Link.Href
			if be.Buildstate == "Successful" {
				message.Out.Status = "SUCCESS"
			} else {
				message.Out.Status = "FAIL"
			}
			publishMsgs <- message
		}
	}
}

func listenBuilds(lastMarker string, commandMsgs chan<- models.Message, connector models.Connector) (nextMarker string) {
	var displayOnStart = 0
	url := "https://" + connector.Login + ":" + connector.Pass + "@"
	url += connector.Server + "/builds/plugins/servlet/streams?local=true"
	feed, err := rss.Fetch(url)
	if err != nil {
		log.Print(err)
		return
	}
	for i := len(feed.Items) - 1; i >= 0; i-- {
		if connector.Debug {
			log.Print("Bamboo " + connector.ID + " item #" + strconv.Itoa(i) + " marker " + feed.Items[i].Date.String())
		}
		if lastMarker == "" {
			lastMarker = feed.Items[displayOnStart].Date.String()
		}
		item := feed.Items[i]
		if item.Date.String() > lastMarker {
			status := "NONE"
			if strings.Contains(item.Title, "successful") {
				status = "SUCCESS"
			}
			if strings.Contains(item.Title, "fail") {
				status = "FAIL"
			}
			var m models.Message
			m.Routes = connector.Routes
			m.In.Process = false
			m.Out.Text = "Bamboo Build " + html.UnescapeString(sanitize.HTML(item.Title))
			m.Out.Detail = html.UnescapeString(sanitize.HTML(item.Content))
			m.Out.Link = item.Link
			m.Out.Status = status
			commandMsgs <- m
			if i == 0 {
				lastMarker = item.Date.String()
			}
		}
	}
	nextMarker = lastMarker
	return nextMarker
}
<commit_msg>fixing link for bamboo builds<commit_after>package connectors

import (
	"github.com/SlyMarbo/rss"
	"github.com/kennygrant/sanitize"
	"github.com/mmcquillan/bambooapi"
	"github.com/projectjane/jane/models"
	"html"
	"log"
	"strconv"
	"strings"
	"time"
)

type Bamboo struct {
}

func (x Bamboo) Listen(commandMsgs chan<- models.Message, connector models.Connector) {
	defer Recovery(connector)
	now := time.Now()
	buildMarker := ""
	deployMarker := strconv.FormatInt(now.Unix(), 10) + "000"
	for {
		buildMarker = listenBuilds(buildMarker, commandMsgs, connector)
		deployMarker = listenDeploys(deployMarker, commandMsgs, connector)
		time.Sleep(120 * time.Second)
	}
}

func (x Bamboo) Command(message models.Message, publishMsgs chan<- models.Message, connector models.Connector) {
	if strings.HasPrefix(message.In.Text, "bamboo status") {
		commandDeployStatus(message, publishMsgs, connector)
		commandBuildStatus(message, publishMsgs, connector)
	}
	if strings.HasPrefix(message.In.Text, "bamboo build") {
		commandBuild(message, publishMsgs, connector)
	}
}

func (x Bamboo) Publish(connector models.Connector, message models.Message, target string) {
	return
}

func (x Bamboo) Help(connector models.Connector) (help string) {
	help += "bamboo build <build key>\n"
	help += "bamboo status <environment or build key>\n"
	return help
}

func listenDeploys(lastMarker string, commandMsgs chan<- models.Message, connector models.Connector) (nextMarker string) {
	now := time.Now()
	nextMarker = strconv.FormatInt(now.Unix(), 10) + "000"
	if connector.Debug {
		log.Print("Calling deploy results with last marker: " + lastMarker)
	}
	d := bambooapi.DeployResults(connector.Server, connector.Login, connector.Pass)
	for _, de := range d {
		for _, e := range de.Environmentstatuses {
			buildTime := strconv.FormatInt(e.Deploymentresult.Finisheddate, 10)
			if e.Deploymentresult.ID > 0 && buildTime > lastMarker {
				var m models.Message
				m.Routes = connector.Routes
				m.In.Process = false
				m.Out.Text = "Bamboo Deploy " + e.Deploymentresult.Deploymentstate
				m.Out.Detail = "Deployed " + e.Deploymentresult.Deploymentversion.Name + " to " + e.Environment.Name
				m.Out.Link = "https://" + connector.Server + "/builds/deploy/viewDeploymentResult.action?deploymentResultId=" + strconv.Itoa(e.Deploymentresult.ID)
				if e.Deploymentresult.Deploymentstate == "SUCCESS" {
					m.Out.Status = "SUCCESS"
				} else {
					m.Out.Status = "FAIL"
				}
				commandMsgs <- m
			}
		}
	}
	return nextMarker
}

func commandBuild(message models.Message, publishMsgs chan<- models.Message, connector models.Connector) {
	tokens := strings.Split(message.In.Text, " ")
	queue := bambooapi.Queue(connector.Server, connector.Login, connector.Pass, tokens[2])
	log.Printf("%+v", queue)
	if queue.StatusCode > 0 {
		message.Out.Text = "Problem queueing build: " + tokens[2]
	} else {
		message.Out.Text = "Queued build for " + queue.Plankey
		message.Out.Detail = "Build #" + strconv.Itoa(queue.Buildnumber)
		message.Out.Link = "https://" + connector.Server + "/builds/browse/" + queue.Plankey + "-" + strconv.Itoa(queue.Buildnumber)
	}
	publishMsgs <- message
}

func commandDeployStatus(message models.Message, publishMsgs chan<- models.Message, connector models.Connector) {
	tokens := strings.Split(message.In.Text, " ")
	d := bambooapi.DeployResults(connector.Server, connector.Login, connector.Pass)
	for _, de := range d {
		for _, e := range de.Environmentstatuses {
			detail := "Deployed " + e.Deploymentresult.Deploymentversion.Name + " to " + e.Environment.Name
			if strings.Contains(strings.ToLower(detail), strings.ToLower(tokens[2])) {
				message.Out.Text = "Bamboo Deploy " + e.Deploymentresult.Deploymentstate
				message.Out.Detail = detail
				message.Out.Link = "https://" + connector.Server + "/builds/deploy/viewDeploymentResult.action?deploymentResultId=" + strconv.Itoa(e.Deploymentresult.ID)
				if e.Deploymentresult.Deploymentstate == "SUCCESS" {
					message.Out.Status = "SUCCESS"
				} else {
					message.Out.Status = "FAIL"
				}
				publishMsgs <- message
			}
		}
	}
}

func commandBuildStatus(message models.Message, publishMsgs chan<- models.Message, connector models.Connector) {
	tokens := strings.Split(message.In.Text, " ")
	b := bambooapi.BuildResults(connector.Server, connector.Login, connector.Pass)
	for _, be := range b.Results.Result {
		if strings.Contains(strings.ToLower(be.Plan.Shortname), strings.ToLower(tokens[2])) {
			message.Out.Text = "Bamboo Build " + be.Plan.Shortname
			message.Out.Detail = be.Plan.Name + " #" + strconv.Itoa(be.Buildnumber)
			message.Out.Link = be.Link.Href
			if be.Buildstate == "Successful" {
				message.Out.Status = "SUCCESS"
			} else {
				message.Out.Status = "FAIL"
			}
			publishMsgs <- message
		}
	}
}

func listenBuilds(lastMarker string, commandMsgs chan<- models.Message, connector models.Connector) (nextMarker string) {
	var displayOnStart = 0
	url := "https://" + connector.Login + ":" + connector.Pass + "@"
	url += connector.Server + "/builds/plugins/servlet/streams?local=true"
	feed, err := rss.Fetch(url)
	if err != nil {
		log.Print(err)
		return
	}
	for i := len(feed.Items) - 1; i >= 0; i-- {
		if connector.Debug {
			log.Print("Bamboo " + connector.ID + " item #" + strconv.Itoa(i) + " marker " + feed.Items[i].Date.String())
		}
		if lastMarker == "" {
			lastMarker = feed.Items[displayOnStart].Date.String()
		}
		item := feed.Items[i]
		if item.Date.String() > lastMarker {
			status := "NONE"
			if strings.Contains(item.Title, "successful") {
				status = "SUCCESS"
			}
			if strings.Contains(item.Title, "fail") {
				status = "FAIL"
			}
			var m models.Message
			m.Routes = connector.Routes
			m.In.Process = false
			m.Out.Text = "Bamboo Build " + html.UnescapeString(sanitize.HTML(item.Title))
			m.Out.Detail = html.UnescapeString(sanitize.HTML(item.Content))
			m.Out.Link = item.Link
			m.Out.Status = status
			commandMsgs <- m
			if i == 0 {
				lastMarker = item.Date.String()
			}
		}
	}
	nextMarker = lastMarker
	return nextMarker
}
<|endoftext|>


<commit_before><commit_msg>wdte: Remove crash dump from test file.<commit_after><|endoftext|>