<commit_before>package config_test

import (
	"testing"

	. "github.com/andygrunwald/perseus/config"
	"github.com/andygrunwald/perseus/dependency"
)

func TestNewMedusa(t *testing.T) {
	v := &EmptyUnitTestProvider{}

	m, err := NewMedusa(v)
	if m == nil {
		t.Error("Medusa configuration object is nil.")
	}
	if err != nil {
		t.Errorf("NewMedusa(provider) throws error: %s", err)
	}
}

func TestNewMedusa_WithoutConfiguration(t *testing.T) {
	m, err := NewMedusa(nil)
	if m != nil {
		t.Errorf("Expected medusa configuration to be nil. Got: %+v", m)
	}
	if err == nil {
		t.Error("No error thrown by creating NewMedusa(nil).")
	}
}

func TestMedusa_GetRepositoryURLOfPackage_FaultyRepositories(t *testing.T) {
	tests := []struct {
		name     string
		provider Provider
	}{
		// No "repositories" configured at all
		{"symfony/console", &EmptyUnitTestProvider{}},
		// "repositories" key is there, but empty
		{"key/exists", &EmptyWithKeysUnitTestProvider{}},
		// Repositories configured, but not this one
		{"twig/twig", &MedusaUnitTestProvider{}},
		// Repositories configured, plus this one, but doesn't have an url key
		{"no/url", &MedusaUnitTestProvider{}},
		// Repositories configured, plus this one, but has an empty url key
		{"empty/url", &MedusaUnitTestProvider{}},
		// Repositories configured, plus this one, but has an invalid url key
		{"invalid/url", &MedusaUnitTestProvider{}},
	}

	for _, tt := range tests {
		m, err := NewMedusa(tt.provider)
		if err != nil {
			t.Errorf("NewMedusa(Provider) throws error: %s", err)
		}

		p := &dependency.Package{Name: tt.name}
		u, err := m.GetRepositoryURLOfPackage(p)
		if u != nil {
			t.Errorf("Package '%s': Expected url to be nil. Got: %+v", tt.name, u)
		}
		if err == nil {
			t.Errorf("Package '%s': No error thrown.", tt.name)
		}
	}
}

func TestMedusa_GetRepositoryURLOfPackage_CorrectRepositories(t *testing.T) {
	tests := []struct {
		name     string
		provider Provider
	}{
		// Everything is fine with a git ssh url (github)
		{"symfony/console", &MedusaUnitTestProvider{}},
		// Everything is fine with a https url (github)
		{"symfony/polyfill", &MedusaUnitTestProvider{}},
	}

	for _, tt := range tests {
		m, err := NewMedusa(tt.provider)
		if err != nil {
			t.Errorf("NewMedusa(Provider) throws error: %s", err)
		}

		p := &dependency.Package{Name: tt.name}
		u, err := m.GetRepositoryURLOfPackage(p)
		if u == nil {
			t.Errorf("Package '%s': No url returned. Expected one.", tt.name)

		}
		if err != nil {
			t.Errorf("Package '%s': Expected error to be nil. Got: %+v", tt.name, err)
		}
	}
}

func TestMedusa_GetNamesOfRepositories_FaultyRepositories(t *testing.T) {
	tests := []struct {
		name     string
		provider Provider
		num      int
	}{
		// No "repositories" configured at all
		{"symfony/console", &EmptyUnitTestProvider{}, 0},
		// "repositories" key is there, but empty
		{"key/exists", &EmptyWithKeysUnitTestProvider{}, 0},
		/*
			// Repositories configured, but not this one
			{"twig/twig", &MedusaUnitTestProvider{}, 0},
			// Repositories configured, plus this one, but doesn't have an url key
			{"no/url", &MedusaUnitTestProvider{}, 0},
			// Repositories configured, plus this one, but has an empty url key
			{"empty/url", &MedusaUnitTestProvider{}, 0},
			// Repositories configured, plus this one, but has an invalid url key
			{"invalid/url", &MedusaUnitTestProvider{}, 0},
		*/
	}

	for _, tt := range tests {
		m, err := NewMedusa(tt.provider)
		if err != nil {
			t.Errorf("NewMedusa(Provider) throws error: %s", err)
		}

		l, err := m.GetNamesOfRepositories()
		if l != nil {
			t.Errorf("Package '%s': Expected url to be nil. Got: %+v", tt.name, l)
		}
		if err == nil {
			t.Errorf("Package '%s': No error thrown.", tt.name)
		}
	}
}
<commit_msg>Added a few more unit tests for Medusa<commit_after>package config_test

import (
	"testing"

	. "github.com/andygrunwald/perseus/config"
	"github.com/andygrunwald/perseus/dependency"
)

func TestNewMedusa(t *testing.T) {
	v := &EmptyUnitTestProvider{}

	m, err := NewMedusa(v)
	if m == nil {
		t.Error("Medusa configuration object is nil.")
	}
	if err != nil {
		t.Errorf("NewMedusa(provider) throws error: %s", err)
	}
}

func TestNewMedusa_WithoutConfiguration(t *testing.T) {
	m, err := NewMedusa(nil)
	if m != nil {
		t.Errorf("Expected medusa configuration to be nil. Got: %+v", m)
	}
	if err == nil {
		t.Error("No error thrown by creating NewMedusa(nil).")
	}
}

func TestMedusa_GetRepositoryURLOfPackage_FaultyRepositories(t *testing.T) {
	tests := []struct {
		name     string
		provider Provider
	}{
		// No "repositories" configured at all
		{"symfony/console", &EmptyUnitTestProvider{}},
		// "repositories" key is there, but empty
		{"key/exists", &EmptyWithKeysUnitTestProvider{}},
		// Repositories configured, but not this one
		{"twig/twig", &MedusaUnitTestProvider{}},
		// Repositories configured, plus this one, but doesn't have an url key
		{"no/url", &MedusaUnitTestProvider{}},
		// Repositories configured, plus this one, but has an empty url key
		{"empty/url", &MedusaUnitTestProvider{}},
		// Repositories configured, plus this one, but has an invalid url key
		{"invalid/url", &MedusaUnitTestProvider{}},
	}

	for _, tt := range tests {
		m, err := NewMedusa(tt.provider)
		if err != nil {
			t.Errorf("NewMedusa(Provider) throws error: %s", err)
		}

		p := &dependency.Package{Name: tt.name}
		u, err := m.GetRepositoryURLOfPackage(p)
		if u != nil {
			t.Errorf("Package '%s': Expected url to be nil. Got: %+v", tt.name, u)
		}
		if err == nil {
			t.Errorf("Package '%s': No error thrown.", tt.name)
		}
	}
}

func TestMedusa_GetRepositoryURLOfPackage_CorrectRepositories(t *testing.T) {
	tests := []struct {
		name     string
		provider Provider
	}{
		// Everything is fine with a git ssh url (github)
		{"symfony/console", &MedusaUnitTestProvider{}},
		// Everything is fine with a https url (github)
		{"symfony/polyfill", &MedusaUnitTestProvider{}},
	}

	for _, tt := range tests {
		m, err := NewMedusa(tt.provider)
		if err != nil {
			t.Errorf("NewMedusa(Provider) throws error: %s", err)
		}

		p := &dependency.Package{Name: tt.name}
		u, err := m.GetRepositoryURLOfPackage(p)
		if u == nil {
			t.Errorf("Package '%s': No url returned. Expected one.", tt.name)

		}
		if err != nil {
			t.Errorf("Package '%s': Expected error to be nil. Got: %+v", tt.name, err)
		}
	}
}

func TestMedusa_GetNamesOfRepositories(t *testing.T) {
	provider := &MedusaUnitTestProvider{}
	numOfPackages := 2

	m, err := NewMedusa(provider)
	if err != nil {
		t.Errorf("NewMedusa(Provider) throws error: %s", err)
	}

	l, err := m.GetNamesOfRepositories()
	if err != nil {
		t.Errorf("Expected no error for provider %T. Got %s", provider, err)
	}
	if n := len(l); n != numOfPackages {
		t.Errorf("Expected a different number of packages. Got %d, expected %d for provider %T", n, numOfPackages, provider)
	}
}

func TestMedusa_GetNamesOfRepositories_EmptyRepositoryList(t *testing.T) {
	tests := []struct {
		provider Provider
		num      int
	}{
		// No "repositories" configured at all
		{&EmptyUnitTestProvider{}, 0},
		// "repositories" key is there, but empty
		{&EmptyWithKeysUnitTestProvider{}, 0},
	}

	for _, tt := range tests {
		m, err := NewMedusa(tt.provider)
		if err != nil {
			t.Errorf("NewMedusa(Provider) throws error: %s", err)
		}

		l, err := m.GetNamesOfRepositories()
		if n := len(l); n != tt.num {
			t.Errorf("Expected a different number of packages. Got %d, expected %d for provider %T", n, tt.num, tt.provider)
		}
		if err == nil {
			t.Errorf("No error thrown. Expected an error for provider %T", tt.provider)
		}
	}
}

func TestMedusa_GetRequire(t *testing.T) {
	tests := []struct {
		provider Provider
		num      int
	}{
		// Empty "require" configured
		{&EmptyUnitTestProvider{}, 0},
		// 3 "require"s configured
		{&MedusaUnitTestProvider{}, 3},
	}

	for _, tt := range tests {
		m, err := NewMedusa(tt.provider)
		if err != nil {
			t.Errorf("NewMedusa(Provider) throws error: %s", err)
		}

		l := m.GetRequire()
		if n := len(l); n != tt.num {
			t.Errorf("Expected a different number of packages. Got %d, expected %d for provider %T", n, tt.num, tt.provider)
		}
	}
}

func TestMedusa_GetString(t *testing.T) {
	provider := &MedusaUnitTestProvider{}
	key := "repodir"

	m, err := NewMedusa(provider)
	if err != nil {
		t.Errorf("NewMedusa(Provider) throws error: %s", err)
	}

	s := m.GetString(key)
	if len(s) == 0 {
		t.Errorf("Expected a non empty string. Got an empty string for key %s", key)
	}
}<|endoftext|>


<commit_before>package consul

import (
	"fmt"
	"net"
	"os"
	"sync"
	"testing"
	"time"

	"github.com/hashicorp/consul/consul/structs"
	"github.com/hashicorp/consul/testutil"
	"github.com/hashicorp/net-rpc-msgpackrpc"
	"github.com/hashicorp/serf/serf"
)

func testClientConfig(t *testing.T, NodeName string) (string, *Config) {
	dir := tmpDir(t)
	config := DefaultConfig()
	config.Datacenter = "dc1"
	config.DataDir = dir
	config.NodeName = NodeName
	config.RPCAddr = &net.TCPAddr{
		IP:   []byte{127, 0, 0, 1},
		Port: getPort(),
	}
	config.SerfLANConfig.MemberlistConfig.BindAddr = "127.0.0.1"
	config.SerfLANConfig.MemberlistConfig.BindPort = getPort()
	config.SerfLANConfig.MemberlistConfig.ProbeTimeout = 200 * time.Millisecond
	config.SerfLANConfig.MemberlistConfig.ProbeInterval = time.Second
	config.SerfLANConfig.MemberlistConfig.GossipInterval = 100 * time.Millisecond

	return dir, config
}

func testClient(t *testing.T) (string, *Client) {
	return testClientDC(t, "dc1")
}

func testClientDC(t *testing.T, dc string) (string, *Client) {
	dir, config := testClientConfig(t, "testco.internal")
	config.Datacenter = dc

	client, err := NewClient(config)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	return dir, client
}

func testClientWithConfig(t *testing.T, cb func(c *Config)) (string, *Client) {
	name := fmt.Sprintf("Client %d", getPort())
	dir, config := testClientConfig(t, name)
	cb(config)
	client, err := NewClient(config)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	return dir, client
}

func TestClient_StartStop(t *testing.T) {
	dir, client := testClient(t)
	defer os.RemoveAll(dir)

	if err := client.Shutdown(); err != nil {
		t.Fatalf("err: %v", err)
	}
}

func TestClient_JoinLAN(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, c1 := testClient(t)
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}
	testutil.WaitForResult(func() (bool, error) {
		return c1.serverMgr.NumServers() == 1, nil
	}, func(err error) {
		t.Fatalf("expected consul server")
	})

	// Check the members
	testutil.WaitForResult(func() (bool, error) {
		server_check := len(s1.LANMembers()) == 2
		client_check := len(c1.LANMembers()) == 2
		return server_check && client_check, nil
	}, func(err error) {
		t.Fatalf("bad len")
	})

	// Check we have a new consul
	testutil.WaitForResult(func() (bool, error) {
		return c1.serverMgr.NumServers() == 1, nil
	}, func(err error) {
		t.Fatalf("expected consul server")
	})
}

func TestClient_JoinLAN_Invalid(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, c1 := testClientDC(t, "other")
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err == nil {
		t.Fatalf("should error")
	}

	time.Sleep(50 * time.Millisecond)
	if len(s1.LANMembers()) != 1 {
		t.Fatalf("should not join")
	}
	if len(c1.LANMembers()) != 1 {
		t.Fatalf("should not join")
	}
}

func TestClient_JoinWAN_Invalid(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, c1 := testClientDC(t, "dc2")
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfWANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err == nil {
		t.Fatalf("should error")
	}

	time.Sleep(50 * time.Millisecond)
	if len(s1.WANMembers()) != 1 {
		t.Fatalf("should not join")
	}
	if len(c1.LANMembers()) != 1 {
		t.Fatalf("should not join")
	}
}

func TestClient_RPC(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, c1 := testClient(t)
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try an RPC
	var out struct{}
	if err := c1.RPC("Status.Ping", struct{}{}, &out); err != structs.ErrNoServers {
		t.Fatalf("err: %v", err)
	}

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check the members
	if len(s1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	if len(c1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	// RPC should succeed
	testutil.WaitForResult(func() (bool, error) {
		err := c1.RPC("Status.Ping", struct{}{}, &out)
		return err == nil, err
	}, func(err error) {
		t.Fatalf("err: %v", err)
	})
}

func TestClient_RPC_Pool(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, c1 := testClient(t)
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try to join.
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}
	if len(s1.LANMembers()) != 2 || len(c1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	// Blast out a bunch of RPC requests at the same time to try to get
	// contention opening new connections.
	var wg sync.WaitGroup
	for i := 0; i < 150; i++ {
		wg.Add(1)

		go func() {
			defer wg.Done()
			var out struct{}
			testutil.WaitForResult(func() (bool, error) {
				err := c1.RPC("Status.Ping", struct{}{}, &out)
				return err == nil, err
			}, func(err error) {
				t.Fatalf("err: %v", err)
			})
		}()
	}

	wg.Wait()
}

func TestClient_RPC_TLS(t *testing.T) {
	dir1, conf1 := testServerConfig(t, "a.testco.internal")
	conf1.VerifyIncoming = true
	conf1.VerifyOutgoing = true
	configureTLS(conf1)
	s1, err := NewServer(conf1)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, conf2 := testClientConfig(t, "b.testco.internal")
	conf2.VerifyOutgoing = true
	configureTLS(conf2)
	c1, err := NewClient(conf2)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try an RPC
	var out struct{}
	if err := c1.RPC("Status.Ping", struct{}{}, &out); err != structs.ErrNoServers {
		t.Fatalf("err: %v", err)
	}

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check the members
	if len(s1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	if len(c1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	// RPC should succeed
	testutil.WaitForResult(func() (bool, error) {
		err := c1.RPC("Status.Ping", struct{}{}, &out)
		return err == nil, err
	}, func(err error) {
		t.Fatalf("err: %v", err)
	})
}

func TestClientServer_UserEvent(t *testing.T) {
	clientOut := make(chan serf.UserEvent, 2)
	dir1, c1 := testClientWithConfig(t, func(conf *Config) {
		conf.UserEventHandler = func(e serf.UserEvent) {
			clientOut <- e
		}
	})
	defer os.RemoveAll(dir1)
	defer c1.Shutdown()

	serverOut := make(chan serf.UserEvent, 2)
	dir2, s1 := testServerWithConfig(t, func(conf *Config) {
		conf.UserEventHandler = func(e serf.UserEvent) {
			serverOut <- e
		}
	})
	defer os.RemoveAll(dir2)
	defer s1.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Wait for the leader
	testutil.WaitForLeader(t, s1.RPC, "dc1")

	// Check the members
	testutil.WaitForResult(func() (bool, error) {
		return len(c1.LANMembers()) == 2 && len(s1.LANMembers()) == 2, nil
	}, func(err error) {
		t.Fatalf("bad len")
	})

	// Fire the user event
	codec := rpcClient(t, s1)
	event := structs.EventFireRequest{
		Name:       "foo",
		Datacenter: "dc1",
		Payload:    []byte("baz"),
	}
	if err := msgpackrpc.CallWithCodec(codec, "Internal.EventFire", &event, nil); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Wait for all the events
	var clientReceived, serverReceived bool
	for i := 0; i < 2; i++ {
		select {
		case e := <-clientOut:
			switch e.Name {
			case "foo":
				clientReceived = true
			default:
				t.Fatalf("Bad: %#v", e)
			}

		case e := <-serverOut:
			switch e.Name {
			case "foo":
				serverReceived = true
			default:
				t.Fatalf("Bad: %#v", e)
			}

		case <-time.After(10 * time.Second):
			t.Fatalf("timeout")
		}
	}

	if !serverReceived || !clientReceived {
		t.Fatalf("missing events")
	}
}

func TestClient_Encrypted(t *testing.T) {
	dir1, c1 := testClient(t)
	defer os.RemoveAll(dir1)
	defer c1.Shutdown()

	key := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
	dir2, c2 := testClientWithConfig(t, func(c *Config) {
		c.SerfLANConfig.MemberlistConfig.SecretKey = key
	})
	defer os.RemoveAll(dir2)
	defer c2.Shutdown()

	if c1.Encrypted() {
		t.Fatalf("should not be encrypted")
	}
	if !c2.Encrypted() {
		t.Fatalf("should be encrypted")
	}
}
<commit_msg>Add a test for ConnPool.PingConsulServer<commit_after>package consul

import (
	"fmt"
	"net"
	"os"
	"sync"
	"testing"
	"time"

	"github.com/hashicorp/consul/consul/structs"
	"github.com/hashicorp/consul/testutil"
	"github.com/hashicorp/net-rpc-msgpackrpc"
	"github.com/hashicorp/serf/serf"
)

func testClientConfig(t *testing.T, NodeName string) (string, *Config) {
	dir := tmpDir(t)
	config := DefaultConfig()
	config.Datacenter = "dc1"
	config.DataDir = dir
	config.NodeName = NodeName
	config.RPCAddr = &net.TCPAddr{
		IP:   []byte{127, 0, 0, 1},
		Port: getPort(),
	}
	config.SerfLANConfig.MemberlistConfig.BindAddr = "127.0.0.1"
	config.SerfLANConfig.MemberlistConfig.BindPort = getPort()
	config.SerfLANConfig.MemberlistConfig.ProbeTimeout = 200 * time.Millisecond
	config.SerfLANConfig.MemberlistConfig.ProbeInterval = time.Second
	config.SerfLANConfig.MemberlistConfig.GossipInterval = 100 * time.Millisecond

	return dir, config
}

func testClient(t *testing.T) (string, *Client) {
	return testClientDC(t, "dc1")
}

func testClientDC(t *testing.T, dc string) (string, *Client) {
	dir, config := testClientConfig(t, "testco.internal")
	config.Datacenter = dc

	client, err := NewClient(config)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	return dir, client
}

func testClientWithConfig(t *testing.T, cb func(c *Config)) (string, *Client) {
	name := fmt.Sprintf("Client %d", getPort())
	dir, config := testClientConfig(t, name)
	cb(config)
	client, err := NewClient(config)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	return dir, client
}

func TestClient_StartStop(t *testing.T) {
	dir, client := testClient(t)
	defer os.RemoveAll(dir)

	if err := client.Shutdown(); err != nil {
		t.Fatalf("err: %v", err)
	}
}

func TestClient_JoinLAN(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, c1 := testClient(t)
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}
	testutil.WaitForResult(func() (bool, error) {
		return c1.serverMgr.NumServers() == 1, nil
	}, func(err error) {
		t.Fatalf("expected consul server")
	})

	// Check the members
	testutil.WaitForResult(func() (bool, error) {
		server_check := len(s1.LANMembers()) == 2
		client_check := len(c1.LANMembers()) == 2
		return server_check && client_check, nil
	}, func(err error) {
		t.Fatalf("bad len")
	})

	// Check we have a new consul
	testutil.WaitForResult(func() (bool, error) {
		return c1.serverMgr.NumServers() == 1, nil
	}, func(err error) {
		t.Fatalf("expected consul server")
	})
}

func TestClient_JoinLAN_Invalid(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, c1 := testClientDC(t, "other")
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err == nil {
		t.Fatalf("should error")
	}

	time.Sleep(50 * time.Millisecond)
	if len(s1.LANMembers()) != 1 {
		t.Fatalf("should not join")
	}
	if len(c1.LANMembers()) != 1 {
		t.Fatalf("should not join")
	}
}

func TestClient_JoinWAN_Invalid(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, c1 := testClientDC(t, "dc2")
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfWANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err == nil {
		t.Fatalf("should error")
	}

	time.Sleep(50 * time.Millisecond)
	if len(s1.WANMembers()) != 1 {
		t.Fatalf("should not join")
	}
	if len(c1.LANMembers()) != 1 {
		t.Fatalf("should not join")
	}
}

func TestClient_RPC(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, c1 := testClient(t)
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try an RPC
	var out struct{}
	if err := c1.RPC("Status.Ping", struct{}{}, &out); err != structs.ErrNoServers {
		t.Fatalf("err: %v", err)
	}

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check the members
	if len(s1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	if len(c1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	// RPC should succeed
	testutil.WaitForResult(func() (bool, error) {
		err := c1.RPC("Status.Ping", struct{}{}, &out)
		return err == nil, err
	}, func(err error) {
		t.Fatalf("err: %v", err)
	})
}

func TestClient_RPC_Pool(t *testing.T) {
	dir1, s1 := testServer(t)
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, c1 := testClient(t)
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try to join.
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}
	if len(s1.LANMembers()) != 2 || len(c1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	// Blast out a bunch of RPC requests at the same time to try to get
	// contention opening new connections.
	var wg sync.WaitGroup
	for i := 0; i < 150; i++ {
		wg.Add(1)

		go func() {
			defer wg.Done()
			var out struct{}
			testutil.WaitForResult(func() (bool, error) {
				err := c1.RPC("Status.Ping", struct{}{}, &out)
				return err == nil, err
			}, func(err error) {
				t.Fatalf("err: %v", err)
			})
		}()
	}

	wg.Wait()
}

func TestClient_RPC_ConsulServerPing(t *testing.T) {
	var servers []*Server
	var serverDirs []string
	const numServers = 5

	for n := numServers; n > 0; n-- {
		var bootstrap bool
		if n == numServers {
			bootstrap = true
		}
		dir, s := testServerDCBootstrap(t, "dc1", bootstrap)
		defer os.RemoveAll(dir)
		defer s.Shutdown()

		servers = append(servers, s)
		serverDirs = append(serverDirs, dir)
	}

	const numClients = 1
	clientDir, c := testClient(t)
	defer os.RemoveAll(clientDir)
	defer c.Shutdown()

	// Join all servers.
	for _, s := range servers {
		addr := fmt.Sprintf("127.0.0.1:%d",
			s.config.SerfLANConfig.MemberlistConfig.BindPort)
		if _, err := c.JoinLAN([]string{addr}); err != nil {
			t.Fatalf("err: %v", err)
		}
	}

	// Sleep to allow Serf to sync, shuffle, and let the shuffle complete
	time.Sleep(1 * time.Second)
	c.serverMgr.ResetRebalanceTimer()
	time.Sleep(1 * time.Second)

	if len(c.LANMembers()) != numServers+numClients {
		t.Errorf("bad len: %d", len(c.LANMembers()))
	}
	for _, s := range servers {
		if len(s.LANMembers()) != numServers+numClients {
			t.Errorf("bad len: %d", len(s.LANMembers()))
		}
	}

	// Ping each server in the list
	var pingCount int
	for range servers {
		time.Sleep(1 * time.Second)
		s := c.serverMgr.FindServer()
		if !c.connPool.PingConsulServer(s) {
			t.Errorf("Unable to ping server %v", s.String())
		}
		pingCount += 1
	}

	if pingCount != numServers {
		t.Errorf("bad len: %d/%d", pingCount, numServers)
	}
}

func TestClient_RPC_TLS(t *testing.T) {
	dir1, conf1 := testServerConfig(t, "a.testco.internal")
	conf1.VerifyIncoming = true
	conf1.VerifyOutgoing = true
	configureTLS(conf1)
	s1, err := NewServer(conf1)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	defer os.RemoveAll(dir1)
	defer s1.Shutdown()

	dir2, conf2 := testClientConfig(t, "b.testco.internal")
	conf2.VerifyOutgoing = true
	configureTLS(conf2)
	c1, err := NewClient(conf2)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	defer os.RemoveAll(dir2)
	defer c1.Shutdown()

	// Try an RPC
	var out struct{}
	if err := c1.RPC("Status.Ping", struct{}{}, &out); err != structs.ErrNoServers {
		t.Fatalf("err: %v", err)
	}

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check the members
	if len(s1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	if len(c1.LANMembers()) != 2 {
		t.Fatalf("bad len")
	}

	// RPC should succeed
	testutil.WaitForResult(func() (bool, error) {
		err := c1.RPC("Status.Ping", struct{}{}, &out)
		return err == nil, err
	}, func(err error) {
		t.Fatalf("err: %v", err)
	})
}

func TestClientServer_UserEvent(t *testing.T) {
	clientOut := make(chan serf.UserEvent, 2)
	dir1, c1 := testClientWithConfig(t, func(conf *Config) {
		conf.UserEventHandler = func(e serf.UserEvent) {
			clientOut <- e
		}
	})
	defer os.RemoveAll(dir1)
	defer c1.Shutdown()

	serverOut := make(chan serf.UserEvent, 2)
	dir2, s1 := testServerWithConfig(t, func(conf *Config) {
		conf.UserEventHandler = func(e serf.UserEvent) {
			serverOut <- e
		}
	})
	defer os.RemoveAll(dir2)
	defer s1.Shutdown()

	// Try to join
	addr := fmt.Sprintf("127.0.0.1:%d",
		s1.config.SerfLANConfig.MemberlistConfig.BindPort)
	if _, err := c1.JoinLAN([]string{addr}); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Wait for the leader
	testutil.WaitForLeader(t, s1.RPC, "dc1")

	// Check the members
	testutil.WaitForResult(func() (bool, error) {
		return len(c1.LANMembers()) == 2 && len(s1.LANMembers()) == 2, nil
	}, func(err error) {
		t.Fatalf("bad len")
	})

	// Fire the user event
	codec := rpcClient(t, s1)
	event := structs.EventFireRequest{
		Name:       "foo",
		Datacenter: "dc1",
		Payload:    []byte("baz"),
	}
	if err := msgpackrpc.CallWithCodec(codec, "Internal.EventFire", &event, nil); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Wait for all the events
	var clientReceived, serverReceived bool
	for i := 0; i < 2; i++ {
		select {
		case e := <-clientOut:
			switch e.Name {
			case "foo":
				clientReceived = true
			default:
				t.Fatalf("Bad: %#v", e)
			}

		case e := <-serverOut:
			switch e.Name {
			case "foo":
				serverReceived = true
			default:
				t.Fatalf("Bad: %#v", e)
			}

		case <-time.After(10 * time.Second):
			t.Fatalf("timeout")
		}
	}

	if !serverReceived || !clientReceived {
		t.Fatalf("missing events")
	}
}

func TestClient_Encrypted(t *testing.T) {
	dir1, c1 := testClient(t)
	defer os.RemoveAll(dir1)
	defer c1.Shutdown()

	key := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
	dir2, c2 := testClientWithConfig(t, func(c *Config) {
		c.SerfLANConfig.MemberlistConfig.SecretKey = key
	})
	defer os.RemoveAll(dir2)
	defer c2.Shutdown()

	if c1.Encrypted() {
		t.Fatalf("should not be encrypted")
	}
	if !c2.Encrypted() {
		t.Fatalf("should be encrypted")
	}
}
<|endoftext|>


<commit_before>package kiwi

// TODO: switch from
// github.com/Andoryuuta/w32 to github.com/VividCortex/w32 if pull request is accepted.

import (
	"errors"
	"fmt"
	"github.com/Andoryuuta/w32"
	"path/filepath"
	"reflect"
	"unsafe"
)

// Platform specific fields to be embeded into
// the Process struct.
type ProcPlatAttribs struct {
	Handle w32.HANDLE
}

// Constant for full process access
const PROCESS_ALL_ACCESS = w32.PROCESS_VM_READ | w32.PROCESS_VM_WRITE | w32.PROCESS_VM_OPERATION | w32.PROCESS_QUERY_INFORMATION

//getFileNameByPID returns a file name given a PID.
func getFileNameByPID(pid uint32) string {
	var fileName string = `<Unknown File>`

	//Open process
	hnd, ok := w32.OpenProcess(w32.PROCESS_QUERY_INFORMATION, false, pid)
	if !ok {
		return fileName
	}
	defer w32.CloseHandle(hnd)

	//Get file path
	path, ok := w32.GetProcessImageFileName(hnd)
	if !ok {
		return fileName
	}

	//Split file path to get file name
	_, fileName = filepath.Split(path)
	return fileName
}

// GetProcessByFileName returns the process with the given file name.
// If multiple processes have the same filename, the first process
// enumerated by this function is returned.
func GetProcessByFileName(fileName string) (Process, error) {
	// Read in process ids
	PIDs := make([]uint32, 1024)
	var bytesRead uint32 = 0
	ok := w32.EnumProcesses(PIDs, uint32(len(PIDs)), &bytesRead)
	if !ok {
		panic("Error Enumerating processes.")
	}

	// Loop over pids,
	// Divide bytesRead by sizeof(uint32) to get how many processes there are.
	for i := uint32(0); i < (bytesRead / 4); i++ {
		// Make sure to skip over the system process with PID 0
		if PIDs[i] == 0 {
			continue
		}

		// Check if its the process
		if getFileNameByPID(PIDs[i]) == fileName {
			hnd, ok := w32.OpenProcess(PROCESS_ALL_ACCESS, false, PIDs[i])
			if !ok {
				return Process{}, errors.New(fmt.Sprintf("Error while opening process %d", PIDs[i]))
			}
			return Process{hnd, PIDs[i]}, nil
		}
	}

	// Couldn't find process, return an error
	return Process{}, errors.New("Couldn't find process with name " + fileName)
}

// Taken from genkman's gist(https://gist.github.com/henkman/3083408)
func (p *Process) GetModuleBase(moduleName string) (uintptr, error) {
	snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPMODULE32|w32.TH32CS_SNAPALL|w32.TH32CS_SNAPMODULE, p.PID)
	if snap == 0 {
		return 0, errors.New("Error trying on create toolhelp32 snapshot.")
	}
	defer w32.CloseHandle(snap)

	var me32 w32.MODULEENTRY32
	me32.Size = uint32(unsafe.Sizeof(me32))

	// Get first module
	if !w32.Module32First(snap, &me32) {
		return 0, errors.New("Error trying to get first module.")
	}

	// Check first module
	if syscall.UTF16ToString(me32.SzModule[:]) == moduleName {
		return uintptr(unsafe.Pointer(me32.ModBaseAddr)), nil
	}

	// Loop all modules remaining
	for w32.Module32Next(snap, &me32) {
		// Check this module
		if syscall.UTF16ToString(me32.SzModule[:]) == moduleName {
			return uintptr(unsafe.Pointer(me32.ModBaseAddr)), nil
		}
	}

	// If this is reached, then we couldn't find the module
	return 0, errors.New("Couldn't Find Module.")
}

// The Windows specific read function.
func (p *Process) read(addr uintptr, ptr interface{}) error {
	v := reflect.ValueOf(ptr)
	i := reflect.Indirect(v)
	size := i.Type().Size()
	bytesRead, ok := w32.ReadProcessMemory(
		p.Handle,
		unsafe.Pointer(addr),
		unsafe.Pointer(i.UnsafeAddr()),
		size,
	)
	if !ok || bytesRead != size {
		return errors.New("Error on reading process memory.")
	}
	return nil
}

// The Windows specific write function.
func (p *Process) write(addr uintptr, ptr interface{}) error {
	v := reflect.ValueOf(ptr)
	i := reflect.Indirect(v)
	size := i.Type().Size()
	bytesWritten, ok := w32.WriteProcessMemory(
		p.Handle,
		unsafe.Pointer(addr),
		unsafe.Pointer(i.UnsafeAddr()),
		size,
	)
	if !ok || bytesWritten != size {
		return errors.New("Error on writing process memory.")
	}
	return nil
}
<commit_msg>Fixed small things which broke on windows.<commit_after>package kiwi

import (
	"errors"
	"fmt"
	"github.com/Andoryuuta/w32"
	"path/filepath"
	"reflect"
	"syscall"
	"unsafe"
)

// Platform specific fields to be embeded into
// the Process struct.
type ProcPlatAttribs struct {
	Handle w32.HANDLE
}

// Constant for full process access
const PROCESS_ALL_ACCESS = w32.PROCESS_VM_READ | w32.PROCESS_VM_WRITE | w32.PROCESS_VM_OPERATION | w32.PROCESS_QUERY_INFORMATION

//getFileNameByPID returns a file name given a PID.
func getFileNameByPID(pid uint32) string {
	var fileName string = `<Unknown File>`

	//Open process
	hnd, ok := w32.OpenProcess(w32.PROCESS_QUERY_INFORMATION, false, pid)
	if !ok {
		return fileName
	}
	defer w32.CloseHandle(hnd)

	//Get file path
	path, ok := w32.GetProcessImageFileName(hnd)
	if !ok {
		return fileName
	}

	//Split file path to get file name
	_, fileName = filepath.Split(path)
	return fileName
}

// GetProcessByFileName returns the process with the given file name.
// If multiple processes have the same filename, the first process
// enumerated by this function is returned.
func GetProcessByFileName(fileName string) (Process, error) {
	// Read in process ids
	PIDs := make([]uint32, 1024)
	var bytesRead uint32 = 0
	ok := w32.EnumProcesses(PIDs, uint32(len(PIDs)), &bytesRead)
	if !ok {
		panic("Error Enumerating processes.")
	}

	// Loop over pids,
	// Divide bytesRead by sizeof(uint32) to get how many processes there are.
	for i := uint32(0); i < (bytesRead / 4); i++ {
		// Make sure to skip over the system process with PID 0
		if PIDs[i] == 0 {
			continue
		}

		// Check if its the process
		if getFileNameByPID(PIDs[i]) == fileName {
			hnd, ok := w32.OpenProcess(PROCESS_ALL_ACCESS, false, PIDs[i])
			if !ok {
				return Process{}, errors.New(fmt.Sprintf("Error while opening process %d", PIDs[i]))
			}
			return Process{ProcPlatAttribs: ProcPlatAttribs{Handle: hnd}, PID: uint64(PIDs[i])}, nil
		}
	}

	// Couldn't find process, return an error
	return Process{}, errors.New("Couldn't find process with name " + fileName)
}

// GetModuleBase takes a module name as an argument. (e.g. "kernel32.dll")
// Returns the modules base address.
//
// (Mostly taken from genkman's gist: https://gist.github.com/henkman/3083408)
// TODO(Andoryuuta): Figure out possible licencing issues with this, or rewrite.
func (p *Process) GetModuleBase(moduleName string) (uintptr, error) {
	snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPMODULE32|w32.TH32CS_SNAPALL|w32.TH32CS_SNAPMODULE, uint32(p.PID))
	if snap == 0 {
		return 0, errors.New("Error trying on create toolhelp32 snapshot.")
	}
	defer w32.CloseHandle(snap)

	var me32 w32.MODULEENTRY32
	me32.Size = uint32(unsafe.Sizeof(me32))

	// Get first module
	if !w32.Module32First(snap, &me32) {
		return 0, errors.New("Error trying to get first module.")
	}

	// Check first module
	if syscall.UTF16ToString(me32.SzModule[:]) == moduleName {
		return uintptr(unsafe.Pointer(me32.ModBaseAddr)), nil
	}

	// Loop all modules remaining
	for w32.Module32Next(snap, &me32) {
		// Check this module
		if syscall.UTF16ToString(me32.SzModule[:]) == moduleName {
			return uintptr(unsafe.Pointer(me32.ModBaseAddr)), nil
		}
	}

	// If this is reached, then we couldn't find the module
	return 0, errors.New("Couldn't Find Module.")
}

// The Windows specific read function.
func (p *Process) read(addr uintptr, ptr interface{}) error {
	v := reflect.ValueOf(ptr)
	i := reflect.Indirect(v)
	size := i.Type().Size()
	bytesRead, ok := w32.ReadProcessMemory(
		p.Handle,
		unsafe.Pointer(addr),
		unsafe.Pointer(i.UnsafeAddr()),
		size,
	)
	if !ok || bytesRead != size {
		return errors.New("Error on reading process memory.")
	}
	return nil
}

// The Windows specific write function.
func (p *Process) write(addr uintptr, ptr interface{}) error {
	v := reflect.ValueOf(ptr)
	i := reflect.Indirect(v)
	size := i.Type().Size()
	bytesWritten, ok := w32.WriteProcessMemory(
		p.Handle,
		unsafe.Pointer(addr),
		unsafe.Pointer(i.UnsafeAddr()),
		size,
	)
	if !ok || bytesWritten != size {
		return errors.New("Error on writing process memory.")
	}
	return nil
}
<|endoftext|>


<commit_before>// +build windows

package gopsutil

func Pids() ([]int32, error) {
	ret := make([]int32, 0)

	return ret, nil
}

func NewProcess(pid int32) (*Process, error) {
	p := &Process{Pid: pid}
	return p, nil
}
<commit_msg>start to get windows process information<commit_after>// +build windows

package gopsutil

import (
	"fmt"
	"syscall"
	"unsafe"
)

var (
	procCloseHandle              = modKernel32.NewProc("CloseHandle")
	procCreateToolhelp32Snapshot = modKernel32.NewProc("CreateToolhelp32Snapshot")
	procProcess32First           = modKernel32.NewProc("Process32FirstW")
	procProcess32Next            = modKernel32.NewProc("Process32NextW")
)

const (
	ERROR_NO_MORE_FILES = 0x12
	MAX_PATH            = 260
)

type PROCESSENTRY32 struct {
	DwSize              uint32
	CntUsage            uint32
	Th32ProcessID       uint32
	Th32DefaultHeapID   uintptr
	Th32ModuleID        uint32
	CntThreads          uint32
	Th32ParentProcessID uint32
	PcPriClassBase      int32
	DwFlags             uint32
	SzExeFile           [MAX_PATH]uint16
}

/*
type SYSTEM_PROCESS_INFORMATION struct {
	ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    BYTE Reserved1[48];
    PVOID Reserved2[3];
    HANDLE UniqueProcessId;
    PVOID Reserved3;
    ULONG HandleCount;
    BYTE Reserved4[4];
    PVOID Reserved5[11];
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved6[6];
}
*/

func Pids() ([]int32, error) {
	ret := make([]int32, 0)

	procs, err := processes()
	if err != nil {
		return ret, nil
	}
	for _, proc := range procs {
		ret = append(ret, proc.Pid)
	}

	return ret, nil
}

func NewProcess(pid int32) (*Process, error) {
	p := &Process{Pid: pid}

	if (pid == 0) || (pid == 4) {
		p.Cmdline = ""
	}
	return p, nil
}

func copy_params(pe32 *PROCESSENTRY32, p *Process) error {
	p.Ppid = int32(pe32.Th32ParentProcessID)

	return nil
}

// Get processes
// This is borrowed from go-ps
func processes() ([]*Process, error) {
	handle, _, _ := procCreateToolhelp32Snapshot.Call(
		0x00000002,
		0)
	if handle < 0 {
		return nil, syscall.GetLastError()
	}
	defer procCloseHandle.Call(handle)

	var entry PROCESSENTRY32
	entry.DwSize = uint32(unsafe.Sizeof(entry))
	ret, _, _ := procProcess32First.Call(handle, uintptr(unsafe.Pointer(&entry)))
	if ret == 0 {
		return nil, fmt.Errorf("Error retrieving process info.")
	}

	results := make([]*Process, 0)
	for {
		pid := int32(entry.Th32ProcessID)
		p, err := NewProcess(pid)
		if err != nil {
			break
		}
		copy_params(&entry, p)
		results = append(results, p)

		ret, _, _ := procProcess32Next.Call(handle, uintptr(unsafe.Pointer(&entry)))
		if ret == 0 {
			break
		}
	}

	return results, nil
}
<|endoftext|>


<commit_before>package main

import (
    "bufio"
    "flag"
    "fmt"
    "github.com/nu7hatch/gouuid"
    "io"
    "log"
    "net"
    "net/url"
    "os"
    "os/signal"
    "syscall"
)

type exchangeid string

type Exchange struct {
    id     exchangeid
    router *Router
    socket net.Listener
    uchan  chan string
}

func NewExchange(id string, socket net.Listener) *Exchange {
    return &Exchange{exchangeid(id), NewRouter(), socket, make(chan string)}
}

func (e *Exchange) Start(quit <-chan bool, quitted chan<- bool) {
    squit := make(chan bool, 1)
    uquit := make(chan bool, 1)

    go func() {
        e.waitClient(squit)
        e.distributeUrl(uquit)
    }()

    <-quit
    close(e.uchan)
    e.socket.Close()

    <-uquit
    <-squit

    quitted <- true
}

func (e *Exchange) waitClient(quit chan<- bool) {
    for {
        log.Printf("Waiting client")
        client, err := e.socket.Accept()
        log.Printf("Accepting client")
        if err != nil {
            log.Println(err)
            break
        }
        log.Printf("Connected from %s", client.RemoteAddr().String())
        go func() {
            e.handleConnection(client)
        }()
    }

    quit <- true
}

func (e *Exchange) handleConnection(client net.Conn) {
    crawler := NewCrawler(e.id, client)
    e.router.Add(crawler)
    defer e.router.Remove(crawler)

    reader := bufio.NewReader(crawler.GetConn())
    for {
        rawurl, err := reader.ReadString('\n')
        if err != nil {
            if err == io.EOF {
                log.Printf("Connection closed by %s", client.RemoteAddr().String())
            } else {
                log.Println(err)
            }
            break
        }

        switch parsed, err := url.Parse(rawurl); {
        case len(rawurl) < 1:
            log.Printf("Invalid URL: %s", rawurl)
        case err != nil:
            log.Printf("Invalid URL: %s (%v)", rawurl, err)
        case parsed.Scheme != "http" && parsed.Scheme != "https":
            log.Printf("Invalid URL: %s", rawurl)
        default:
            e.uchan <- rawurl[:len(rawurl)-2]
        }
    }
}

func (e *Exchange) distributeUrl(quit chan<- bool) {
    for rawurl := range e.uchan {
        crawler, err := e.router.Route(rawurl)
        if err != nil {
            log.Println(err)
            e.uchan <- rawurl
            continue
        }

        eid := crawler.GetExchangeId()
        if eid == e.id {
            fmt.Fprintf(crawler.GetConn(), rawurl+"\n")
        } else {
            // amqp.Publish(exchange), rawurl)
        }
    }
    quit <- true
}

func main() {
    newid, _ := uuid.NewV4()
    id := *flag.String("id", newid.String(), "Exchange ID")
    ip := *flag.String("ip", "0.0.0.0", "IP address for listen")
    port := *flag.Int("port", 9000, "Port number for listen")
    flag.Parse()

    isContinue := true
    for isContinue {
        func() {
            quit := make(chan bool, 1)
            quitted := make(chan bool, 1)
            defer func() {
                quit <- true
                if err := recover(); err == nil {
                    isContinue = false
                    log.Println("Exiting...")
                }
                <-quitted
            }()

            log.Printf("Listening %s:%d", ip, port)
            socket, err := net.Listen("tcp", fmt.Sprintf("%s:%d", ip, port))
            if err != nil {
                log.Fatalln(err)
                return
            }
            exchange := NewExchange(id, socket)
            go exchange.Start(quit, quitted)

            stop := make(chan os.Signal, 1)
            signal.Notify(stop, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGTERM)
            <-stop
        }()
    }
}
<commit_msg>add message when exit<commit_after>package main

import (
    "bufio"
    "flag"
    "fmt"
    "github.com/nu7hatch/gouuid"
    "io"
    "log"
    "net"
    "net/url"
    "os"
    "os/signal"
    "syscall"
)

type exchangeid string

type Exchange struct {
    id     exchangeid
    router *Router
    socket net.Listener
    uchan  chan string
}

func NewExchange(id string, socket net.Listener) *Exchange {
    return &Exchange{exchangeid(id), NewRouter(), socket, make(chan string)}
}

func (e *Exchange) Start(quit <-chan bool, quitted chan<- bool) {
    squit := make(chan bool, 1)
    uquit := make(chan bool, 1)

    go func() {
        e.waitClient(squit)
        e.distributeUrl(uquit)
    }()

    <-quit
    close(e.uchan)
    e.socket.Close()

    <-uquit
    <-squit

    quitted <- true
}

func (e *Exchange) waitClient(quit chan<- bool) {
    for {
        log.Printf("Waiting client")
        client, err := e.socket.Accept()
        log.Printf("Accepting client")
        if err != nil {
            log.Println(err)
            break
        }
        log.Printf("Connected from %s", client.RemoteAddr().String())
        go func() {
            e.handleConnection(client)
        }()
    }

    quit <- true
}

func (e *Exchange) handleConnection(client net.Conn) {
    crawler := NewCrawler(e.id, client)
    e.router.Add(crawler)
    defer e.router.Remove(crawler)

    reader := bufio.NewReader(crawler.GetConn())
    for {
        rawurl, err := reader.ReadString('\n')
        if err != nil {
            if err == io.EOF {
                log.Printf("Connection closed by %s", client.RemoteAddr().String())
            } else {
                log.Println(err)
            }
            break
        }

        switch parsed, err := url.Parse(rawurl); {
        case len(rawurl) < 1:
            log.Printf("Invalid URL: %s", rawurl)
        case err != nil:
            log.Printf("Invalid URL: %s (%v)", rawurl, err)
        case parsed.Scheme != "http" && parsed.Scheme != "https":
            log.Printf("Invalid URL: %s", rawurl)
        default:
            e.uchan <- rawurl[:len(rawurl)-2]
        }
    }
}

func (e *Exchange) distributeUrl(quit chan<- bool) {
    for rawurl := range e.uchan {
        crawler, err := e.router.Route(rawurl)
        if err != nil {
            log.Println(err)
            e.uchan <- rawurl
            continue
        }

        eid := crawler.GetExchangeId()
        if eid == e.id {
            fmt.Fprintf(crawler.GetConn(), rawurl+"\n")
        } else {
            // amqp.Publish(exchange), rawurl)
        }
    }
    quit <- true
}

func main() {
    newid, _ := uuid.NewV4()
    id := *flag.String("id", newid.String(), "Exchange ID")
    ip := *flag.String("ip", "0.0.0.0", "IP address for listen")
    port := *flag.Int("port", 9000, "Port number for listen")
    flag.Parse()

    isContinue := true
    for isContinue {
        func() {
            quit := make(chan bool, 1)
            quitted := make(chan bool, 1)
            defer func() {
                quit <- true
                if err := recover(); err == nil {
                    isContinue = false
                    log.Println("Exiting...")
                }
                <-quitted
                log.Println("Exit")
            }()

            log.Printf("Listening %s:%d", ip, port)
            socket, err := net.Listen("tcp", fmt.Sprintf("%s:%d", ip, port))
            if err != nil {
                log.Fatalln(err)
                return
            }
            exchange := NewExchange(id, socket)
            go exchange.Start(quit, quitted)

            stop := make(chan os.Signal, 1)
            signal.Notify(stop, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGTERM)
            <-stop
        }()
    }
}
<|endoftext|>


<commit_before>package program

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "v0.24.0 Cadmium 2018-05-14"
<commit_msg>Bump version: v0.24.1 Cadmium 2018-05-17<commit_after>package program

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "v0.24.1 Cadmium 2018-05-17"
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state

import (
	"sync"

	"github.com/juju/errors"
	"gopkg.in/juju/names.v2"
)

// NewStatePool returns a new StatePool instance. It takes a State
// connected to the system (controller model).
func NewStatePool(systemState *State) *StatePool {
	return &StatePool{
		systemState: systemState,
		pool:        make(map[string]*PoolItem),
	}
}

// PoolItem holds a State and tracks how many requests are using it
// and whether it's been marked for removal.
type PoolItem struct {
	state      *State
	references uint
	remove     bool
}

// StatePool is a cache of State instances for multiple
// models. Clients should call Put when they have finished with any
// state.
type StatePool struct {
	systemState *State
	// mu protects pool
	mu   sync.Mutex
	pool map[string]*PoolItem
}

// Get returns a State for a given model from the pool, creating one
// if required. If the State has been marked for removal because there
// are outstanding uses, an error will be returned.
func (p *StatePool) Get(modelUUID string) (*State, error) {
	if modelUUID == p.systemState.ModelUUID() {
		return p.systemState, nil
	}

	p.mu.Lock()
	defer p.mu.Unlock()

	item, ok := p.pool[modelUUID]
	if ok && item.remove {
		// We don't want to allow increasing the refcount of a model
		// that's been removed.
		return nil, errors.Errorf("model %v has been removed", modelUUID)
	}
	if ok {
		item.references++
		return item.state, nil
	}

	st, err := p.systemState.ForModel(names.NewModelTag(modelUUID))
	if err != nil {
		return nil, errors.Annotatef(err, "failed to create state for model %v", modelUUID)
	}
	p.pool[modelUUID] = &PoolItem{state: st, references: 1}
	return st, nil
}

// Put indicates that the client has finished using the State. If the
// state has been marked for removal, it will be closed and removed
// when the final Put is done.
func (p *StatePool) Put(modelUUID string) error {
	if modelUUID == p.systemState.ModelUUID() {
		// We don't maintain a refcount for the controller.
		return nil
	}

	p.mu.Lock()
	defer p.mu.Unlock()

	item, ok := p.pool[modelUUID]
	if !ok {
		return errors.Errorf("unable to return unknown model %v to the pool", modelUUID)
	}
	if item.references == 0 {
		return errors.Errorf("state pool refcount for model %v is already 0", modelUUID)
	}
	item.references--
	return p.maybeRemoveItem(modelUUID, item)
}

// Remove takes the state out of the pool and closes it, or marks it
// for removal if it's currently being used (indicated by Gets without
// corresponding Puts).
func (p *StatePool) Remove(modelUUID string) error {
	if modelUUID == p.systemState.ModelUUID() {
		// We don't manage the controller state.
		return nil
	}

	p.mu.Lock()
	defer p.mu.Unlock()

	item, ok := p.pool[modelUUID]
	if !ok {
		// Don't require the client to keep track of what we've seen -
		// ignore unknown model ids.
		return nil
	}
	item.remove = true
	return p.maybeRemoveItem(modelUUID, item)
}

func (p *StatePool) maybeRemoveItem(modelUUID string, item *PoolItem) error {
	if item.remove && item.references == 0 {
		delete(p.pool, modelUUID)
		return item.state.Close()
	}
	return nil
}

// SystemState returns the State passed in to NewStatePool.
func (p *StatePool) SystemState() *State {
	return p.systemState
}

// KillWorkers tells the internal worker for all cached State
// instances in the pool to die.
func (p *StatePool) KillWorkers() {
	p.mu.Lock()
	defer p.mu.Unlock()
	for _, item := range p.pool {
		item.state.KillWorkers()
	}
}

// Close closes all State instances in the pool.
func (p *StatePool) Close() error {
	p.mu.Lock()
	defer p.mu.Unlock()

	var lastErr error
	for _, item := range p.pool {
		err := item.state.Close()
		if err != nil {
			lastErr = err
		}
	}
	p.pool = make(map[string]*PoolItem)
	return errors.Annotate(lastErr, "at least one error closing a state")
}
<commit_msg>Log when StatePool.Close sees a leaked State<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state

import (
	"sync"

	"github.com/juju/errors"
	"gopkg.in/juju/names.v2"
)

// NewStatePool returns a new StatePool instance. It takes a State
// connected to the system (controller model).
func NewStatePool(systemState *State) *StatePool {
	return &StatePool{
		systemState: systemState,
		pool:        make(map[string]*PoolItem),
	}
}

// PoolItem holds a State and tracks how many requests are using it
// and whether it's been marked for removal.
type PoolItem struct {
	state      *State
	references uint
	remove     bool
}

// StatePool is a cache of State instances for multiple
// models. Clients should call Put when they have finished with any
// state.
type StatePool struct {
	systemState *State
	// mu protects pool
	mu   sync.Mutex
	pool map[string]*PoolItem
}

// Get returns a State for a given model from the pool, creating one
// if required. If the State has been marked for removal because there
// are outstanding uses, an error will be returned.
func (p *StatePool) Get(modelUUID string) (*State, error) {
	if modelUUID == p.systemState.ModelUUID() {
		return p.systemState, nil
	}

	p.mu.Lock()
	defer p.mu.Unlock()

	item, ok := p.pool[modelUUID]
	if ok && item.remove {
		// We don't want to allow increasing the refcount of a model
		// that's been removed.
		return nil, errors.Errorf("model %v has been removed", modelUUID)
	}
	if ok {
		item.references++
		return item.state, nil
	}

	st, err := p.systemState.ForModel(names.NewModelTag(modelUUID))
	if err != nil {
		return nil, errors.Annotatef(err, "failed to create state for model %v", modelUUID)
	}
	p.pool[modelUUID] = &PoolItem{state: st, references: 1}
	return st, nil
}

// Put indicates that the client has finished using the State. If the
// state has been marked for removal, it will be closed and removed
// when the final Put is done.
func (p *StatePool) Put(modelUUID string) error {
	if modelUUID == p.systemState.ModelUUID() {
		// We don't maintain a refcount for the controller.
		return nil
	}

	p.mu.Lock()
	defer p.mu.Unlock()

	item, ok := p.pool[modelUUID]
	if !ok {
		return errors.Errorf("unable to return unknown model %v to the pool", modelUUID)
	}
	if item.references == 0 {
		return errors.Errorf("state pool refcount for model %v is already 0", modelUUID)
	}
	item.references--
	return p.maybeRemoveItem(modelUUID, item)
}

// Remove takes the state out of the pool and closes it, or marks it
// for removal if it's currently being used (indicated by Gets without
// corresponding Puts).
func (p *StatePool) Remove(modelUUID string) error {
	if modelUUID == p.systemState.ModelUUID() {
		// We don't manage the controller state.
		return nil
	}

	p.mu.Lock()
	defer p.mu.Unlock()

	item, ok := p.pool[modelUUID]
	if !ok {
		// Don't require the client to keep track of what we've seen -
		// ignore unknown model ids.
		return nil
	}
	item.remove = true
	return p.maybeRemoveItem(modelUUID, item)
}

func (p *StatePool) maybeRemoveItem(modelUUID string, item *PoolItem) error {
	if item.remove && item.references == 0 {
		delete(p.pool, modelUUID)
		return item.state.Close()
	}
	return nil
}

// SystemState returns the State passed in to NewStatePool.
func (p *StatePool) SystemState() *State {
	return p.systemState
}

// KillWorkers tells the internal worker for all cached State
// instances in the pool to die.
func (p *StatePool) KillWorkers() {
	p.mu.Lock()
	defer p.mu.Unlock()
	for _, item := range p.pool {
		item.state.KillWorkers()
	}
}

// Close closes all State instances in the pool.
func (p *StatePool) Close() error {
	p.mu.Lock()
	defer p.mu.Unlock()

	var lastErr error
	for _, item := range p.pool {
		if item.references != 0 || item.remove {
			logger.Warningf(
				"state for %v leaked from pool - references: %v, removed: %v",
				item.state.ModelUUID(),
				item.references,
				item.remove,
			)
		}
		err := item.state.Close()
		if err != nil {
			lastErr = err
		}
	}
	p.pool = make(map[string]*PoolItem)
	return errors.Annotate(lastErr, "at least one error closing a state")
}
<|endoftext|>


<commit_before>package dotweb

import (
	"testing"
)

// 以下为功能测试

func Test_AddRequestCount_1(t *testing.T) {
	var num uint64 = 1
	var count uint64
	for i := 0; i < 100; i++ {
		count = GlobalState.AddRequestCount(num)
	}
	t.Log("TotalRequestCount:", count)
}

func Test_AddRequestCount_2(t *testing.T) {
	var num uint64 = 1
	var count uint64
	for i := 0; i < 100; i++ {
		count = GlobalState.AddRequestCount(num)
		num++
	}
	t.Log("TotalRequestCount:", count)
}

func Test_AddErrorCount_1(t *testing.T) {
	var num, count uint64
	for i := 0; i < 100; i++ {
		num = 1
		count = GlobalState.AddErrorCount(num)
	}
	t.Log("TotalErrorCount:", count)
}

func Test_AddErrorCount_2(t *testing.T) {
	var num, count uint64
	for i := 0; i < 100; i++ {
		count = GlobalState.AddErrorCount(num)
		num++
	}
	t.Log("TotalErrorCount:", count)
}

// 以下是性能测试
<commit_msg>update Unit test files<commit_after>package dotweb

import (
	"testing"
)

// 以下为功能测试

func Test_AddRequestCount_1(t *testing.T) {
	var num uint64 = 1
	var count uint64
	for i := 0; i < 100; i++ {
		count = GlobalState.AddRequestCount(num)
	}
	t.Log("TotalRequestCount:", count)
}

func Test_AddRequestCount_2(t *testing.T) {
	var num uint64 = 1
	var count uint64
	for i := 0; i < 100; i++ {
		count = GlobalState.AddRequestCount(num)
		num++
	}
	t.Log("TotalRequestCount:", count)
}

func Test_AddErrorCount_1(t *testing.T) {
	var num, count uint64
	for i := 0; i < 100; i++ {
		num = 1
		count = GlobalState.AddErrorCount(num)
	}
	t.Log("TotalErrorCount:", count)
}

func Test_AddErrorCount_2(t *testing.T) {
	var num, count uint64
	for i := 0; i < 100; i++ {
		count = GlobalState.AddErrorCount(num)
		num++
	}
	t.Log("TotalErrorCount:", count)
}

// 以下是性能测试

//基准测试
func Benchmark_AddErrorCount_1(b *testing.B) {
	var num uint64 = 1
	for i := 0; i < b.N; i++ {
		GlobalState.AddErrorCount(num)
	}
}

// 测试并发效率
func Benchmark_AddErrorCount_Parallel(b *testing.B) {
	b.RunParallel(func(pb *testing.PB) {
		var num uint64 = 1
		for pb.Next() {
			GlobalState.AddErrorCount(num)
		}
	})
}

//基准测试
func Benchmark_AddRequestCount_1(b *testing.B) {
	var num uint64 = 1
	for i := 0; i < b.N; i++ {
		GlobalState.AddRequestCount(num)
	}
}

// 测试并发效率
func Benchmark_AddRequestCount_Parallel(b *testing.B) {
	b.RunParallel(func(pb *testing.PB) {
		var num uint64 = 1
		for pb.Next() {
			GlobalState.AddRequestCount(num)
		}
	})
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2018 gRPC authors.
 *
 * 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 alts implements the ALTS credential support by gRPC library, which
// encapsulates all the state needed by a client to authenticate with a server
// using ALTS and make various assertions, e.g., about the client's identity,
// role, or whether it is authorized to make a particular call.
// This package is experimental.
package alts

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"sync"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/credentials/alts/core"
	"google.golang.org/grpc/credentials/alts/core/handshaker"
	"google.golang.org/grpc/credentials/alts/core/handshaker/service"
	altspb "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp"
	"google.golang.org/grpc/grpclog"
)

const (
	// defaultTimeout specifies the server handshake timeout.
	defaultTimeout = 30.0 * time.Second
	// The following constants specify the minimum and maximum acceptable
	// protocol versions.
	protocolVersionMaxMajor = 2
	protocolVersionMaxMinor = 1
	protocolVersionMinMajor = 2
	protocolVersionMinMinor = 1
)

var (
	enableUntrustedALTS = flag.Bool("enable_untrusted_alts", false, "Enables ALTS in untrusted mode. Enabling this mode is risky since we cannot ensure that the application is running on GCP with a trusted handshaker service.")
	once                sync.Once
	maxRPCVersion       = &altspb.RpcProtocolVersions_Version{
		Major: protocolVersionMaxMajor,
		Minor: protocolVersionMaxMinor,
	}
	minRPCVersion = &altspb.RpcProtocolVersions_Version{
		Major: protocolVersionMinMajor,
		Minor: protocolVersionMinMinor,
	}
	// ErrUntrustedPlatform is returned from ClientHandshake and
	// ServerHandshake is running on a platform where the trustworthiness of
	// the handshaker service is not guaranteed.
	ErrUntrustedPlatform = errors.New("untrusted platform, use enable_untrusted_alts flag at your own risk")
)

// AuthInfo exposes security information from the ALTS handshake to the
// application. This interface is to be implemented by ALTS. Users should not
// need a brand new implementation of this interface. For situations like
// testing, any new implementation should embed this interface. This allows
// ALTS to add new methods to this interface.
type AuthInfo interface {
	// ApplicationProtocol returns application protocol negotiated for the
	// ALTS connection.
	ApplicationProtocol() string
	// RecordProtocol returns the record protocol negotiated for the ALTS
	// connection.
	RecordProtocol() string
	// SecurityLevel returns the security level of the created ALTS secure
	// channel.
	SecurityLevel() altspb.SecurityLevel
	// PeerServiceAccount returns the peer service account.
	PeerServiceAccount() string
	// LocalServiceAccount returns the local service account.
	LocalServiceAccount() string
	// PeerRPCVersions returns the RPC version supported by the peer.
	PeerRPCVersions() *altspb.RpcProtocolVersions
}

// ClientOptions contains the client-side options of an ALTS channel. These
// options will be passed to the underlying ALTS handshaker.
type ClientOptions struct {
	// TargetServiceAccounts contains a list of expected target service
	// accounts.
	TargetServiceAccounts []string
}

// altsTC is the credentials required for authenticating a connection using ALTS.
// It implements credentials.TransportCredentials interface.
type altsTC struct {
	info     *credentials.ProtocolInfo
	hsAddr   string
	side     core.Side
	accounts []string
}

// NewClientCreds constructs a client-side ALTS TransportCredentials object.
func NewClientCreds(opts *ClientOptions) credentials.TransportCredentials {
	return newALTS(core.ClientSide, opts.TargetServiceAccounts)
}

// NewServerCreds constructs a server-side ALTS TransportCredentials object.
func NewServerCreds() credentials.TransportCredentials {
	return newALTS(core.ServerSide, nil)
}

func newALTS(side core.Side, accounts []string) credentials.TransportCredentials {
	// Make sure flags are parsed before accessing enableUntrustedALTS.
	once.Do(func() {
		flag.Parse()
		vmOnGCP = isRunningOnGCP()
	})
	if *enableUntrustedALTS {
		grpclog.Warning("untrusted ALTS mode is enabled and we cannot guarantee the trustworthiness of the ALTS handshaker service.")
	}

	return &altsTC{
		info: &credentials.ProtocolInfo{
			SecurityProtocol: "alts",
			SecurityVersion:  "1.0",
		},
		side:     side,
		accounts: accounts,
	}
}

// ClientHandshake implements the client side handshake protocol.
func (g *altsTC) ClientHandshake(ctx context.Context, addr string, rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) {
	if !*enableUntrustedALTS && !vmOnGCP {
		return nil, nil, ErrUntrustedPlatform
	}

	// Connecting to ALTS handshaker service.
	hsConn, err := service.Dial()
	if err != nil {
		return nil, nil, err
	}
	// Do not close hsConn since it is shared with other handshakes.

	// Possible context leak:
	// The cancel function for the child context we create will only be
	// called a non-nil error is returned.
	var cancel context.CancelFunc
	ctx, cancel = context.WithCancel(ctx)
	defer func() {
		if err != nil {
			cancel()
		}
	}()

	opts := handshaker.DefaultClientHandshakerOptions()
	opts.TargetServiceAccounts = g.accounts
	opts.RPCVersions = &altspb.RpcProtocolVersions{
		MaxRpcVersion: maxRPCVersion,
		MinRpcVersion: minRPCVersion,
	}
	chs, err := handshaker.NewClientHandshaker(ctx, hsConn, rawConn, opts)
	defer func() {
		if err != nil {
			chs.Close()
		}
	}()
	if err != nil {
		return nil, nil, err
	}
	secConn, authInfo, err := chs.ClientHandshake(ctx)
	if err != nil {
		return nil, nil, err
	}
	altsAuthInfo, ok := authInfo.(AuthInfo)
	if !ok {
		return nil, nil, errors.New("client-side auth info is not of type alts.AuthInfo")
	}
	match, _ := checkRPCVersions(opts.RPCVersions, altsAuthInfo.PeerRPCVersions())
	if !match {
		return nil, nil, fmt.Errorf("server-side RPC versions are not compatible with this client, local versions: %v, peer versions: %v", opts.RPCVersions, altsAuthInfo.PeerRPCVersions())
	}
	return secConn, authInfo, nil
}

// ServerHandshake implements the server side ALTS handshaker.
func (g *altsTC) ServerHandshake(rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) {
	if !*enableUntrustedALTS && !vmOnGCP {
		return nil, nil, ErrUntrustedPlatform
	}
	// Connecting to ALTS handshaker service.
	hsConn, err := service.Dial()
	if err != nil {
		return nil, nil, err
	}
	// Do not close hsConn since it's shared with other handshakes.

	ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
	defer cancel()
	opts := handshaker.DefaultServerHandshakerOptions()
	opts.RPCVersions = &altspb.RpcProtocolVersions{
		MaxRpcVersion: maxRPCVersion,
		MinRpcVersion: minRPCVersion,
	}
	shs, err := handshaker.NewServerHandshaker(ctx, hsConn, rawConn, opts)
	defer func() {
		if err != nil {
			shs.Close()
		}
	}()
	if err != nil {
		return nil, nil, err
	}
	secConn, authInfo, err := shs.ServerHandshake(ctx)
	if err != nil {
		return nil, nil, err
	}
	altsAuthInfo, ok := authInfo.(AuthInfo)
	if !ok {
		return nil, nil, errors.New("server-side auth info is not of type alts.AuthInfo")
	}
	match, _ := checkRPCVersions(opts.RPCVersions, altsAuthInfo.PeerRPCVersions())
	if !match {
		return nil, nil, fmt.Errorf("client-side RPC versions is not compatible with this server, local versions: %v, peer versions: %v", opts.RPCVersions, altsAuthInfo.PeerRPCVersions())
	}
	return secConn, authInfo, nil
}

func (g *altsTC) Info() credentials.ProtocolInfo {
	return *g.info
}

func (g *altsTC) Clone() credentials.TransportCredentials {
	info := *g.info
	return &altsTC{
		info: &info,
	}
}

func (g *altsTC) OverrideServerName(serverNameOverride string) error {
	g.info.ServerName = serverNameOverride
	return nil
}

// compareRPCVersion returns 0 if v1 == v2, 1 if v1 > v2 and -1 if v1 < v2.
func compareRPCVersions(v1, v2 *altspb.RpcProtocolVersions_Version) int {
	switch {
	case v1.GetMajor() > v2.GetMajor(),
		v1.GetMajor() == v2.GetMajor() && v1.GetMinor() > v2.GetMinor():
		return 1
	case v1.GetMajor() < v2.GetMajor(),
		v1.GetMajor() == v2.GetMajor() && v1.GetMinor() < v2.GetMinor():
		return -1
	}
	return 0
}

// checkRPCVersions performs a version check between local and peer rpc protocol
// versions. This function returns true if the check passes which means both
// parties agreed on a common rpc protocol to use, and false otherwise. The
// function also returns the highest common RPC protocol version both parties
// agreed on.
func checkRPCVersions(local, peer *altspb.RpcProtocolVersions) (bool, *altspb.RpcProtocolVersions_Version) {
	if local == nil || peer == nil {
		grpclog.Error("invalid checkRPCVersions argument, either local or peer is nil.")
		return false, nil
	}

	// maxCommonVersion is MIN(local.max, peer.max).
	maxCommonVersion := local.GetMaxRpcVersion()
	if compareRPCVersions(local.GetMaxRpcVersion(), peer.GetMaxRpcVersion()) > 0 {
		maxCommonVersion = peer.GetMaxRpcVersion()
	}

	// minCommonVersion is MAX(local.min, peer.min).
	minCommonVersion := peer.GetMinRpcVersion()
	if compareRPCVersions(local.GetMinRpcVersion(), peer.GetMinRpcVersion()) > 0 {
		minCommonVersion = local.GetMinRpcVersion()
	}

	if compareRPCVersions(maxCommonVersion, minCommonVersion) < 0 {
		return false, nil
	}
	return true, maxCommonVersion
}
<commit_msg>credentials/alts: Remove the enable_untrusted_alts flag (#1931)<commit_after>/*
 *
 * Copyright 2018 gRPC authors.
 *
 * 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 alts implements the ALTS credential support by gRPC library, which
// encapsulates all the state needed by a client to authenticate with a server
// using ALTS and make various assertions, e.g., about the client's identity,
// role, or whether it is authorized to make a particular call.
// This package is experimental.
package alts

import (
	"errors"
	"fmt"
	"net"
	"sync"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/credentials/alts/core"
	"google.golang.org/grpc/credentials/alts/core/handshaker"
	"google.golang.org/grpc/credentials/alts/core/handshaker/service"
	altspb "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp"
	"google.golang.org/grpc/grpclog"
)

const (
	// defaultTimeout specifies the server handshake timeout.
	defaultTimeout = 30.0 * time.Second
	// The following constants specify the minimum and maximum acceptable
	// protocol versions.
	protocolVersionMaxMajor = 2
	protocolVersionMaxMinor = 1
	protocolVersionMinMajor = 2
	protocolVersionMinMinor = 1
)

var (
	once          sync.Once
	maxRPCVersion = &altspb.RpcProtocolVersions_Version{
		Major: protocolVersionMaxMajor,
		Minor: protocolVersionMaxMinor,
	}
	minRPCVersion = &altspb.RpcProtocolVersions_Version{
		Major: protocolVersionMinMajor,
		Minor: protocolVersionMinMinor,
	}
	// ErrUntrustedPlatform is returned from ClientHandshake and
	// ServerHandshake is running on a platform where the trustworthiness of
	// the handshaker service is not guaranteed.
	ErrUntrustedPlatform = errors.New("untrusted platform")
)

// AuthInfo exposes security information from the ALTS handshake to the
// application. This interface is to be implemented by ALTS. Users should not
// need a brand new implementation of this interface. For situations like
// testing, any new implementation should embed this interface. This allows
// ALTS to add new methods to this interface.
type AuthInfo interface {
	// ApplicationProtocol returns application protocol negotiated for the
	// ALTS connection.
	ApplicationProtocol() string
	// RecordProtocol returns the record protocol negotiated for the ALTS
	// connection.
	RecordProtocol() string
	// SecurityLevel returns the security level of the created ALTS secure
	// channel.
	SecurityLevel() altspb.SecurityLevel
	// PeerServiceAccount returns the peer service account.
	PeerServiceAccount() string
	// LocalServiceAccount returns the local service account.
	LocalServiceAccount() string
	// PeerRPCVersions returns the RPC version supported by the peer.
	PeerRPCVersions() *altspb.RpcProtocolVersions
}

// ClientOptions contains the client-side options of an ALTS channel. These
// options will be passed to the underlying ALTS handshaker.
type ClientOptions struct {
	// TargetServiceAccounts contains a list of expected target service
	// accounts.
	TargetServiceAccounts []string
}

// altsTC is the credentials required for authenticating a connection using ALTS.
// It implements credentials.TransportCredentials interface.
type altsTC struct {
	info     *credentials.ProtocolInfo
	hsAddr   string
	side     core.Side
	accounts []string
}

// NewClientCreds constructs a client-side ALTS TransportCredentials object.
func NewClientCreds(opts *ClientOptions) credentials.TransportCredentials {
	return newALTS(core.ClientSide, opts.TargetServiceAccounts)
}

// NewServerCreds constructs a server-side ALTS TransportCredentials object.
func NewServerCreds() credentials.TransportCredentials {
	return newALTS(core.ServerSide, nil)
}

func newALTS(side core.Side, accounts []string) credentials.TransportCredentials {
	once.Do(func() {
		vmOnGCP = isRunningOnGCP()
	})

	return &altsTC{
		info: &credentials.ProtocolInfo{
			SecurityProtocol: "alts",
			SecurityVersion:  "1.0",
		},
		side:     side,
		accounts: accounts,
	}
}

// ClientHandshake implements the client side handshake protocol.
func (g *altsTC) ClientHandshake(ctx context.Context, addr string, rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) {
	if !vmOnGCP {
		return nil, nil, ErrUntrustedPlatform
	}

	// Connecting to ALTS handshaker service.
	hsConn, err := service.Dial()
	if err != nil {
		return nil, nil, err
	}
	// Do not close hsConn since it is shared with other handshakes.

	// Possible context leak:
	// The cancel function for the child context we create will only be
	// called a non-nil error is returned.
	var cancel context.CancelFunc
	ctx, cancel = context.WithCancel(ctx)
	defer func() {
		if err != nil {
			cancel()
		}
	}()

	opts := handshaker.DefaultClientHandshakerOptions()
	opts.TargetServiceAccounts = g.accounts
	opts.RPCVersions = &altspb.RpcProtocolVersions{
		MaxRpcVersion: maxRPCVersion,
		MinRpcVersion: minRPCVersion,
	}
	chs, err := handshaker.NewClientHandshaker(ctx, hsConn, rawConn, opts)
	defer func() {
		if err != nil {
			chs.Close()
		}
	}()
	if err != nil {
		return nil, nil, err
	}
	secConn, authInfo, err := chs.ClientHandshake(ctx)
	if err != nil {
		return nil, nil, err
	}
	altsAuthInfo, ok := authInfo.(AuthInfo)
	if !ok {
		return nil, nil, errors.New("client-side auth info is not of type alts.AuthInfo")
	}
	match, _ := checkRPCVersions(opts.RPCVersions, altsAuthInfo.PeerRPCVersions())
	if !match {
		return nil, nil, fmt.Errorf("server-side RPC versions are not compatible with this client, local versions: %v, peer versions: %v", opts.RPCVersions, altsAuthInfo.PeerRPCVersions())
	}
	return secConn, authInfo, nil
}

// ServerHandshake implements the server side ALTS handshaker.
func (g *altsTC) ServerHandshake(rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) {
	if !vmOnGCP {
		return nil, nil, ErrUntrustedPlatform
	}
	// Connecting to ALTS handshaker service.
	hsConn, err := service.Dial()
	if err != nil {
		return nil, nil, err
	}
	// Do not close hsConn since it's shared with other handshakes.

	ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
	defer cancel()
	opts := handshaker.DefaultServerHandshakerOptions()
	opts.RPCVersions = &altspb.RpcProtocolVersions{
		MaxRpcVersion: maxRPCVersion,
		MinRpcVersion: minRPCVersion,
	}
	shs, err := handshaker.NewServerHandshaker(ctx, hsConn, rawConn, opts)
	defer func() {
		if err != nil {
			shs.Close()
		}
	}()
	if err != nil {
		return nil, nil, err
	}
	secConn, authInfo, err := shs.ServerHandshake(ctx)
	if err != nil {
		return nil, nil, err
	}
	altsAuthInfo, ok := authInfo.(AuthInfo)
	if !ok {
		return nil, nil, errors.New("server-side auth info is not of type alts.AuthInfo")
	}
	match, _ := checkRPCVersions(opts.RPCVersions, altsAuthInfo.PeerRPCVersions())
	if !match {
		return nil, nil, fmt.Errorf("client-side RPC versions is not compatible with this server, local versions: %v, peer versions: %v", opts.RPCVersions, altsAuthInfo.PeerRPCVersions())
	}
	return secConn, authInfo, nil
}

func (g *altsTC) Info() credentials.ProtocolInfo {
	return *g.info
}

func (g *altsTC) Clone() credentials.TransportCredentials {
	info := *g.info
	return &altsTC{
		info: &info,
	}
}

func (g *altsTC) OverrideServerName(serverNameOverride string) error {
	g.info.ServerName = serverNameOverride
	return nil
}

// compareRPCVersion returns 0 if v1 == v2, 1 if v1 > v2 and -1 if v1 < v2.
func compareRPCVersions(v1, v2 *altspb.RpcProtocolVersions_Version) int {
	switch {
	case v1.GetMajor() > v2.GetMajor(),
		v1.GetMajor() == v2.GetMajor() && v1.GetMinor() > v2.GetMinor():
		return 1
	case v1.GetMajor() < v2.GetMajor(),
		v1.GetMajor() == v2.GetMajor() && v1.GetMinor() < v2.GetMinor():
		return -1
	}
	return 0
}

// checkRPCVersions performs a version check between local and peer rpc protocol
// versions. This function returns true if the check passes which means both
// parties agreed on a common rpc protocol to use, and false otherwise. The
// function also returns the highest common RPC protocol version both parties
// agreed on.
func checkRPCVersions(local, peer *altspb.RpcProtocolVersions) (bool, *altspb.RpcProtocolVersions_Version) {
	if local == nil || peer == nil {
		grpclog.Error("invalid checkRPCVersions argument, either local or peer is nil.")
		return false, nil
	}

	// maxCommonVersion is MIN(local.max, peer.max).
	maxCommonVersion := local.GetMaxRpcVersion()
	if compareRPCVersions(local.GetMaxRpcVersion(), peer.GetMaxRpcVersion()) > 0 {
		maxCommonVersion = peer.GetMaxRpcVersion()
	}

	// minCommonVersion is MAX(local.min, peer.min).
	minCommonVersion := peer.GetMinRpcVersion()
	if compareRPCVersions(local.GetMinRpcVersion(), peer.GetMinRpcVersion()) > 0 {
		minCommonVersion = local.GetMinRpcVersion()
	}

	if compareRPCVersions(maxCommonVersion, minCommonVersion) < 0 {
		return false, nil
	}
	return true, maxCommonVersion
}
<|endoftext|>


<commit_before>package credhub

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"sync"

	"code.cloudfoundry.org/lager"

	"github.com/cloudfoundry-incubator/credhub-cli/credhub"
	"github.com/cloudfoundry-incubator/credhub-cli/credhub/auth"
	"github.com/concourse/atc/creds"
)

type CredHubManager struct {
	URL string `long:"url" description:"CredHub server address used to access secrets."`

	PathPrefix string `long:"path-prefix" default:"/concourse" description:"Path under which to namespace credential lookup."`

	TLS TLS
	UAA UAA
}

type TLS struct {
	CACerts    []string `long:"ca-cert"              description:"Paths to PEM-encoded CA cert files to use to verify the CredHub server SSL cert."`
	ClientCert string   `long:"client-cert"          description:"Path to the client certificate for mutual TLS authorization."`
	ClientKey  string   `long:"client-key"           description:"Path to the client private key for mutual TLS authorization."`
	Insecure   bool     `long:"insecure-skip-verify" description:"Enable insecure SSL verification."`
}

type UAA struct {
	ClientId     string `long:"client-id"     description:"Client ID for CredHub authorization."`
	ClientSecret string `long:"client-secret" description:"Client secret for CredHub authorization."`
}

func (manager *CredHubManager) MarshalJSON() ([]byte, error) {
	return json.Marshal(&map[string]interface{}{
		"url":           manager.URL,
		"path_prefix":   manager.PathPrefix,
		"ca_certs":      manager.TLS.CACerts,
		"uaa_client_id": manager.UAA.ClientId,
	})
}

func (manager CredHubManager) IsConfigured() bool {
	return manager.URL != "" ||
		manager.UAA.ClientId != "" ||
		manager.UAA.ClientSecret != "" ||
		len(manager.TLS.CACerts) != 0 ||
		manager.TLS.ClientCert != "" ||
		manager.TLS.ClientKey != ""
}

func (manager CredHubManager) Validate() error {
	parsedUrl, err := url.Parse(manager.URL)
	if err != nil {
		return fmt.Errorf("invalid URL: %s", err)
	}

	// "foo" will parse without error (as a Path, with an empty Host)
	// so we'll do a few additional sanity checks that this is a valid URL
	if parsedUrl.Host == "" || !(parsedUrl.Scheme == "http" || parsedUrl.Scheme == "https") {
		return fmt.Errorf("invalid URL (must be http or https)")
	}

	return nil
}

func (manager CredHubManager) NewVariablesFactory(logger lager.Logger) (creds.VariablesFactory, error) {
	var options []credhub.Option

	if manager.TLS.Insecure {
		options = append(options, credhub.SkipTLSValidation(true))
	}

	caCerts := []string{}
	for _, cert := range manager.TLS.CACerts {
		contents, err := ioutil.ReadFile(cert)
		if err != nil {
			return nil, err
		}

		caCerts = append(caCerts, string(contents))
	}

	if len(caCerts) > 0 {
		options = append(options, credhub.CaCerts(caCerts...))
	}

	if manager.UAA.ClientId != "" && manager.UAA.ClientSecret != "" {
		options = append(options, credhub.Auth(auth.UaaClientCredentials(
			manager.UAA.ClientId,
			manager.UAA.ClientSecret,
		)))
	}

	if manager.TLS.ClientCert != "" && manager.TLS.ClientKey != "" {
		options = append(options, credhub.ClientCert(manager.TLS.ClientCert, manager.TLS.ClientKey))
	}

	return NewCredHubFactory(logger, newLazyCredhub(manager.URL, options), manager.PathPrefix), nil
}

type lazyCredhub struct {
	url     string
	options []credhub.Option
	credhub *credhub.CredHub
}

var credhubInstance *credhub.CredHub
var credhubOnce = &sync.Once{}

func newLazyCredhub(url string, options []credhub.Option) *lazyCredhub {
	return &lazyCredhub{
		url:     url,
		options: options,
	}
}

func (lc lazyCredhub) CredHub() (*credhub.CredHub, error) {
	if lc.credhub != nil {
		return lc.credhub, nil
	}

	var err error
	credhubOnce.Do(func() {
		credhubInstance, err = credhub.New(lc.url, lc.options...)
	})
	if err != nil {
		return nil, err
	}

	lc.credhub = credhubInstance

	return lc.credhub, nil
}
<commit_msg>Fix issue #2300. lazyCredhub.Credhub() did not receive a pointer, so was not able to mutate itself.<commit_after>package credhub

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"sync"

	"code.cloudfoundry.org/lager"

	"github.com/cloudfoundry-incubator/credhub-cli/credhub"
	"github.com/cloudfoundry-incubator/credhub-cli/credhub/auth"
	"github.com/concourse/atc/creds"
)

type CredHubManager struct {
	URL string `long:"url" description:"CredHub server address used to access secrets."`

	PathPrefix string `long:"path-prefix" default:"/concourse" description:"Path under which to namespace credential lookup."`

	TLS TLS
	UAA UAA
}

type TLS struct {
	CACerts    []string `long:"ca-cert"              description:"Paths to PEM-encoded CA cert files to use to verify the CredHub server SSL cert."`
	ClientCert string   `long:"client-cert"          description:"Path to the client certificate for mutual TLS authorization."`
	ClientKey  string   `long:"client-key"           description:"Path to the client private key for mutual TLS authorization."`
	Insecure   bool     `long:"insecure-skip-verify" description:"Enable insecure SSL verification."`
}

type UAA struct {
	ClientId     string `long:"client-id"     description:"Client ID for CredHub authorization."`
	ClientSecret string `long:"client-secret" description:"Client secret for CredHub authorization."`
}

func (manager *CredHubManager) MarshalJSON() ([]byte, error) {
	return json.Marshal(&map[string]interface{}{
		"url":           manager.URL,
		"path_prefix":   manager.PathPrefix,
		"ca_certs":      manager.TLS.CACerts,
		"uaa_client_id": manager.UAA.ClientId,
	})
}

func (manager CredHubManager) IsConfigured() bool {
	return manager.URL != "" ||
		manager.UAA.ClientId != "" ||
		manager.UAA.ClientSecret != "" ||
		len(manager.TLS.CACerts) != 0 ||
		manager.TLS.ClientCert != "" ||
		manager.TLS.ClientKey != ""
}

func (manager CredHubManager) Validate() error {
	parsedUrl, err := url.Parse(manager.URL)
	if err != nil {
		return fmt.Errorf("invalid URL: %s", err)
	}

	// "foo" will parse without error (as a Path, with an empty Host)
	// so we'll do a few additional sanity checks that this is a valid URL
	if parsedUrl.Host == "" || !(parsedUrl.Scheme == "http" || parsedUrl.Scheme == "https") {
		return fmt.Errorf("invalid URL (must be http or https)")
	}

	return nil
}

func (manager CredHubManager) NewVariablesFactory(logger lager.Logger) (creds.VariablesFactory, error) {
	var options []credhub.Option

	if manager.TLS.Insecure {
		options = append(options, credhub.SkipTLSValidation(true))
	}

	caCerts := []string{}
	for _, cert := range manager.TLS.CACerts {
		contents, err := ioutil.ReadFile(cert)
		if err != nil {
			return nil, err
		}

		caCerts = append(caCerts, string(contents))
	}

	if len(caCerts) > 0 {
		options = append(options, credhub.CaCerts(caCerts...))
	}

	if manager.UAA.ClientId != "" && manager.UAA.ClientSecret != "" {
		options = append(options, credhub.Auth(auth.UaaClientCredentials(
			manager.UAA.ClientId,
			manager.UAA.ClientSecret,
		)))
	}

	if manager.TLS.ClientCert != "" && manager.TLS.ClientKey != "" {
		options = append(options, credhub.ClientCert(manager.TLS.ClientCert, manager.TLS.ClientKey))
	}

	return NewCredHubFactory(logger, newLazyCredhub(manager.URL, options), manager.PathPrefix), nil
}

type lazyCredhub struct {
	url     string
	options []credhub.Option
	credhub *credhub.CredHub
	mu      sync.Mutex
}

func newLazyCredhub(url string, options []credhub.Option) *lazyCredhub {
	return &lazyCredhub{
		url:     url,
		options: options,
	}
}

func (lc *lazyCredhub) CredHub() (*credhub.CredHub, error) {
	lc.mu.Lock()
	defer lc.mu.Unlock()
	if lc.credhub != nil {
		return lc.credhub, nil
	}

	ch, err := credhub.New(lc.url, lc.options...)
	if err != nil {
		return nil, err
	}

	lc.credhub = ch

	return lc.credhub, nil
}
<|endoftext|>


<commit_before>package cryptfs

// Filename encryption / decryption function

import (
	"crypto/cipher"
	"crypto/aes"
	"fmt"
	"strings"
	"encoding/base64"
	"errors"
)

const (
	ENCRYPT = true
	DECRYPT = false
)

// DecryptName - decrypt filename
func (be *CryptFS) decryptName(cipherName string) (string, error) {

	bin, err := base64.URLEncoding.DecodeString(cipherName)
	if err != nil {
		return "", err
	}

	if len(bin) % aes.BlockSize != 0 {
		return "", errors.New(fmt.Sprintf("Name len=%d is not a multiple of 16", len(bin)))
	}

	iv := make([]byte, aes.BlockSize) // TODO ?
	cbc := cipher.NewCBCDecrypter(be.blockCipher, iv)
	cbc.CryptBlocks(bin, bin)

	bin, err = be.unPad16(bin)
	if err != nil {
		return "", err
	}

	plain := string(bin)
	return plain, err
}

// EncryptName - encrypt filename
func (be *CryptFS) encryptName(plainName string) string {

	bin := []byte(plainName)
	bin = be.pad16(bin)

	iv := make([]byte, 16) // TODO ?
	cbc := cipher.NewCBCEncrypter(be.blockCipher, iv)
	cbc.CryptBlocks(bin, bin)

	cipherName64 := base64.URLEncoding.EncodeToString(bin)
	return cipherName64
}

// TranslatePath - encrypt or decrypt path. Just splits the string on "/"
// and hands the parts to EncryptName() / DecryptName()
func (be *CryptFS) translatePath(path string, op bool) (string, error) {
	var err error

	// Empty string means root directory
	if path == "" {
		return path, err
	}

	// Run operation on each path component
	var translatedParts []string
	parts := strings.Split(path, "/")
	for _, part := range parts {
		if part == "" {
			// This happens on "/foo/bar/" on the front and on the end.
			// Don't panic.
			translatedParts = append(translatedParts, "")
			continue
		}
		var newPart string
		if op == ENCRYPT {
			newPart = be.encryptName(part)
		} else {
			newPart, err = be.decryptName(part)
			if err != nil {
				return "", err
			}
		}
		translatedParts = append(translatedParts, newPart)
	}

	return strings.Join(translatedParts, "/"), err
}

// EncryptPath - encrypt filename or path. Just hands it to TranslatePath().
func (be *CryptFS) EncryptPath(path string) string {
	newPath, _ := be.translatePath(path, ENCRYPT)
	return newPath
}

// DecryptPath - decrypt filename or path. Just hands it to TranslatePath().
func (be *CryptFS) DecryptPath(path string) (string, error) {
	return be.translatePath(path, DECRYPT)
}

// pad16 - pad filename to 16 byte blocks using standard PKCS#7 padding
// https://tools.ietf.org/html/rfc5652#section-6.3
func (be *CryptFS) pad16(orig []byte) (padded []byte) {
	oldLen := len(orig)
	if oldLen == 0 {
		panic("Padding zero-length string makes no sense")
	}
	padLen := aes.BlockSize - oldLen % aes.BlockSize
	if padLen == 0 {
		padLen = aes.BlockSize
	}
	newLen := oldLen + padLen
	padded = make([]byte, newLen)
	copy(padded, orig)
	padByte := byte(padLen)
	for i := oldLen; i < newLen; i++ {
		padded[i] = padByte
	}
	return padded
}

// unPad16 - remove padding
func (be *CryptFS) unPad16(orig []byte) ([]byte, error) {
	oldLen := len(orig)
	if oldLen % aes.BlockSize != 0 {
		return nil, errors.New("Unaligned size")
	}
	// The last byte is always a padding byte
	padByte := orig[oldLen -1]
	// The padding byte's value is the padding length
	padLen := int(padByte)
	// Padding must be at least 1 byte
	if padLen <= 0 {
		return nil, errors.New("Padding cannot be zero-length")
	}
	// Larger paddings make no sense
	if padLen > aes.BlockSize {
		return nil, errors.New("Padding cannot be larger than 16")
	}
	// All padding bytes must be identical
	for i := oldLen - padLen; i < oldLen; i++ {
		if orig[i] != padByte {
			return nil, errors.New(fmt.Sprintf("Padding byte at i=%d is invalid", i))
		}
	}
	newLen := oldLen - padLen
	// Padding an empty string makes no sense
	if newLen == 0 {
		return nil, errors.New("Unpadded length is zero")
	}
	return orig[0:newLen], nil
}
<commit_msg>symlink encryption: pass ".." and "." through unchanged<commit_after>package cryptfs

// Filename encryption / decryption function

import (
	"crypto/cipher"
	"crypto/aes"
	"fmt"
	"strings"
	"encoding/base64"
	"errors"
)

const (
	ENCRYPT = true
	DECRYPT = false
)

// DecryptName - decrypt filename
func (be *CryptFS) decryptName(cipherName string) (string, error) {

	// Make sure relative symlinks still work after encryption
	// by passing these trough unchanged
	if cipherName == "." || cipherName == ".." {
		return cipherName, nil
	}

	bin, err := base64.URLEncoding.DecodeString(cipherName)
	if err != nil {
		return "", err
	}

	if len(bin) % aes.BlockSize != 0 {
		return "", errors.New(fmt.Sprintf("Name len=%d is not a multiple of 16", len(bin)))
	}

	iv := make([]byte, aes.BlockSize) // TODO ?
	cbc := cipher.NewCBCDecrypter(be.blockCipher, iv)
	cbc.CryptBlocks(bin, bin)

	bin, err = be.unPad16(bin)
	if err != nil {
		return "", err
	}

	plain := string(bin)
	return plain, err
}

// EncryptName - encrypt filename
func (be *CryptFS) encryptName(plainName string) string {

	// Make sure relative symlinks still work after encryption
	// by passing these trough unchanged
	if plainName == "." || plainName == ".." {
		return plainName
	}

	bin := []byte(plainName)
	bin = be.pad16(bin)

	iv := make([]byte, 16) // TODO ?
	cbc := cipher.NewCBCEncrypter(be.blockCipher, iv)
	cbc.CryptBlocks(bin, bin)

	cipherName64 := base64.URLEncoding.EncodeToString(bin)
	return cipherName64
}

// TranslatePath - encrypt or decrypt path. Just splits the string on "/"
// and hands the parts to EncryptName() / DecryptName()
func (be *CryptFS) translatePath(path string, op bool) (string, error) {
	var err error

	// Empty string means root directory
	if path == "" {
		return path, err
	}

	// Run operation on each path component
	var translatedParts []string
	parts := strings.Split(path, "/")
	for _, part := range parts {
		if part == "" {
			// This happens on "/foo/bar/" on the front and on the end.
			// Don't panic.
			translatedParts = append(translatedParts, "")
			continue
		}
		var newPart string
		if op == ENCRYPT {
			newPart = be.encryptName(part)
		} else {
			newPart, err = be.decryptName(part)
			if err != nil {
				return "", err
			}
		}
		translatedParts = append(translatedParts, newPart)
	}

	return strings.Join(translatedParts, "/"), err
}

// EncryptPath - encrypt filename or path. Just hands it to TranslatePath().
func (be *CryptFS) EncryptPath(path string) string {
	newPath, _ := be.translatePath(path, ENCRYPT)
	return newPath
}

// DecryptPath - decrypt filename or path. Just hands it to TranslatePath().
func (be *CryptFS) DecryptPath(path string) (string, error) {
	return be.translatePath(path, DECRYPT)
}

// pad16 - pad filename to 16 byte blocks using standard PKCS#7 padding
// https://tools.ietf.org/html/rfc5652#section-6.3
func (be *CryptFS) pad16(orig []byte) (padded []byte) {
	oldLen := len(orig)
	if oldLen == 0 {
		panic("Padding zero-length string makes no sense")
	}
	padLen := aes.BlockSize - oldLen % aes.BlockSize
	if padLen == 0 {
		padLen = aes.BlockSize
	}
	newLen := oldLen + padLen
	padded = make([]byte, newLen)
	copy(padded, orig)
	padByte := byte(padLen)
	for i := oldLen; i < newLen; i++ {
		padded[i] = padByte
	}
	return padded
}

// unPad16 - remove padding
func (be *CryptFS) unPad16(orig []byte) ([]byte, error) {
	oldLen := len(orig)
	if oldLen % aes.BlockSize != 0 {
		return nil, errors.New("Unaligned size")
	}
	// The last byte is always a padding byte
	padByte := orig[oldLen -1]
	// The padding byte's value is the padding length
	padLen := int(padByte)
	// Padding must be at least 1 byte
	if padLen <= 0 {
		return nil, errors.New("Padding cannot be zero-length")
	}
	// Larger paddings make no sense
	if padLen > aes.BlockSize {
		return nil, errors.New("Padding cannot be larger than 16")
	}
	// All padding bytes must be identical
	for i := oldLen - padLen; i < oldLen; i++ {
		if orig[i] != padByte {
			return nil, errors.New(fmt.Sprintf("Padding byte at i=%d is invalid", i))
		}
	}
	newLen := oldLen - padLen
	// Padding an empty string makes no sense
	if newLen == 0 {
		return nil, errors.New("Unpadded length is zero")
	}
	return orig[0:newLen], nil
}
<|endoftext|>


<commit_before>package libkbfs

import (
	"sync"

	"github.com/eapache/channels"
)

const (
	defaultInfiniteBufferSize int = 0
)

// infiniteChannelWrapper is a wrapper to allow us to select on sending to an
// infinite channel without fearing a panic when we Close() it.
type infiniteChannelWrapper struct {
	*channels.InfiniteChannel
	input        chan interface{}
	shutdownOnce sync.Once
	shutdownCh   chan struct{}
}

var _ channels.Channel = (*infiniteChannelWrapper)(nil)

func newInfiniteChannelWrapper() *infiniteChannelWrapper {
	ch := &infiniteChannelWrapper{
		InfiniteChannel: channels.NewInfiniteChannel(),
		input:           make(chan interface{}, defaultInfiniteBufferSize),
		shutdownCh:      make(chan struct{}),
	}
	go ch.run()
	return ch
}

func (ch *infiniteChannelWrapper) run() {
	for {
		select {
		case next := <-ch.input:
			ch.InfiniteChannel.In() <- next
		case <-ch.shutdownCh:
			ch.InfiniteChannel.Close()
			return
		}
	}
}

func (ch *infiniteChannelWrapper) In() chan<- interface{} {
	return ch.input
}

func (ch *infiniteChannelWrapper) Close() {
	ch.shutdownOnce.Do(func() {
		close(ch.shutdownCh)
	})
}
<commit_msg>channels: Fix copyright header.<commit_after>// Copyright 2017 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"sync"

	"github.com/eapache/channels"
)

const (
	defaultInfiniteBufferSize int = 0
)

// infiniteChannelWrapper is a wrapper to allow us to select on sending to an
// infinite channel without fearing a panic when we Close() it.
type infiniteChannelWrapper struct {
	*channels.InfiniteChannel
	input        chan interface{}
	shutdownOnce sync.Once
	shutdownCh   chan struct{}
}

var _ channels.Channel = (*infiniteChannelWrapper)(nil)

func newInfiniteChannelWrapper() *infiniteChannelWrapper {
	ch := &infiniteChannelWrapper{
		InfiniteChannel: channels.NewInfiniteChannel(),
		input:           make(chan interface{}, defaultInfiniteBufferSize),
		shutdownCh:      make(chan struct{}),
	}
	go ch.run()
	return ch
}

func (ch *infiniteChannelWrapper) run() {
	for {
		select {
		case next := <-ch.input:
			ch.InfiniteChannel.In() <- next
		case <-ch.shutdownCh:
			ch.InfiniteChannel.Close()
			return
		}
	}
}

func (ch *infiniteChannelWrapper) In() chan<- interface{} {
	return ch.input
}

func (ch *infiniteChannelWrapper) Close() {
	ch.shutdownOnce.Do(func() {
		close(ch.shutdownCh)
	})
}
<|endoftext|>


<commit_before>package main

import (
	"errors"

	"github.com/Knetic/govaluate"
	"github.com/rs/zerolog/log"
)

// WhenEvaluator evaluates when clauses from the manifest
type WhenEvaluator interface {
	Evaluate(string, string, map[string]interface{}) (bool, error)
	GetParameters() map[string]interface{}
}

type whenEvaluatorImpl struct {
	envvarHelper EnvvarHelper
}

// NewWhenEvaluator returns a new WhenEvaluator
func NewWhenEvaluator(envvarHelper EnvvarHelper) WhenEvaluator {
	return &whenEvaluatorImpl{
		envvarHelper: envvarHelper,
	}
}

func (we *whenEvaluatorImpl) Evaluate(pipelineName, input string, parameters map[string]interface{}) (result bool, err error) {

	if input == "" {
		return false, errors.New("When expression is empty")
	}

	log.Info().Msgf("[%v] Evaluating when expression \"%v\" with parameters \"%v\"", pipelineName, input, parameters)

	expression, err := govaluate.NewEvaluableExpression(input)
	if err != nil {
		return
	}

	r, err := expression.Evaluate(parameters)

	log.Info().Msgf("[%v] Result of when expression \"%v\" is \"%v\"", pipelineName, input, r)

	if result, ok := r.(bool); ok {
		return result, err
	}

	return false, errors.New("Result of evaluating when expression is not of type boolean")
}

func (we *whenEvaluatorImpl) GetParameters() map[string]interface{} {

	parameters := make(map[string]interface{}, 3)
	parameters["branch"] = we.envvarHelper.getEstafetteEnv("ESTAFETTE_GIT_BRANCH")
	parameters["trigger"] = we.envvarHelper.getEstafetteEnv("ESTAFETTE_TRIGGER")
	parameters["status"] = we.envvarHelper.getEstafetteEnv("ESTAFETTE_BUILD_STATUS")
	parameters["action"] = we.envvarHelper.getEstafetteEnv("ESTAFETTE_RELEASE_ACTION")
	parameters["server"] = we.envvarHelper.getCiServer()

	return parameters
}
<commit_msg>expand estafette envvars in when clause<commit_after>package main

import (
	"errors"
	"os"

	"github.com/Knetic/govaluate"
	"github.com/rs/zerolog/log"
)

// WhenEvaluator evaluates when clauses from the manifest
type WhenEvaluator interface {
	Evaluate(string, string, map[string]interface{}) (bool, error)
	GetParameters() map[string]interface{}
}

type whenEvaluatorImpl struct {
	envvarHelper EnvvarHelper
}

// NewWhenEvaluator returns a new WhenEvaluator
func NewWhenEvaluator(envvarHelper EnvvarHelper) WhenEvaluator {
	return &whenEvaluatorImpl{
		envvarHelper: envvarHelper,
	}
}

func (we *whenEvaluatorImpl) Evaluate(pipelineName, input string, parameters map[string]interface{}) (result bool, err error) {

	if input == "" {
		return false, errors.New("When expression is empty")
	}

	log.Info().Msgf("[%v] Evaluating when expression \"%v\" with parameters \"%v\"", pipelineName, input, parameters)

	// replace estafette envvars in when clause
	input = os.Expand(input, we.envvarHelper.getEstafetteEnv)

	expression, err := govaluate.NewEvaluableExpression(input)
	if err != nil {
		return
	}

	r, err := expression.Evaluate(parameters)

	log.Info().Msgf("[%v] Result of when expression \"%v\" is \"%v\"", pipelineName, input, r)

	if result, ok := r.(bool); ok {
		return result, err
	}

	return false, errors.New("Result of evaluating when expression is not of type boolean")
}

func (we *whenEvaluatorImpl) GetParameters() map[string]interface{} {

	parameters := make(map[string]interface{}, 3)
	parameters["branch"] = we.envvarHelper.getEstafetteEnv("ESTAFETTE_GIT_BRANCH")
	parameters["trigger"] = we.envvarHelper.getEstafetteEnv("ESTAFETTE_TRIGGER")
	parameters["status"] = we.envvarHelper.getEstafetteEnv("ESTAFETTE_BUILD_STATUS")
	parameters["action"] = we.envvarHelper.getEstafetteEnv("ESTAFETTE_RELEASE_ACTION")
	parameters["server"] = we.envvarHelper.getCiServer()

	return parameters
}
<|endoftext|>