<commit_before>// Copyright (c) 2013-2016 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package mop

import (
	`github.com/michaeldv/termbox-go`
	`strings`
	`time`
)

// Screen is thin wrapper aroung Termbox library to provide basic display
// capabilities as requied by Mop.
type Screen struct {
	width    int        // Current number of columns.
	height   int        // Current number of rows.
	cleared  bool       // True after the screens gets cleared.
	layout   *Layout    // Pointer to layout (gets created by screen).
	markup   *Markup    // Pointer to markup processor (gets created by screen).
	pausedAt *time.Time // Timestamp of the pause request or nil if none.
}

// Initializes Termbox, creates screen along with layout and markup, and
// calculates current screen dimensions. Once initialized the screen is
// ready for display.
func NewScreen() *Screen {
	if err := termbox.Init(); err != nil {
		panic(err)
	}
	screen := &Screen{}
	screen.layout = NewLayout()
	screen.markup = NewMarkup()

	return screen.Resize()
}

// Close gets called upon program termination to close the Termbox.
func (screen *Screen) Close() *Screen {
	termbox.Close()

	return screen
}

// Resize gets called when the screen is being resized. It recalculates screen
// dimensions and requests to clear the screen on next update.
func (screen *Screen) Resize() *Screen {
	screen.width, screen.height = termbox.Size()
	screen.cleared = false

	return screen
}

// Pause is a toggle function that either creates a timestamp of the pause
// request or resets it to nil.
func (screen *Screen) Pause(pause bool) *Screen {
	if pause {
		screen.pausedAt = new(time.Time)
		*screen.pausedAt = time.Now()
	} else {
		screen.pausedAt = nil
	}

	return screen
}

// Clear makes the entire screen blank using default background color.
func (screen *Screen) Clear() *Screen {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	screen.cleared = true

	return screen
}

// ClearLine erases the contents of the line starting from (x,y) coordinate
// till the end of the line.
func (screen *Screen) ClearLine(x int, y int) *Screen {
	for i := x; i < screen.width; i++ {
		termbox.SetCell(i, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
	}
	termbox.Flush()

	return screen
}

// Draw accepts variable number of arguments and knows how to display the
// market data, stock quotes, current time, and an arbitrary string.
func (screen *Screen) Draw(objects ...interface{}) *Screen {
	if screen.pausedAt != nil {
		defer screen.DrawLine(0, 0, `<right><r>`+screen.pausedAt.Format(`3:04:05pm PST`)+`</r></right>`)
	}
	for _, ptr := range objects {
		switch ptr.(type) {
		case *Market:
			object := ptr.(*Market)
			screen.draw(screen.layout.Market(object.Fetch()))
		case *Quotes:
			object := ptr.(*Quotes)
			screen.draw(screen.layout.Quotes(object.Fetch()))
		case time.Time:
			timestamp := ptr.(time.Time).Format(`3:04:05pm PST`)
			screen.DrawLine(0, 0, `<right>`+timestamp+`</right>`)
		default:
			screen.draw(ptr.(string))
		}
	}

	return screen
}

// DrawLine takes the incoming string, tokenizes it to extract markup
// elements, and displays it all starting at (x,y) location.
func (screen *Screen) DrawLine(x int, y int, str string) {
	start, column := 0, 0

	for _, token := range screen.markup.Tokenize(str) {
		// First check if it's a tag. Tags are eaten up and not displayed.
		if screen.markup.IsTag(token) {
			continue
		}

		// Here comes the actual text: display it one character at a time.
		for i, char := range token {
			if !screen.markup.RightAligned {
				start = x + column
				column++
			} else {
				start = screen.width - len(token) + i
			}
			termbox.SetCell(start, y, char, screen.markup.Foreground, screen.markup.Background)
		}
	}
	termbox.Flush()
}

// Underlying workhorse function that takes multiline string, splits it into
// lines, and displays them row by row.
func (screen *Screen) draw(str string) {
	if !screen.cleared {
		screen.Clear()
	}
	for row, line := range strings.Split(str, "\n") {
		screen.DrawLine(0, row, line)
	}
}
<commit_msg>Using original Termbox-Go<commit_after>// Copyright (c) 2013-2016 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package mop

import (
	`github.com/nsf/termbox-go`
	`strings`
	`time`
)

// Screen is thin wrapper aroung Termbox library to provide basic display
// capabilities as requied by Mop.
type Screen struct {
	width    int        // Current number of columns.
	height   int        // Current number of rows.
	cleared  bool       // True after the screens gets cleared.
	layout   *Layout    // Pointer to layout (gets created by screen).
	markup   *Markup    // Pointer to markup processor (gets created by screen).
	pausedAt *time.Time // Timestamp of the pause request or nil if none.
}

// Initializes Termbox, creates screen along with layout and markup, and
// calculates current screen dimensions. Once initialized the screen is
// ready for display.
func NewScreen() *Screen {
	if err := termbox.Init(); err != nil {
		panic(err)
	}
	screen := &Screen{}
	screen.layout = NewLayout()
	screen.markup = NewMarkup()

	return screen.Resize()
}

// Close gets called upon program termination to close the Termbox.
func (screen *Screen) Close() *Screen {
	termbox.Close()

	return screen
}

// Resize gets called when the screen is being resized. It recalculates screen
// dimensions and requests to clear the screen on next update.
func (screen *Screen) Resize() *Screen {
	screen.width, screen.height = termbox.Size()
	screen.cleared = false

	return screen
}

// Pause is a toggle function that either creates a timestamp of the pause
// request or resets it to nil.
func (screen *Screen) Pause(pause bool) *Screen {
	if pause {
		screen.pausedAt = new(time.Time)
		*screen.pausedAt = time.Now()
	} else {
		screen.pausedAt = nil
	}

	return screen
}

// Clear makes the entire screen blank using default background color.
func (screen *Screen) Clear() *Screen {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	screen.cleared = true

	return screen
}

// ClearLine erases the contents of the line starting from (x,y) coordinate
// till the end of the line.
func (screen *Screen) ClearLine(x int, y int) *Screen {
	for i := x; i < screen.width; i++ {
		termbox.SetCell(i, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
	}
	termbox.Flush()

	return screen
}

// Draw accepts variable number of arguments and knows how to display the
// market data, stock quotes, current time, and an arbitrary string.
func (screen *Screen) Draw(objects ...interface{}) *Screen {
	if screen.pausedAt != nil {
		defer screen.DrawLine(0, 0, `<right><r>`+screen.pausedAt.Format(`3:04:05pm PST`)+`</r></right>`)
	}
	for _, ptr := range objects {
		switch ptr.(type) {
		case *Market:
			object := ptr.(*Market)
			screen.draw(screen.layout.Market(object.Fetch()))
		case *Quotes:
			object := ptr.(*Quotes)
			screen.draw(screen.layout.Quotes(object.Fetch()))
		case time.Time:
			timestamp := ptr.(time.Time).Format(`3:04:05pm PST`)
			screen.DrawLine(0, 0, `<right>`+timestamp+`</right>`)
		default:
			screen.draw(ptr.(string))
		}
	}

	return screen
}

// DrawLine takes the incoming string, tokenizes it to extract markup
// elements, and displays it all starting at (x,y) location.
func (screen *Screen) DrawLine(x int, y int, str string) {
	start, column := 0, 0

	for _, token := range screen.markup.Tokenize(str) {
		// First check if it's a tag. Tags are eaten up and not displayed.
		if screen.markup.IsTag(token) {
			continue
		}

		// Here comes the actual text: display it one character at a time.
		for i, char := range token {
			if !screen.markup.RightAligned {
				start = x + column
				column++
			} else {
				start = screen.width - len(token) + i
			}
			termbox.SetCell(start, y, char, screen.markup.Foreground, screen.markup.Background)
		}
	}
	termbox.Flush()
}

// Underlying workhorse function that takes multiline string, splits it into
// lines, and displays them row by row.
func (screen *Screen) draw(str string) {
	if !screen.cleared {
		screen.Clear()
	}
	for row, line := range strings.Split(str, "\n") {
		screen.DrawLine(0, row, line)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"code.google.com/p/go.crypto/openpgp"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/azlyth/mdns"
	"github.com/codegangsta/cli"
	"github.com/howeyc/gopass"
	"github.com/koding/kite"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/user"
	"strconv"
)

// General values
const LogLevel = kite.FATAL

const Author = "Peter Valdez"
const Email = "peter@nycmesh.net"
const Name = "secret"
const Usage = "Send secrets with ease."
const Version = "0.1.0"

var currentUser *user.User
var context *cli.Context
var entity *openpgp.Entity
var entityList openpgp.EntityList
var secretKeyring, publicKeyring string

// Flags
var Flags = []cli.Flag{
	cli.BoolFlag{
		Name:  "verbose",
		Usage: "print verbose output",
	},
}

// Subcommands
var Commands = []cli.Command{
	{
		Name:      "send",
		ShortName: "s",
		Usage:     "Sends a secret",
		Action:    handle(send),
	},
	{
		Name:      "receive",
		ShortName: "r",
		Usage:     "Waits for secrets",
		Action:    handle(receive),
		Flags:     Flags,
	},
}

func handle(f func() error) func(*cli.Context) {
	return func(c *cli.Context) {
		// Store the context globally
		context = c

		// Run the function
		err := f()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	}
}

// Receive subcommand
func receive() error {
	// Decrypt the key we'll be using to decrypt messages
	err := decryptKey()
	if err != nil {
		return errors.New("Unable to decrypt key.")
	}

	// Create and configure the kite
	k := kite.New("secret", Version)
	k.Config.Port = 4321
	k.HandleFunc("secret", secret).DisableAuthentication()
	k.HandleFunc("identify", identify).DisableAuthentication()

	// Prepare the kite
	k.SetLogLevel(LogLevel)
	k.Config.Region = "secret"
	k.Config.Username = "secret"
	k.Config.Environment = "secret"
	if err != nil {
		return err
	}

	// Have the user select the IP address
	ips, err := selectIPs()
	if err != nil {
		return err
	}

	// Register the mdns service
	host, _ := os.Hostname()
	info := []string{"Sharing secrets."}
	service, err := mdns.NewMDNSService(host, "_secret._tcp", "", "", 4321, ips, info)
	if err != nil {
		return err
	}

	server, _ := mdns.NewServer(&mdns.Config{Zone: service})
	defer server.Shutdown()

	// Run the kite
	fmt.Println("\nWaiting for secrets...")
	k.Run()

	return nil
}

func identify(r *kite.Request) (interface{}, error) {
	// Open the file
	buf, err := ioutil.ReadFile(publicKeyring)
	if err != nil {
		return nil, err
	}

	// Encode the contents of the file to base64
	str := base64.StdEncoding.EncodeToString(buf)

	return str, nil
}

func secret(r *kite.Request) (interface{}, error) {
	// Retrieve the encrypted secret
	encrypted := r.Args.One().MustString()

	// Decrypt and print the secret
	decrypted, err := decryptMessage(encrypted)
	if err != nil {
		return nil, err
	}
	fmt.Printf("From %s: %s\n", r.Client.Name, decrypted)

	// Return an acknowledgment
	return "Received.", nil
}

func selectIPs() ([]net.IP, error) {
	// Get the interfaces
	allInterfaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	// Filter out the ones with no addresses
	ifaces := make([]net.Interface, 0)
	for _, iface := range allInterfaces {
		// Get the addresses
		addrs, err := iface.Addrs()
		if err != nil {
			return nil, err
		}

		// The interface is a valid choice if it has addresses
		if len(addrs) > 0 {
			ifaces = append(ifaces, iface)
		}
	}

	// Error if there are no interfaces
	if len(ifaces) == 0 {
		err = errors.New("No interfaces with addresses to listen on.")
		return nil, err
	}

	// Parse the addresses
	choices := make([]net.Interface, len(ifaces))
	for i, iface := range ifaces {
		choices[i] = iface
	}

	// Display the choices
	fmt.Println("= Your network interfaces =")
	for i, choice := range choices {
		// Get addresses
		addrs, err := choice.Addrs()
		if err != nil {
			return nil, err
		}

		// Skip if there are no addresses on this
		if len(ifaces) == 0 {
			err = errors.New("No interfaces to listen on.")
			return nil, err
		}

		// Get the IP
		ips := make([]net.IP, len(addrs))
		for i, addr := range addrs {
			ip, _, err := net.ParseCIDR(addr.String())
			if err != nil {
				return nil, err
			}
			ips[i] = ip
		}

		// Display the addresses
		fmt.Println(strconv.Itoa(i), "-", ips)
	}

	// Gather the user's input
	choice := -1
	for choice < 0 || choice >= len(choices) {
		fmt.Println("\nListen on which? (Enter a number)")
		fmt.Print("> ")
		_, err = fmt.Scanf("%d", &choice)
		if err != nil {
			return nil, err
		}
	}

	// Get the interface addresses
	chosenInterface := choices[choice]
	addrs, err := chosenInterface.Addrs()
	if err != nil {
		return nil, err
	}

	// Convert Addrs to IPs
	ips := make([]net.IP, len(addrs))
	for i, addr := range addrs {
		ip, _, err := net.ParseCIDR(addr.String())
		if err != nil {
			return nil, err
		}
		ips[i] = ip
	}

	return ips, nil
}

func getIPs() ([]net.IP, error) {
	// Get the string interface addresses
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return nil, err
	}

	// Convert them to actual IP objects
	ips := make([]net.IP, 0, 4)
	for _, addr := range addrs {
		ip, _, err := net.ParseCIDR(addr.String())
		if err != nil {
			return nil, err
		}

		ips = append(ips, ip)
	}

	return ips, nil
}

// Send subcommand
func send() error {
	// Retrieve the argument
	if len(context.Args()) != 1 {
		return errors.New("Invalid number of arguments.")
	}
	secret := context.Args().First()

	// Find secret peers on the network
	entriesCh := make(chan *mdns.ServiceEntry, 4)
	mdns.Lookup("_secret._tcp", entriesCh)
	close(entriesCh)
	var e *mdns.ServiceEntry
	for entry := range entriesCh {
		e = entry
	}

	// Create the kite
	k := kite.New(currentUser.Username, Version)
	k.SetLogLevel(LogLevel)

	// Connect to the peer
	client := k.NewClient(fmt.Sprintf("http://%s:%d/kite", e.AddrV4, e.Port))
	client.Dial()

	// Retrieve the public key
	response, _ := client.Tell("identify")
	str := response.MustString()
	buf, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return err
	}
	reader := bytes.NewReader(buf)

	// Send them a secret
	encrypted, err := encryptMessage(reader, secret)
	if err != nil {
		return err
	}
	response, _ = client.Tell("secret", encrypted)
	fmt.Println("Secret sent.")

	return nil
}

func encryptMessage(publicKey io.Reader, str string) (string, error) {
	// Read in public key
	entityList, err := openpgp.ReadKeyRing(publicKey)
	if err != nil {
		return "", err
	}

	// Encrypt string
	buf := new(bytes.Buffer)
	w, err := openpgp.Encrypt(buf, entityList, nil, nil, nil)
	if err != nil {
		return "", err
	}
	_, err = w.Write([]byte(str))
	if err != nil {
		return "", err
	}
	err = w.Close()
	if err != nil {
		return "", err
	}

	// Encode to base64
	bytesp, err := ioutil.ReadAll(buf)
	if err != nil {
		return "", err
	}
	encstr := base64.StdEncoding.EncodeToString(bytesp)

	return encstr, nil
}

func decryptMessage(encstr string) (string, error) {
	// Decode the base64 string
	dec, err := base64.StdEncoding.DecodeString(encstr)
	if err != nil {
		return "", err
	}

	// Decrypt it with the contents of the private key
	md, err := openpgp.ReadMessage(bytes.NewBuffer(dec), entityList, nil, nil)
	if err != nil {
		return "", err
	}
	bytess, err := ioutil.ReadAll(md.UnverifiedBody)
	if err != nil {
		return "", err
	}
	decstr := string(bytess)

	return decstr, nil
}

func decryptKey() error {
	// Open the private key file
	keyringFileBuffer, err := os.Open(secretKeyring)
	if err != nil {
		return err
	}
	defer keyringFileBuffer.Close()
	entityList, err = openpgp.ReadKeyRing(keyringFileBuffer)
	if err != nil {
		return err
	}
	entity = entityList[0]

	// Get the password
	passphrase := os.Getenv("SECRET_PASSWORD")
	passphrasebyte := []byte(passphrase)
	if passphrase == "" {
		fmt.Printf("Enter your PGP key password: ")
		passphrasebyte = gopass.GetPasswd()
		fmt.Println()
	}

	// Decrypt the key and subkeys
	err = entity.PrivateKey.Decrypt(passphrasebyte)
	if err != nil {
		return err
	}
	for _, subkey := range entity.Subkeys {
		err = subkey.PrivateKey.Decrypt(passphrasebyte)
		if err != nil {
			return err
		}
	}

	return nil
}

func main() {
	// Disable the log
	log.SetOutput(ioutil.Discard)

	// Setup the filenames
	currentUser, _ = user.Current()
	prefix := currentUser.HomeDir
	secretKeyring = fmt.Sprintf("%s/.gnupg/secring.gpg", prefix)
	publicKeyring = fmt.Sprintf("%s/.gnupg/pubring.gpg", prefix)

	// Setup the app
	app := cli.NewApp()
	app.Name = Name
	app.Email = Email
	app.Usage = Usage
	app.Author = Author
	app.Version = Version
	app.Commands = Commands

	// Run the app
	app.Run(os.Args)
}
<commit_msg>Automatically select network interface to listen on.<commit_after>package main

import (
	"bytes"
	"code.google.com/p/go.crypto/openpgp"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/azlyth/mdns"
	"github.com/codegangsta/cli"
	"github.com/howeyc/gopass"
	"github.com/koding/kite"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/user"
	"strconv"
	"strings"
)

// General values
const LogLevel = kite.FATAL

const Author = "Peter Valdez"
const Email = "peter@nycmesh.net"
const Name = "secret"
const Usage = "Send secrets with ease."
const Version = "0.1.0"

var currentUser *user.User
var context *cli.Context
var entity *openpgp.Entity
var entityList openpgp.EntityList
var secretKeyring, publicKeyring string

// Convenience
var InternalAddrs []string
var InvalidPrefixes []string

// Flags
var Flags = []cli.Flag{
	cli.BoolFlag{
		Name:  "verbose",
		Usage: "print verbose output",
	},
}

// Subcommands
var Commands = []cli.Command{
	{
		Name:      "send",
		ShortName: "s",
		Usage:     "Sends a secret",
		Action:    handle(send),
	},
	{
		Name:      "receive",
		ShortName: "r",
		Usage:     "Waits for secrets",
		Action:    handle(receive),
		Flags:     Flags,
	},
}

func handle(f func() error) func(*cli.Context) {
	return func(c *cli.Context) {
		// Store the context globally
		context = c

		// Run the function
		err := f()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	}
}

// Receive subcommand
func receive() error {
	// Decrypt the key we'll be using to decrypt messages
	err := decryptKey()
	if err != nil {
		return errors.New("Unable to decrypt key.")
	}

	// Create and configure the kite
	k := kite.New("secret", Version)
	k.Config.Port = 4321
	k.HandleFunc("secret", secret).DisableAuthentication()
	k.HandleFunc("identify", identify).DisableAuthentication()

	// Prepare the kite
	k.SetLogLevel(LogLevel)
	k.Config.Region = "secret"
	k.Config.Username = "secret"
	k.Config.Environment = "secret"
	if err != nil {
		return err
	}

	// Get the interface and IPs that'll be used
	iface, err := autoSelectInterface()
	if err != nil {
		return err
	}
	ips, err := getIPsFromInterface(iface, true)
	if err != nil {
		return err
	}

	// Register the mdns service
	host, _ := os.Hostname()
	info := []string{"Sharing secrets."}
	service, err := mdns.NewMDNSService(host, "_secret._tcp", "", "", 4321, ips, info)
	if err != nil {
		return err
	}

	server, _ := mdns.NewServer(&mdns.Config{Zone: service, Iface: &iface})
	defer server.Shutdown()

	// Run the kite
	fmt.Println("Waiting for secrets...")
	k.Run()

	return nil
}

func identify(r *kite.Request) (interface{}, error) {
	// Open the file
	buf, err := ioutil.ReadFile(publicKeyring)
	if err != nil {
		return nil, err
	}

	// Encode the contents of the file to base64
	str := base64.StdEncoding.EncodeToString(buf)

	return str, nil
}

func secret(r *kite.Request) (interface{}, error) {
	// Retrieve the encrypted secret
	encrypted := r.Args.One().MustString()

	// Decrypt and print the secret
	decrypted, err := decryptMessage(encrypted)
	if err != nil {
		return nil, err
	}
	fmt.Printf("From %s: %s\n", r.Client.Name, decrypted)

	// Return an acknowledgment
	return "Received.", nil
}

// Return true if s is prefixed by any of the prefixes
func prefixedByAny(s string, prefixes []string) bool {
	for _, prefix := range prefixes {
		if strings.HasPrefix(s, prefix) {
			return true
		}
	}
	return false
}

func getIPsFromInterface(iface net.Interface, ignoreInternal bool) ([]net.IP, error) {
	// Get the addresses
	addrs, err := iface.Addrs()
	if err != nil {
		return nil, err
	}

	// Get the IPs from the Addrs
	ips := make([]net.IP, 0, len(addrs))
	for _, addr := range addrs {
		// Ignore internal addresses
		if ignoreInternal && prefixedByAny(addr.String(), InternalAddrs) {
			continue
		}

		// Convert to IP
		ip, _, err := net.ParseCIDR(addr.String())
		if err != nil {
			return nil, err
		}
		ips = append(ips, ip)
	}

	return ips, nil
}

func autoSelectInterface() (net.Interface, error) {
	// Get the interfaces
	allInterfaces, err := net.Interfaces()
	if err != nil {
		return net.Interface{}, err
	}

	// Get the list of addressable IPs
	for _, iface := range allInterfaces {
		// Ignore certain interfaces
		if prefixedByAny(iface.Name, InvalidPrefixes) {
			continue
		}

		// Get the interface IPs
		ips, err := getIPsFromInterface(iface, true)
		if err != nil {
			return net.Interface{}, err
		}

		// Return if any valid IPs retrieved
		if len(ips) > 0 {
			return iface, nil
		}
	}

	err = errors.New("Unable to automatically choose an IP address.")
	return net.Interface{}, err
}

func selectIPs() ([]net.IP, error) {
	// Get the interfaces
	allInterfaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	// Filter out the ones with no addresses
	choices := make([]net.Interface, 0, 4)
	for _, iface := range allInterfaces {
		// Get the addresses
		addrs, err := iface.Addrs()
		if err != nil {
			return nil, err
		}

		// The interface is a valid choice if it has addresses
		if len(addrs) > 0 {
			choices = append(choices, iface)
		}
	}

	// Error if there are no interfaces
	if len(choices) == 0 {
		err = errors.New("No interfaces with addresses to listen on.")
		return nil, err
	}

	// Display the choices
	fmt.Println("- Your network interfaces -")
	for i, choice := range choices {
		ips, err := getIPsFromInterface(choice, false)
		if err != nil {
			return nil, err
		}

		fmt.Println(strconv.Itoa(i), "-", choice.Name, ips)
	}

	// Gather the user's input
	choice := -1
	for choice < 0 || choice >= len(choices) {
		fmt.Println("\nListen on which? (Enter a number)")
		fmt.Print("> ")
		_, err = fmt.Scanf("%d", &choice)
		if err != nil {
			return nil, err
		}
	}

	// Get the interface addresses
	ips, err := getIPsFromInterface(choices[choice], false)
	if err != nil {
		return nil, err
	}

	return ips, nil
}

// Send subcommand
func send() error {
	// Retrieve the argument
	if len(context.Args()) != 1 {
		return errors.New("Invalid number of arguments.")
	}
	secret := context.Args().First()

	// Find secret peers on the network
	entriesCh := make(chan *mdns.ServiceEntry, 4)
	mdns.Lookup("_secret._tcp", entriesCh)
	close(entriesCh)
	var e *mdns.ServiceEntry
	for entry := range entriesCh {
		e = entry
	}

	// Create the kite
	k := kite.New(currentUser.Username, Version)
	k.SetLogLevel(LogLevel)

	// Connect to the peer
	client := k.NewClient(fmt.Sprintf("http://%s:%d/kite", e.AddrV4, e.Port))
	client.Dial()

	// Retrieve the public key
	response, _ := client.Tell("identify")
	str := response.MustString()
	buf, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return err
	}
	reader := bytes.NewReader(buf)

	// Send them a secret
	encrypted, err := encryptMessage(reader, secret)
	if err != nil {
		return err
	}
	response, _ = client.Tell("secret", encrypted)
	fmt.Println("Secret sent.")

	return nil
}

func encryptMessage(publicKey io.Reader, str string) (string, error) {
	// Read in public key
	entityList, err := openpgp.ReadKeyRing(publicKey)
	if err != nil {
		return "", err
	}

	// Encrypt string
	buf := new(bytes.Buffer)
	w, err := openpgp.Encrypt(buf, entityList, nil, nil, nil)
	if err != nil {
		return "", err
	}
	_, err = w.Write([]byte(str))
	if err != nil {
		return "", err
	}
	err = w.Close()
	if err != nil {
		return "", err
	}

	// Encode to base64
	bytesp, err := ioutil.ReadAll(buf)
	if err != nil {
		return "", err
	}
	encstr := base64.StdEncoding.EncodeToString(bytesp)

	return encstr, nil
}

func decryptMessage(encstr string) (string, error) {
	// Decode the base64 string
	dec, err := base64.StdEncoding.DecodeString(encstr)
	if err != nil {
		return "", err
	}

	// Decrypt it with the contents of the private key
	md, err := openpgp.ReadMessage(bytes.NewBuffer(dec), entityList, nil, nil)
	if err != nil {
		return "", err
	}
	bytess, err := ioutil.ReadAll(md.UnverifiedBody)
	if err != nil {
		return "", err
	}
	decstr := string(bytess)

	return decstr, nil
}

func decryptKey() error {
	// Open the private key file
	keyringFileBuffer, err := os.Open(secretKeyring)
	if err != nil {
		return err
	}
	defer keyringFileBuffer.Close()
	entityList, err = openpgp.ReadKeyRing(keyringFileBuffer)
	if err != nil {
		return err
	}
	entity = entityList[0]

	// Get the password
	passphrase := os.Getenv("SECRET_PASSWORD")
	passphrasebyte := []byte(passphrase)
	if passphrase == "" {
		fmt.Printf("Enter your PGP key password: ")
		passphrasebyte = gopass.GetPasswd()
		fmt.Println()
	}

	// Decrypt the key and subkeys
	err = entity.PrivateKey.Decrypt(passphrasebyte)
	if err != nil {
		return err
	}
	for _, subkey := range entity.Subkeys {
		err = subkey.PrivateKey.Decrypt(passphrasebyte)
		if err != nil {
			return err
		}
	}

	return nil
}

func main() {
	// Disable the log
	log.SetOutput(ioutil.Discard)

	// Setup the filenames
	currentUser, _ = user.Current()
	prefix := currentUser.HomeDir
	secretKeyring = fmt.Sprintf("%s/.gnupg/secring.gpg", prefix)
	publicKeyring = fmt.Sprintf("%s/.gnupg/pubring.gpg", prefix)

	// Setup the convenience values
	InvalidPrefixes = []string{"docker", "vbox", "awdl"}
	InternalAddrs = []string{"127.0.0.1/8", "fe80::1/64", "::1/128"}

	// Setup the app
	app := cli.NewApp()
	app.Name = Name
	app.Email = Email
	app.Usage = Usage
	app.Author = Author
	app.Version = Version
	app.Commands = Commands

	// Run the app
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package veneur

import (
	"fmt"

	"github.com/Sirupsen/logrus"
	"github.com/getsentry/raven-go"
)

// call inside deferred recover, eg
// defer func() {
// 	ConsumePanic(recover())
// }
// will report panic to sentry, print stack and then repanic (to ensure your program terminates)
func (s *Server) ConsumePanic(err interface{}) {
	if err == nil {
		return
	}

	p := raven.Packet{
		Level:      raven.FATAL,
		ServerName: s.Hostname,
		Interfaces: []raven.Interface{
			// ignore 2 stack frames:
			// - the frame for ConsumePanic itself
			// - the frame for the deferred function that invoked ConsumePanic
			raven.NewStacktrace(2, 3, []string{"main", "github.com/stripe/veneur"}),
		},
	}

	// remember to block, since we're about to re-panic, which will probably terminate
	switch e := err.(type) {
	case error:
		p.Message = e.Error()
	case fmt.Stringer:
		p.Message = e.String()
	default:
		p.Message = fmt.Sprintf("%#v", e)
	}

	_, ch := s.sentry.Capture(&p, nil)
	// we don't want the program to terminate before reporting to sentry
	<-ch

	panic(err)
}

// logrus hook to send error/fatal/panic messages to sentry
type sentryHook struct {
	c        *raven.Client
	hostname string
	lv       []logrus.Level
}

var _ logrus.Hook = sentryHook{}

func (s sentryHook) Levels() []logrus.Level {
	return s.lv
}

func (s sentryHook) Fire(e *logrus.Entry) error {
	p := raven.Packet{
		ServerName: s.hostname,
		Interfaces: []raven.Interface{
			// ignore the stack frames for the Fire function itself
			// the logrus machinery that invoked Fire will also be hidden
			// because it is not an "in-app" library
			raven.NewStacktrace(2, 3, []string{"main", "github.com/stripe/veneur"}),
		},
	}

	if err, ok := e.Data[logrus.ErrorKey].(error); ok {
		p.Message = err.Error()
	} else {
		p.Message = e.Message
	}

	p.Extra = make(map[string]interface{}, len(e.Data)-1)
	for k, v := range e.Data {
		if k == logrus.ErrorKey {
			continue // already handled this key, don't put it into the Extra hash
		}
		p.Extra[k] = v
	}

	switch e.Level {
	case logrus.FatalLevel, logrus.PanicLevel:
		p.Level = raven.FATAL
	case logrus.ErrorLevel:
		p.Level = raven.ERROR
	case logrus.WarnLevel:
		p.Level = raven.WARNING
	case logrus.InfoLevel:
		p.Level = raven.INFO
	case logrus.DebugLevel:
		p.Level = raven.DEBUG
	}

	_, ch := s.c.Capture(&p, nil)

	if e.Level == logrus.PanicLevel || e.Level == logrus.FatalLevel {
		// we don't want the program to terminate before reporting to sentry
		return <-ch
	} else {
		return nil
	}
}
<commit_msg>Fix linting errors in sentry.go<commit_after>package veneur

import (
	"fmt"

	"github.com/Sirupsen/logrus"
	"github.com/getsentry/raven-go"
)

// ConsumePanic is intended to be called inside a deferred function when recovering
// from a panic. It accepts the value of recover() as its only argument,
// and reports the panic to Sentry, prints the stack,  and then repanics (to ensure your program terminates)
func (s *Server) ConsumePanic(err interface{}) {
	if err == nil {
		return
	}

	p := raven.Packet{
		Level:      raven.FATAL,
		ServerName: s.Hostname,
		Interfaces: []raven.Interface{
			// ignore 2 stack frames:
			// - the frame for ConsumePanic itself
			// - the frame for the deferred function that invoked ConsumePanic
			raven.NewStacktrace(2, 3, []string{"main", "github.com/stripe/veneur"}),
		},
	}

	// remember to block, since we're about to re-panic, which will probably terminate
	switch e := err.(type) {
	case error:
		p.Message = e.Error()
	case fmt.Stringer:
		p.Message = e.String()
	default:
		p.Message = fmt.Sprintf("%#v", e)
	}

	_, ch := s.sentry.Capture(&p, nil)
	// we don't want the program to terminate before reporting to sentry
	<-ch

	panic(err)
}

// logrus hook to send error/fatal/panic messages to sentry
type sentryHook struct {
	c        *raven.Client
	hostname string
	lv       []logrus.Level
}

var _ logrus.Hook = sentryHook{}

func (s sentryHook) Levels() []logrus.Level {
	return s.lv
}

func (s sentryHook) Fire(e *logrus.Entry) error {
	p := raven.Packet{
		ServerName: s.hostname,
		Interfaces: []raven.Interface{
			// ignore the stack frames for the Fire function itself
			// the logrus machinery that invoked Fire will also be hidden
			// because it is not an "in-app" library
			raven.NewStacktrace(2, 3, []string{"main", "github.com/stripe/veneur"}),
		},
	}

	if err, ok := e.Data[logrus.ErrorKey].(error); ok {
		p.Message = err.Error()
	} else {
		p.Message = e.Message
	}

	p.Extra = make(map[string]interface{}, len(e.Data)-1)
	for k, v := range e.Data {
		if k == logrus.ErrorKey {
			continue // already handled this key, don't put it into the Extra hash
		}
		p.Extra[k] = v
	}

	switch e.Level {
	case logrus.FatalLevel, logrus.PanicLevel:
		p.Level = raven.FATAL
	case logrus.ErrorLevel:
		p.Level = raven.ERROR
	case logrus.WarnLevel:
		p.Level = raven.WARNING
	case logrus.InfoLevel:
		p.Level = raven.INFO
	case logrus.DebugLevel:
		p.Level = raven.DEBUG
	}

	_, ch := s.c.Capture(&p, nil)

	if e.Level == logrus.PanicLevel || e.Level == logrus.FatalLevel {
		// we don't want the program to terminate before reporting to sentry
		return <-ch
	}
	return nil
}
<|endoftext|>


<commit_before>package web

import (
    "bytes"
    "code.google.com/p/go.net/websocket"
    "crypto/tls"
    "fmt"
    "log"
    "net"
    "net/http"
    "net/http/pprof"
    "os"
    "path"
    "reflect"
    "regexp"
    "runtime"
    "strconv"
    "time"
)

// ServerConfig is configuration for server objects.
type ServerConfig struct {
    StaticDir    string
    Addr         string
    Port         int
    CookieSecret string
    RecoverPanic bool
    Profiler     bool
}

// Server represents a web.go server.
type Server struct {
    Config *ServerConfig
    routes []route
    Logger *log.Logger
    Env    map[string]interface{}
    //save the listener so it can be closed
    l   net.Listener
}

func NewServer() *Server {
    return &Server{
        Config: Config,
        Logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
        Env:    map[string]interface{}{},
    }
}

func (s *Server) initServer() {
    if s.Config == nil {
        s.Config = &ServerConfig{}
    }

    if s.Logger == nil {
        s.Logger = log.New(os.Stdout, "", log.Ldate|log.Ltime)
    }
}

type route struct {
    r           string
    cr          *regexp.Regexp
    method      string
    handler     reflect.Value
    httpHandler http.Handler
}

func (s *Server) addRoute(r string, method string, handler interface{}) {
    cr, err := regexp.Compile(r)
    if err != nil {
        s.Logger.Printf("Error in route regex %q\n", r)
        return
    }

    switch handler.(type) {
    case http.Handler:
        s.routes = append(s.routes, route{r: r, cr: cr, method: method, httpHandler: handler.(http.Handler)})
    case reflect.Value:
        fv := handler.(reflect.Value)
        s.routes = append(s.routes, route{r: r, cr: cr, method: method, handler: fv})
    default:
        fv := reflect.ValueOf(handler)
        s.routes = append(s.routes, route{r: r, cr: cr, method: method, handler: fv})
    }
}

// ServeHTTP is the interface method for Go's http server package
func (s *Server) ServeHTTP(c http.ResponseWriter, req *http.Request) {
    s.Process(c, req)
}

// Process invokes the routing system for server s
func (s *Server) Process(c http.ResponseWriter, req *http.Request) {
    route := s.routeHandler(req, c)
    if route != nil {
        route.httpHandler.ServeHTTP(c, req)
    }
}

// Get adds a handler for the 'GET' http method for server s.
func (s *Server) Get(route string, handler interface{}) {
    s.addRoute(route, "GET", handler)
}

// Post adds a handler for the 'POST' http method for server s.
func (s *Server) Post(route string, handler interface{}) {
    s.addRoute(route, "POST", handler)
}

// Put adds a handler for the 'PUT' http method for server s.
func (s *Server) Put(route string, handler interface{}) {
    s.addRoute(route, "PUT", handler)
}

// Delete adds a handler for the 'DELETE' http method for server s.
func (s *Server) Delete(route string, handler interface{}) {
    s.addRoute(route, "DELETE", handler)
}

// Match adds a handler for an arbitrary http method for server s.
func (s *Server) Match(method string, route string, handler interface{}) {
    s.addRoute(route, method, handler)
}

//Adds a custom handler. Only for webserver mode. Will have no effect when running as FCGI or SCGI.
func (s *Server) Handler(route string, method string, httpHandler http.Handler) {
    s.addRoute(route, method, httpHandler)
}

//Adds a handler for websockets. Only for webserver mode. Will have no effect when running as FCGI or SCGI.
func (s *Server) Websocket(route string, httpHandler websocket.Handler) {
    s.addRoute(route, "GET", httpHandler)
}

// Run starts the web application and serves HTTP requests for s
func (s *Server) Run(addr string) {
    s.initServer()

    mux := http.NewServeMux()
    if s.Config.Profiler {
        mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
        mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
        mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
        mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
    }
    mux.Handle("/", s)

    s.Logger.Printf("web.go serving %s\n", addr)

    l, err := net.Listen("tcp", addr)
    if err != nil {
        log.Fatal("ListenAndServe:", err)
    }
    s.l = l
    err = http.Serve(s.l, mux)
    s.l.Close()
}

// RunFcgi starts the web application and serves FastCGI requests for s.
func (s *Server) RunFcgi(addr string) {
    s.initServer()
    s.Logger.Printf("web.go serving fcgi %s\n", addr)
    s.listenAndServeFcgi(addr)
}

// RunScgi starts the web application and serves SCGI requests for s.
func (s *Server) RunScgi(addr string) {
    s.initServer()
    s.Logger.Printf("web.go serving scgi %s\n", addr)
    s.listenAndServeScgi(addr)
}

// RunTLS starts the web application and serves HTTPS requests for s.
func (s *Server) RunTLS(addr string, config *tls.Config) error {
    s.initServer()
    mux := http.NewServeMux()
    mux.Handle("/", s)
    l, err := tls.Listen("tcp", addr, config)
    if err != nil {
        log.Fatal("Listen:", err)
        return err
    }

    s.l = l
    return http.Serve(s.l, mux)
}

// Close stops server s.
func (s *Server) Close() {
    if s.l != nil {
        s.l.Close()
    }
}

// safelyCall invokes `function` in recover block
func (s *Server) safelyCall(function reflect.Value, args []reflect.Value) (resp []reflect.Value, e interface{}) {
    defer func() {
        if err := recover(); err != nil {
            if !s.Config.RecoverPanic {
                // go back to panic
                panic(err)
            } else {
                e = err
                resp = nil
                s.Logger.Println("Handler crashed with error", err)
                for i := 1; ; i += 1 {
                    _, file, line, ok := runtime.Caller(i)
                    if !ok {
                        break
                    }
                    s.Logger.Println(file, line)
                }
            }
        }
    }()
    return function.Call(args), nil
}

// requiresContext determines whether 'handlerType' contains
// an argument to 'web.Ctx' as its first argument
func requiresContext(handlerType reflect.Type) bool {
    //if the method doesn't take arguments, no
    if handlerType.NumIn() == 0 {
        return false
    }

    //if the first argument is not a pointer, no
    a0 := handlerType.In(0)
    if a0.Kind() != reflect.Ptr {
        return false
    }
    //if the first argument is a context, yes
    if a0.Elem() == contextType {
        return true
    }

    return false
}

// tryServingFile attempts to serve a static file, and returns
// whether or not the operation is successful.
// It checks the following directories for the file, in order:
// 1) Config.StaticDir
// 2) The 'static' directory in the parent directory of the executable.
// 3) The 'static' directory in the current working directory
func (s *Server) tryServingFile(name string, req *http.Request, w http.ResponseWriter) bool {
    //try to serve a static file
    if s.Config.StaticDir != "" {
        staticFile := path.Join(s.Config.StaticDir, name)
        if fileExists(staticFile) {
            http.ServeFile(w, req, staticFile)
            return true
        }
    } else {
        for _, staticDir := range defaultStaticDirs {
            staticFile := path.Join(staticDir, name)
            if fileExists(staticFile) {
                http.ServeFile(w, req, staticFile)
                return true
            }
        }
    }
    return false
}

// the main route handler in web.go
// Tries to handle the given request.
// Finds the route matching the request, and execute the callback associated
// with it.  In case of custom http handlers, this function returns an "unused"
// route. The caller is then responsible for calling the httpHandler associated
// with the returned route.
func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused *route) {
    requestPath := req.URL.Path
    ctx := Context{req, map[string]string{}, s, w}

    //log the request
    var logEntry bytes.Buffer
    fmt.Fprintf(&logEntry, "\033[32;1m%s %s\033[0m", req.Method, requestPath)

    //ignore errors from ParseForm because it's usually harmless.
    req.ParseForm()
    if len(req.Form) > 0 {
        for k, v := range req.Form {
            ctx.Params[k] = v[0]
        }
        fmt.Fprintf(&logEntry, "\n\033[37;1mParams: %v\033[0m\n", ctx.Params)
    }
    ctx.Server.Logger.Print(logEntry.String())

    //set some default headers
    ctx.SetHeader("Server", "web.go", true)
    tm := time.Now().UTC()
    ctx.SetHeader("Date", webTime(tm), true)

    if req.Method == "GET" || req.Method == "HEAD" {
        if s.tryServingFile(requestPath, req, w) {
            return
        }
    }

    //Set the default content-type
    ctx.SetHeader("Content-Type", "text/html; charset=utf-8", true)

    for i := 0; i < len(s.routes); i++ {
        route := s.routes[i]
        cr := route.cr
        //if the methods don't match, skip this handler (except HEAD can be used in place of GET)
        if req.Method != route.method && !(req.Method == "HEAD" && route.method == "GET") {
            continue
        }

        if !cr.MatchString(requestPath) {
            continue
        }
        match := cr.FindStringSubmatch(requestPath)

        if len(match[0]) != len(requestPath) {
            continue
        }

        if route.httpHandler != nil {
            unused = &route
            // We can not handle custom http handlers here, give back to the caller.
            return
        }

        var args []reflect.Value
        handlerType := route.handler.Type()
        if requiresContext(handlerType) {
            args = append(args, reflect.ValueOf(&ctx))
        }
        for _, arg := range match[1:] {
            args = append(args, reflect.ValueOf(arg))
        }

        ret, err := s.safelyCall(route.handler, args)
        if err != nil {
            //there was an error or panic while calling the handler
            ctx.Abort(500, "Server Error")
        }
        if len(ret) == 0 {
            return
        }

        sval := ret[0]

        var content []byte

        if sval.Kind() == reflect.String {
            content = []byte(sval.String())
        } else if sval.Kind() == reflect.Slice && sval.Type().Elem().Kind() == reflect.Uint8 {
            content = sval.Interface().([]byte)
        }
        ctx.SetHeader("Content-Length", strconv.Itoa(len(content)), true)
        _, err = ctx.ResponseWriter.Write(content)
        if err != nil {
            ctx.Server.Logger.Println("Error during write: ", err)
        }
        return
    }

    // try serving index.html or index.htm
    if req.Method == "GET" || req.Method == "HEAD" {
        if s.tryServingFile(path.Join(requestPath, "index.html"), req, w) {
            return
        } else if s.tryServingFile(path.Join(requestPath, "index.htm"), req, w) {
            return
        }
    }
    ctx.Abort(404, "Page not found")
    return
}

// SetLogger sets the logger for server s
func (s *Server) SetLogger(logger *log.Logger) {
    s.Logger = logger
}
<commit_msg>Log Request in a separated method<commit_after>package web

import (
    "bytes"
    "code.google.com/p/go.net/websocket"
    "crypto/tls"
    "fmt"
    "log"
    "net"
    "net/http"
    "net/http/pprof"
    "os"
    "path"
    "reflect"
    "regexp"
    "runtime"
    "strconv"
    "strings"
    "time"
)

// ServerConfig is configuration for server objects.
type ServerConfig struct {
    StaticDir    string
    Addr         string
    Port         int
    CookieSecret string
    RecoverPanic bool
    Profiler     bool
}

// Server represents a web.go server.
type Server struct {
    Config *ServerConfig
    routes []route
    Logger *log.Logger
    Env    map[string]interface{}
    //save the listener so it can be closed
    l   net.Listener
}

func NewServer() *Server {
    return &Server{
        Config: Config,
        Logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
        Env:    map[string]interface{}{},
    }
}

func (s *Server) initServer() {
    if s.Config == nil {
        s.Config = &ServerConfig{}
    }

    if s.Logger == nil {
        s.Logger = log.New(os.Stdout, "", log.Ldate|log.Ltime)
    }
}

type route struct {
    r           string
    cr          *regexp.Regexp
    method      string
    handler     reflect.Value
    httpHandler http.Handler
}

func (s *Server) addRoute(r string, method string, handler interface{}) {
    cr, err := regexp.Compile(r)
    if err != nil {
        s.Logger.Printf("Error in route regex %q\n", r)
        return
    }

    switch handler.(type) {
    case http.Handler:
        s.routes = append(s.routes, route{r: r, cr: cr, method: method, httpHandler: handler.(http.Handler)})
    case reflect.Value:
        fv := handler.(reflect.Value)
        s.routes = append(s.routes, route{r: r, cr: cr, method: method, handler: fv})
    default:
        fv := reflect.ValueOf(handler)
        s.routes = append(s.routes, route{r: r, cr: cr, method: method, handler: fv})
    }
}

// ServeHTTP is the interface method for Go's http server package
func (s *Server) ServeHTTP(c http.ResponseWriter, req *http.Request) {
    s.Process(c, req)
}

// Process invokes the routing system for server s
func (s *Server) Process(c http.ResponseWriter, req *http.Request) {
    route := s.routeHandler(req, c)
    if route != nil {
        route.httpHandler.ServeHTTP(c, req)
    }
}

// Get adds a handler for the 'GET' http method for server s.
func (s *Server) Get(route string, handler interface{}) {
    s.addRoute(route, "GET", handler)
}

// Post adds a handler for the 'POST' http method for server s.
func (s *Server) Post(route string, handler interface{}) {
    s.addRoute(route, "POST", handler)
}

// Put adds a handler for the 'PUT' http method for server s.
func (s *Server) Put(route string, handler interface{}) {
    s.addRoute(route, "PUT", handler)
}

// Delete adds a handler for the 'DELETE' http method for server s.
func (s *Server) Delete(route string, handler interface{}) {
    s.addRoute(route, "DELETE", handler)
}

// Match adds a handler for an arbitrary http method for server s.
func (s *Server) Match(method string, route string, handler interface{}) {
    s.addRoute(route, method, handler)
}

//Adds a custom handler. Only for webserver mode. Will have no effect when running as FCGI or SCGI.
func (s *Server) Handler(route string, method string, httpHandler http.Handler) {
    s.addRoute(route, method, httpHandler)
}

//Adds a handler for websockets. Only for webserver mode. Will have no effect when running as FCGI or SCGI.
func (s *Server) Websocket(route string, httpHandler websocket.Handler) {
    s.addRoute(route, "GET", httpHandler)
}

// Run starts the web application and serves HTTP requests for s
func (s *Server) Run(addr string) {
    s.initServer()

    mux := http.NewServeMux()
    if s.Config.Profiler {
        mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
        mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
        mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
        mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
    }
    mux.Handle("/", s)

    s.Logger.Printf("web.go serving %s\n", addr)

    l, err := net.Listen("tcp", addr)
    if err != nil {
        log.Fatal("ListenAndServe:", err)
    }
    s.l = l
    err = http.Serve(s.l, mux)
    s.l.Close()
}

// RunFcgi starts the web application and serves FastCGI requests for s.
func (s *Server) RunFcgi(addr string) {
    s.initServer()
    s.Logger.Printf("web.go serving fcgi %s\n", addr)
    s.listenAndServeFcgi(addr)
}

// RunScgi starts the web application and serves SCGI requests for s.
func (s *Server) RunScgi(addr string) {
    s.initServer()
    s.Logger.Printf("web.go serving scgi %s\n", addr)
    s.listenAndServeScgi(addr)
}

// RunTLS starts the web application and serves HTTPS requests for s.
func (s *Server) RunTLS(addr string, config *tls.Config) error {
    s.initServer()
    mux := http.NewServeMux()
    mux.Handle("/", s)
    l, err := tls.Listen("tcp", addr, config)
    if err != nil {
        log.Fatal("Listen:", err)
        return err
    }

    s.l = l
    return http.Serve(s.l, mux)
}

// Close stops server s.
func (s *Server) Close() {
    if s.l != nil {
        s.l.Close()
    }
}

// safelyCall invokes `function` in recover block
func (s *Server) safelyCall(function reflect.Value, args []reflect.Value) (resp []reflect.Value, e interface{}) {
    defer func() {
        if err := recover(); err != nil {
            if !s.Config.RecoverPanic {
                // go back to panic
                panic(err)
            } else {
                e = err
                resp = nil
                s.Logger.Println("Handler crashed with error", err)
                for i := 1; ; i += 1 {
                    _, file, line, ok := runtime.Caller(i)
                    if !ok {
                        break
                    }
                    s.Logger.Println(file, line)
                }
            }
        }
    }()
    return function.Call(args), nil
}

// requiresContext determines whether 'handlerType' contains
// an argument to 'web.Ctx' as its first argument
func requiresContext(handlerType reflect.Type) bool {
    //if the method doesn't take arguments, no
    if handlerType.NumIn() == 0 {
        return false
    }

    //if the first argument is not a pointer, no
    a0 := handlerType.In(0)
    if a0.Kind() != reflect.Ptr {
        return false
    }
    //if the first argument is a context, yes
    if a0.Elem() == contextType {
        return true
    }

    return false
}

// tryServingFile attempts to serve a static file, and returns
// whether or not the operation is successful.
// It checks the following directories for the file, in order:
// 1) Config.StaticDir
// 2) The 'static' directory in the parent directory of the executable.
// 3) The 'static' directory in the current working directory
func (s *Server) tryServingFile(name string, req *http.Request, w http.ResponseWriter) bool {
    //try to serve a static file
    if s.Config.StaticDir != "" {
        staticFile := path.Join(s.Config.StaticDir, name)
        if fileExists(staticFile) {
            http.ServeFile(w, req, staticFile)
            return true
        }
    } else {
        for _, staticDir := range defaultStaticDirs {
            staticFile := path.Join(staticDir, name)
            if fileExists(staticFile) {
                http.ServeFile(w, req, staticFile)
                return true
            }
        }
    }
    return false
}

func (s *Server) logRequest(ctx Context, sTime time.Time) {
    //log the request
    var logEntry bytes.Buffer
    req := ctx.Request
    requestPath := req.URL.Path

    duration := time.Now().Sub(sTime)
    var client string

    // We suppose RemoteAddr is of the form Ip:Port as specified in the Request
    // documentation at http://golang.org/pkg/net/http/#Request
    pos := strings.LastIndex(req.RemoteAddr, ":")
    if pos > 0 {
        client = req.RemoteAddr[0:pos]
    } else {
        client = req.RemoteAddr
    }

    fmt.Fprintf(&logEntry, "%s - \033[32;1m %s %s\033[0m - %v", client, req.Method, requestPath, duration)

    if len(ctx.Params) > 0 {
        fmt.Fprintf(&logEntry, " - \033[37;1mParams: %v\033[0m\n", ctx.Params)
    }

    ctx.Server.Logger.Print(logEntry.String())

}

// the main route handler in web.go
// Tries to handle the given request.
// Finds the route matching the request, and execute the callback associated
// with it.  In case of custom http handlers, this function returns an "unused"
// route. The caller is then responsible for calling the httpHandler associated
// with the returned route.
func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused *route) {
    requestPath := req.URL.Path
    ctx := Context{req, map[string]string{}, s, w}

    //set some default headers
    ctx.SetHeader("Server", "web.go", true)
    tm := time.Now().UTC()

    //ignore errors from ParseForm because it's usually harmless.
    req.ParseForm()
    if len(req.Form) > 0 {
        for k, v := range req.Form {
            ctx.Params[k] = v[0]
        }
    }

    defer s.logRequest(ctx, tm)

    ctx.SetHeader("Date", webTime(tm), true)

    if req.Method == "GET" || req.Method == "HEAD" {
        if s.tryServingFile(requestPath, req, w) {
            return
        }
    }

    //Set the default content-type
    ctx.SetHeader("Content-Type", "text/html; charset=utf-8", true)

    for i := 0; i < len(s.routes); i++ {
        route := s.routes[i]
        cr := route.cr
        //if the methods don't match, skip this handler (except HEAD can be used in place of GET)
        if req.Method != route.method && !(req.Method == "HEAD" && route.method == "GET") {
            continue
        }

        if !cr.MatchString(requestPath) {
            continue
        }
        match := cr.FindStringSubmatch(requestPath)

        if len(match[0]) != len(requestPath) {
            continue
        }

        if route.httpHandler != nil {
            unused = &route
            // We can not handle custom http handlers here, give back to the caller.
            return
        }

        var args []reflect.Value
        handlerType := route.handler.Type()
        if requiresContext(handlerType) {
            args = append(args, reflect.ValueOf(&ctx))
        }
        for _, arg := range match[1:] {
            args = append(args, reflect.ValueOf(arg))
        }

        ret, err := s.safelyCall(route.handler, args)
        if err != nil {
            //there was an error or panic while calling the handler
            ctx.Abort(500, "Server Error")
        }
        if len(ret) == 0 {
            return
        }

        sval := ret[0]

        var content []byte

        if sval.Kind() == reflect.String {
            content = []byte(sval.String())
        } else if sval.Kind() == reflect.Slice && sval.Type().Elem().Kind() == reflect.Uint8 {
            content = sval.Interface().([]byte)
        }
        ctx.SetHeader("Content-Length", strconv.Itoa(len(content)), true)
        _, err = ctx.ResponseWriter.Write(content)
        if err != nil {
            ctx.Server.Logger.Println("Error during write: ", err)
        }
        return
    }

    // try serving index.html or index.htm
    if req.Method == "GET" || req.Method == "HEAD" {
        if s.tryServingFile(path.Join(requestPath, "index.html"), req, w) {
            return
        } else if s.tryServingFile(path.Join(requestPath, "index.htm"), req, w) {
            return
        }
    }
    ctx.Abort(404, "Page not found")
    return
}

// SetLogger sets the logger for server s
func (s *Server) SetLogger(logger *log.Logger) {
    s.Logger = logger
}
<|endoftext|>


<commit_before>package plugin

import (
	"crypto/tls"
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync/atomic"

	"github.com/hashicorp/go-hclog"

	"google.golang.org/grpc"
)

// CoreProtocolVersion is the ProtocolVersion of the plugin system itself.
// We will increment this whenever we change any protocol behavior. This
// will invalidate any prior plugins but will at least allow us to iterate
// on the core in a safe way. We will do our best to do this very
// infrequently.
const CoreProtocolVersion = 1

// HandshakeConfig is the configuration used by client and servers to
// handshake before starting a plugin connection. This is embedded by
// both ServeConfig and ClientConfig.
//
// In practice, the plugin host creates a HandshakeConfig that is exported
// and plugins then can easily consume it.
type HandshakeConfig struct {
	// ProtocolVersion is the version that clients must match on to
	// agree they can communicate. This should match the ProtocolVersion
	// set on ClientConfig when using a plugin.
	// This field is not required if VersionedPlugins are being used in the
	// Client or Server configurations.
	ProtocolVersion uint

	// MagicCookieKey and value are used as a very basic verification
	// that a plugin is intended to be launched. This is not a security
	// measure, just a UX feature. If the magic cookie doesn't match,
	// we show human-friendly output.
	MagicCookieKey   string
	MagicCookieValue string
}

// PluginSet is a set of plugins provided to be registered in the plugin
// server.
type PluginSet map[string]Plugin

// ServeConfig configures what sorts of plugins are served.
type ServeConfig struct {
	// HandshakeConfig is the configuration that must match clients.
	HandshakeConfig

	// TLSProvider is a function that returns a configured tls.Config.
	TLSProvider func() (*tls.Config, error)

	// Plugins are the plugins that are served.
	// The implied version of this PluginSet is the Handshake.ProtocolVersion.
	Plugins PluginSet

	// VersionedPlugins is a map of PluginSets for specific protocol versions.
	// These can be used to negotiate a compatible version between client and
	// server. If this is set, Handshake.ProtocolVersion is not required.
	VersionedPlugins map[int]PluginSet

	// GRPCServer should be non-nil to enable serving the plugins over
	// gRPC. This is a function to create the server when needed with the
	// given server options. The server options populated by go-plugin will
	// be for TLS if set. You may modify the input slice.
	//
	// Note that the grpc.Server will automatically be registered with
	// the gRPC health checking service. This is not optional since go-plugin
	// relies on this to implement Ping().
	GRPCServer func([]grpc.ServerOption) *grpc.Server

	// Logger is used to pass a logger into the server. If none is provided the
	// server will create a default logger.
	Logger hclog.Logger
}

// protocolVersion determines the protocol version and plugin set to be used by
// the server. In the event that there is no suitable version, the last version
// in the config is returned leaving the client to report the incompatibility.
func protocolVersion(opts *ServeConfig) (int, Protocol, PluginSet) {
	protoVersion := int(opts.ProtocolVersion)
	pluginSet := opts.Plugins
	protoType := ProtocolNetRPC
	// check if the client sent a list of acceptable versions
	var clientVersions []int
	if vs := os.Getenv("PLUGIN_PROTOCOL_VERSIONS"); vs != "" {
		for _, s := range strings.Split(vs, ",") {
			v, err := strconv.Atoi(s)
			if err != nil {
				fmt.Fprintf(os.Stderr, "server sent invalid plugin version %q", s)
				continue
			}
			clientVersions = append(clientVersions, v)
		}
	}

	// we want to iterate in reverse order, to ensure we match the newest
	// compatible plugin version.
	sort.Sort(sort.Reverse(sort.IntSlice(clientVersions)))

	// set the old un-versioned fields as if they were versioned plugins
	if opts.VersionedPlugins == nil {
		opts.VersionedPlugins = make(map[int]PluginSet)
	}

	if pluginSet != nil {
		opts.VersionedPlugins[protoVersion] = pluginSet
	}

	// sort the version to make sure we match the latest first
	var versions []int
	for v := range opts.VersionedPlugins {
		versions = append(versions, v)
	}

	sort.Sort(sort.Reverse(sort.IntSlice(versions)))

	// see if we have multiple versions of Plugins to choose from
	for _, version := range versions {
		// record each version, since we guarantee that this returns valid
		// values even if they are not a protocol match.
		protoVersion = version
		pluginSet = opts.VersionedPlugins[version]

		// all plugins in a set must use the same transport, so check the first
		// for the protocol type
		for _, p := range pluginSet {
			switch p.(type) {
			case GRPCPlugin:
				protoType = ProtocolGRPC
			default:
				protoType = ProtocolNetRPC
			}
			break
		}

		for _, clientVersion := range clientVersions {
			if clientVersion == protoVersion {
				return protoVersion, protoType, pluginSet
			}
		}
	}

	return protoVersion, protoType, pluginSet
}

// Serve serves the plugins given by ServeConfig.
//
// Serve doesn't return until the plugin is done being executed. Any
// errors will be outputted to os.Stderr.
//
// This is the method that plugins should call in their main() functions.
func Serve(opts *ServeConfig) {
	// Validate the handshake config
	if opts.MagicCookieKey == "" || opts.MagicCookieValue == "" {
		fmt.Fprintf(os.Stderr,
			"Misconfigured ServeConfig given to serve this plugin: no magic cookie\n"+
				"key or value was set. Please notify the plugin author and report\n"+
				"this as a bug.\n")
		os.Exit(1)
	}

	// First check the cookie
	if os.Getenv(opts.MagicCookieKey) != opts.MagicCookieValue {
		fmt.Fprintf(os.Stderr,
			"This binary is a plugin. These are not meant to be executed directly.\n"+
				"Please execute the program that consumes these plugins, which will\n"+
				"load any plugins automatically\n")
		os.Exit(1)
	}

	// negotiate the version and plugins
	// start with default version in the handshake config
	protoVersion, protoType, pluginSet := protocolVersion(opts)

	// Logging goes to the original stderr
	log.SetOutput(os.Stderr)

	logger := opts.Logger
	if logger == nil {
		// internal logger to os.Stderr
		logger = hclog.New(&hclog.LoggerOptions{
			Level:      hclog.Trace,
			Output:     os.Stderr,
			JSONFormat: true,
		})
	}

	// Create our new stdout, stderr files. These will override our built-in
	// stdout/stderr so that it works across the stream boundary.
	stdout_r, stdout_w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error preparing plugin: %s\n", err)
		os.Exit(1)
	}
	stderr_r, stderr_w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error preparing plugin: %s\n", err)
		os.Exit(1)
	}

	// Register a listener so we can accept a connection
	listener, err := serverListener()
	if err != nil {
		logger.Error("plugin init error", "error", err)
		return
	}

	// Close the listener on return. We wrap this in a func() on purpose
	// because the "listener" reference may change to TLS.
	defer func() {
		listener.Close()
	}()

	var tlsConfig *tls.Config
	if opts.TLSProvider != nil {
		tlsConfig, err = opts.TLSProvider()
		if err != nil {
			logger.Error("plugin tls init", "error", err)
			return
		}
	}

	// Create the channel to tell us when we're done
	doneCh := make(chan struct{})

	// Build the server type
	var server ServerProtocol
	switch protoType {
	case ProtocolNetRPC:
		// If we have a TLS configuration then we wrap the listener
		// ourselves and do it at that level.
		if tlsConfig != nil {
			listener = tls.NewListener(listener, tlsConfig)
		}

		// Create the RPC server to dispense
		server = &RPCServer{
			Plugins: pluginSet,
			Stdout:  stdout_r,
			Stderr:  stderr_r,
			DoneCh:  doneCh,
		}

	case ProtocolGRPC:
		// Create the gRPC server
		server = &GRPCServer{
			Plugins: pluginSet,
			Server:  opts.GRPCServer,
			TLS:     tlsConfig,
			Stdout:  stdout_r,
			Stderr:  stderr_r,
			DoneCh:  doneCh,
		}

	default:
		panic("unknown server protocol: " + protoType)
	}

	// Initialize the servers
	if err := server.Init(); err != nil {
		logger.Error("protocol init", "error", err)
		return
	}

	// Build the extra configuration
	extra := ""
	if v := server.Config(); v != "" {
		extra = base64.StdEncoding.EncodeToString([]byte(v))
	}
	if extra != "" {
		extra = "|" + extra
	}

	logger.Debug("plugin address", "network", listener.Addr().Network(), "address", listener.Addr().String())

	// Output the address and service name to stdout so that the client can bring it up.
	fmt.Printf("%d|%d|%s|%s|%s%s\n",
		CoreProtocolVersion,
		protoVersion,
		listener.Addr().Network(),
		listener.Addr().String(),
		protoType,
		extra)
	os.Stdout.Sync()

	// Eat the interrupts
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	go func() {
		var count int32 = 0
		for {
			<-ch
			newCount := atomic.AddInt32(&count, 1)
			logger.Debug("plugin received interrupt signal, ignoring", "count", newCount)
		}
	}()

	// Set our new out, err
	os.Stdout = stdout_w
	os.Stderr = stderr_w

	// Accept connections and wait for completion
	go server.Serve(listener)
	<-doneCh
}

func serverListener() (net.Listener, error) {
	if runtime.GOOS == "windows" {
		return serverListener_tcp()
	}

	return serverListener_unix()
}

func serverListener_tcp() (net.Listener, error) {
	minPort, err := strconv.ParseInt(os.Getenv("PLUGIN_MIN_PORT"), 10, 32)
	if err != nil {
		return nil, err
	}

	maxPort, err := strconv.ParseInt(os.Getenv("PLUGIN_MAX_PORT"), 10, 32)
	if err != nil {
		return nil, err
	}

	for port := minPort; port <= maxPort; port++ {
		address := fmt.Sprintf("127.0.0.1:%d", port)
		listener, err := net.Listen("tcp", address)
		if err == nil {
			return listener, nil
		}
	}

	return nil, errors.New("Couldn't bind plugin TCP listener")
}

func serverListener_unix() (net.Listener, error) {
	tf, err := ioutil.TempFile("", "plugin")
	if err != nil {
		return nil, err
	}
	path := tf.Name()

	// Close the file and remove it because it has to not exist for
	// the domain socket.
	if err := tf.Close(); err != nil {
		return nil, err
	}
	if err := os.Remove(path); err != nil {
		return nil, err
	}

	l, err := net.Listen("unix", path)
	if err != nil {
		return nil, err
	}

	// Wrap the listener in rmListener so that the Unix domain socket file
	// is removed on close.
	return &rmListener{
		Listener: l,
		Path:     path,
	}, nil
}

// rmListener is an implementation of net.Listener that forwards most
// calls to the listener but also removes a file as part of the close. We
// use this to cleanup the unix domain socket on close.
type rmListener struct {
	net.Listener
	Path string
}

func (l *rmListener) Close() error {
	// Close the listener itself
	if err := l.Listener.Close(); err != nil {
		return err
	}

	// Remove the file
	return os.Remove(l.Path)
}
<commit_msg>add comment about server fallback<commit_after>package plugin

import (
	"crypto/tls"
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync/atomic"

	"github.com/hashicorp/go-hclog"

	"google.golang.org/grpc"
)

// CoreProtocolVersion is the ProtocolVersion of the plugin system itself.
// We will increment this whenever we change any protocol behavior. This
// will invalidate any prior plugins but will at least allow us to iterate
// on the core in a safe way. We will do our best to do this very
// infrequently.
const CoreProtocolVersion = 1

// HandshakeConfig is the configuration used by client and servers to
// handshake before starting a plugin connection. This is embedded by
// both ServeConfig and ClientConfig.
//
// In practice, the plugin host creates a HandshakeConfig that is exported
// and plugins then can easily consume it.
type HandshakeConfig struct {
	// ProtocolVersion is the version that clients must match on to
	// agree they can communicate. This should match the ProtocolVersion
	// set on ClientConfig when using a plugin.
	// This field is not required if VersionedPlugins are being used in the
	// Client or Server configurations.
	ProtocolVersion uint

	// MagicCookieKey and value are used as a very basic verification
	// that a plugin is intended to be launched. This is not a security
	// measure, just a UX feature. If the magic cookie doesn't match,
	// we show human-friendly output.
	MagicCookieKey   string
	MagicCookieValue string
}

// PluginSet is a set of plugins provided to be registered in the plugin
// server.
type PluginSet map[string]Plugin

// ServeConfig configures what sorts of plugins are served.
type ServeConfig struct {
	// HandshakeConfig is the configuration that must match clients.
	HandshakeConfig

	// TLSProvider is a function that returns a configured tls.Config.
	TLSProvider func() (*tls.Config, error)

	// Plugins are the plugins that are served.
	// The implied version of this PluginSet is the Handshake.ProtocolVersion.
	Plugins PluginSet

	// VersionedPlugins is a map of PluginSets for specific protocol versions.
	// These can be used to negotiate a compatible version between client and
	// server. If this is set, Handshake.ProtocolVersion is not required.
	VersionedPlugins map[int]PluginSet

	// GRPCServer should be non-nil to enable serving the plugins over
	// gRPC. This is a function to create the server when needed with the
	// given server options. The server options populated by go-plugin will
	// be for TLS if set. You may modify the input slice.
	//
	// Note that the grpc.Server will automatically be registered with
	// the gRPC health checking service. This is not optional since go-plugin
	// relies on this to implement Ping().
	GRPCServer func([]grpc.ServerOption) *grpc.Server

	// Logger is used to pass a logger into the server. If none is provided the
	// server will create a default logger.
	Logger hclog.Logger
}

// protocolVersion determines the protocol version and plugin set to be used by
// the server. In the event that there is no suitable version, the last version
// in the config is returned leaving the client to report the incompatibility.
func protocolVersion(opts *ServeConfig) (int, Protocol, PluginSet) {
	protoVersion := int(opts.ProtocolVersion)
	pluginSet := opts.Plugins
	protoType := ProtocolNetRPC
	// check if the client sent a list of acceptable versions
	var clientVersions []int
	if vs := os.Getenv("PLUGIN_PROTOCOL_VERSIONS"); vs != "" {
		for _, s := range strings.Split(vs, ",") {
			v, err := strconv.Atoi(s)
			if err != nil {
				fmt.Fprintf(os.Stderr, "server sent invalid plugin version %q", s)
				continue
			}
			clientVersions = append(clientVersions, v)
		}
	}

	// we want to iterate in reverse order, to ensure we match the newest
	// compatible plugin version.
	sort.Sort(sort.Reverse(sort.IntSlice(clientVersions)))

	// set the old un-versioned fields as if they were versioned plugins
	if opts.VersionedPlugins == nil {
		opts.VersionedPlugins = make(map[int]PluginSet)
	}

	if pluginSet != nil {
		opts.VersionedPlugins[protoVersion] = pluginSet
	}

	// sort the version to make sure we match the latest first
	var versions []int
	for v := range opts.VersionedPlugins {
		versions = append(versions, v)
	}

	sort.Sort(sort.Reverse(sort.IntSlice(versions)))

	// see if we have multiple versions of Plugins to choose from
	for _, version := range versions {
		// record each version, since we guarantee that this returns valid
		// values even if they are not a protocol match.
		protoVersion = version
		pluginSet = opts.VersionedPlugins[version]

		// all plugins in a set must use the same transport, so check the first
		// for the protocol type
		for _, p := range pluginSet {
			switch p.(type) {
			case GRPCPlugin:
				protoType = ProtocolGRPC
			default:
				protoType = ProtocolNetRPC
			}
			break
		}

		for _, clientVersion := range clientVersions {
			if clientVersion == protoVersion {
				return protoVersion, protoType, pluginSet
			}
		}
	}

	// Return the lowest version as the fallback.
	// Since we iterated over all the versions in reverse order above, these
	// values are from the lowest version number plugins (which may be from
	// a combination of the Handshake.ProtocolVersion and ServeConfig.Plugins
	// fields). This allows serving the oldest version of our plugins to a
	// legacy client that did not send a PLUGIN_PROTOCOL_VERSIONS list.
	return protoVersion, protoType, pluginSet
}

// Serve serves the plugins given by ServeConfig.
//
// Serve doesn't return until the plugin is done being executed. Any
// errors will be outputted to os.Stderr.
//
// This is the method that plugins should call in their main() functions.
func Serve(opts *ServeConfig) {
	// Validate the handshake config
	if opts.MagicCookieKey == "" || opts.MagicCookieValue == "" {
		fmt.Fprintf(os.Stderr,
			"Misconfigured ServeConfig given to serve this plugin: no magic cookie\n"+
				"key or value was set. Please notify the plugin author and report\n"+
				"this as a bug.\n")
		os.Exit(1)
	}

	// First check the cookie
	if os.Getenv(opts.MagicCookieKey) != opts.MagicCookieValue {
		fmt.Fprintf(os.Stderr,
			"This binary is a plugin. These are not meant to be executed directly.\n"+
				"Please execute the program that consumes these plugins, which will\n"+
				"load any plugins automatically\n")
		os.Exit(1)
	}

	// negotiate the version and plugins
	// start with default version in the handshake config
	protoVersion, protoType, pluginSet := protocolVersion(opts)

	// Logging goes to the original stderr
	log.SetOutput(os.Stderr)

	logger := opts.Logger
	if logger == nil {
		// internal logger to os.Stderr
		logger = hclog.New(&hclog.LoggerOptions{
			Level:      hclog.Trace,
			Output:     os.Stderr,
			JSONFormat: true,
		})
	}

	// Create our new stdout, stderr files. These will override our built-in
	// stdout/stderr so that it works across the stream boundary.
	stdout_r, stdout_w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error preparing plugin: %s\n", err)
		os.Exit(1)
	}
	stderr_r, stderr_w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error preparing plugin: %s\n", err)
		os.Exit(1)
	}

	// Register a listener so we can accept a connection
	listener, err := serverListener()
	if err != nil {
		logger.Error("plugin init error", "error", err)
		return
	}

	// Close the listener on return. We wrap this in a func() on purpose
	// because the "listener" reference may change to TLS.
	defer func() {
		listener.Close()
	}()

	var tlsConfig *tls.Config
	if opts.TLSProvider != nil {
		tlsConfig, err = opts.TLSProvider()
		if err != nil {
			logger.Error("plugin tls init", "error", err)
			return
		}
	}

	// Create the channel to tell us when we're done
	doneCh := make(chan struct{})

	// Build the server type
	var server ServerProtocol
	switch protoType {
	case ProtocolNetRPC:
		// If we have a TLS configuration then we wrap the listener
		// ourselves and do it at that level.
		if tlsConfig != nil {
			listener = tls.NewListener(listener, tlsConfig)
		}

		// Create the RPC server to dispense
		server = &RPCServer{
			Plugins: pluginSet,
			Stdout:  stdout_r,
			Stderr:  stderr_r,
			DoneCh:  doneCh,
		}

	case ProtocolGRPC:
		// Create the gRPC server
		server = &GRPCServer{
			Plugins: pluginSet,
			Server:  opts.GRPCServer,
			TLS:     tlsConfig,
			Stdout:  stdout_r,
			Stderr:  stderr_r,
			DoneCh:  doneCh,
		}

	default:
		panic("unknown server protocol: " + protoType)
	}

	// Initialize the servers
	if err := server.Init(); err != nil {
		logger.Error("protocol init", "error", err)
		return
	}

	// Build the extra configuration
	extra := ""
	if v := server.Config(); v != "" {
		extra = base64.StdEncoding.EncodeToString([]byte(v))
	}
	if extra != "" {
		extra = "|" + extra
	}

	logger.Debug("plugin address", "network", listener.Addr().Network(), "address", listener.Addr().String())

	// Output the address and service name to stdout so that the client can bring it up.
	fmt.Printf("%d|%d|%s|%s|%s%s\n",
		CoreProtocolVersion,
		protoVersion,
		listener.Addr().Network(),
		listener.Addr().String(),
		protoType,
		extra)
	os.Stdout.Sync()

	// Eat the interrupts
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	go func() {
		var count int32 = 0
		for {
			<-ch
			newCount := atomic.AddInt32(&count, 1)
			logger.Debug("plugin received interrupt signal, ignoring", "count", newCount)
		}
	}()

	// Set our new out, err
	os.Stdout = stdout_w
	os.Stderr = stderr_w

	// Accept connections and wait for completion
	go server.Serve(listener)
	<-doneCh
}

func serverListener() (net.Listener, error) {
	if runtime.GOOS == "windows" {
		return serverListener_tcp()
	}

	return serverListener_unix()
}

func serverListener_tcp() (net.Listener, error) {
	minPort, err := strconv.ParseInt(os.Getenv("PLUGIN_MIN_PORT"), 10, 32)
	if err != nil {
		return nil, err
	}

	maxPort, err := strconv.ParseInt(os.Getenv("PLUGIN_MAX_PORT"), 10, 32)
	if err != nil {
		return nil, err
	}

	for port := minPort; port <= maxPort; port++ {
		address := fmt.Sprintf("127.0.0.1:%d", port)
		listener, err := net.Listen("tcp", address)
		if err == nil {
			return listener, nil
		}
	}

	return nil, errors.New("Couldn't bind plugin TCP listener")
}

func serverListener_unix() (net.Listener, error) {
	tf, err := ioutil.TempFile("", "plugin")
	if err != nil {
		return nil, err
	}
	path := tf.Name()

	// Close the file and remove it because it has to not exist for
	// the domain socket.
	if err := tf.Close(); err != nil {
		return nil, err
	}
	if err := os.Remove(path); err != nil {
		return nil, err
	}

	l, err := net.Listen("unix", path)
	if err != nil {
		return nil, err
	}

	// Wrap the listener in rmListener so that the Unix domain socket file
	// is removed on close.
	return &rmListener{
		Listener: l,
		Path:     path,
	}, nil
}

// rmListener is an implementation of net.Listener that forwards most
// calls to the listener but also removes a file as part of the close. We
// use this to cleanup the unix domain socket on close.
type rmListener struct {
	net.Listener
	Path string
}

func (l *rmListener) Close() error {
	// Close the listener itself
	if err := l.Listener.Close(); err != nil {
		return err
	}

	// Remove the file
	return os.Remove(l.Path)
}
<|endoftext|>


<commit_before>package falcore

import (
	"bufio"
	"crypto/rand"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"sync"
	"syscall"
	"time"
)

type Server struct {
	Addr             string
	Pipeline         *Pipeline
	listener         net.Listener
	listenerFile     *os.File
	stopAccepting    chan int
	handlerWaitGroup *sync.WaitGroup
	logPrefix        string
	AcceptReady      chan int
	sendfile         bool
	sockOpt          int
	bufferPool       *bufferPool
}

func NewServer(port int, pipeline *Pipeline) *Server {
	s := new(Server)
	s.Addr = fmt.Sprintf(":%v", port)
	s.Pipeline = pipeline
	s.stopAccepting = make(chan int)
	s.AcceptReady = make(chan int, 1)
	s.handlerWaitGroup = new(sync.WaitGroup)
	s.logPrefix = fmt.Sprintf("%d", syscall.Getpid())

	// openbsd/netbsd don't have TCP_NOPUSH so it's likely sendfile will be slower
	// without these socket options, just enable for linux, mac and freebsd.
	// TODO (Graham) windows has TransmitFile zero-copy mechanism, try to use it
	switch runtime.GOOS {
	case "linux":
		s.sendfile = true
		s.sockOpt = 0x3 // syscall.TCP_CORK
	case "freebsd", "darwin":
		s.sendfile = true
		s.sockOpt = 0x4 // syscall.TCP_NOPUSH
	default:
		s.sendfile = false
	}

	// buffer pool for reusing connection bufio.Readers
	s.bufferPool = newBufferPool(100, 8192)

	return s
}

func (srv *Server) FdListen(fd int) error {
	var err error
	srv.listenerFile = os.NewFile(uintptr(fd), "")
	if srv.listener, err = net.FileListener(srv.listenerFile); err != nil {
		return err
	}
	if _, ok := srv.listener.(*net.TCPListener); !ok {
		return errors.New("Broken listener isn't TCP")
	}
	return nil
}

func (srv *Server) socketListen() error {
	var la *net.TCPAddr
	var err error
	if la, err = net.ResolveTCPAddr("tcp", srv.Addr); err != nil {
		return err
	}

	var l *net.TCPListener
	if l, err = net.ListenTCP("tcp", la); err != nil {
		return err
	}
	srv.listener = l
	// setup listener to be non-blocking if we're not on windows.
	// this is required for hot restart to work.
	return srv.setupNonBlockingListener(err, l)
}

func (srv *Server) ListenAndServe() error {
	if srv.Addr == "" {
		srv.Addr = ":http"
	}
	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}
	return srv.serve()
}

func (srv *Server) SocketFd() int {
	return int(srv.listenerFile.Fd())
}

func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
	if srv.Addr == "" {
		srv.Addr = ":https"
	}
	config := &tls.Config{
		Rand:       rand.Reader,
		Time:       time.Now,
		NextProtos: []string{"http/1.1"},
	}

	var err error
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return err
	}

	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}

	srv.listener = tls.NewListener(srv.listener, config)

	return srv.serve()
}

func (srv *Server) StopAccepting() {
	close(srv.stopAccepting)
}

func (srv *Server) Port() int {
	if l := srv.listener; l != nil {
		a := l.Addr()
		if _, p, e := net.SplitHostPort(a.String()); e == nil && p != "" {
			server_port, _ := strconv.Atoi(p)
			return server_port
		}
	}
	return 0
}

func (srv *Server) serve() (e error) {
	var accept = true
	srv.AcceptReady <- 1
	for accept {
		var c net.Conn
		if l, ok := srv.listener.(*net.TCPListener); ok {
			l.SetDeadline(time.Now().Add(3e9))
		}
		c, e = srv.listener.Accept()
		if e != nil {
			if ope, ok := e.(*net.OpError); ok {
				if !(ope.Timeout() && ope.Temporary()) {
					Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), ope)
				}
			} else {
				Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), e)
			}
		} else {
			//Trace("Handling!")
			srv.handlerWaitGroup.Add(1)
			go srv.handler(c)
		}
		select {
		case <-srv.stopAccepting:
			accept = false
		default:
		}
	}
	Trace("Stopped accepting, waiting for handlers")
	// wait for handlers
	srv.handlerWaitGroup.Wait()
	return nil
}

func (srv *Server) sentinel(c net.Conn, connClosed chan int) {
	select {
	case <-srv.stopAccepting:
		c.SetReadDeadline(time.Now().Add(3 * time.Second))
	case <-connClosed:
	}
}

func (srv *Server) handler(c net.Conn) {
	startTime := time.Now()
	bpe := srv.bufferPool.take(c)
	defer srv.bufferPool.give(bpe)
	var closeSentinelChan = make(chan int)
	go srv.sentinel(c, closeSentinelChan)
	defer srv.connectionFinished(c, closeSentinelChan)
	var err error
	var req *http.Request
	// no keepalive (for now)
	reqCount := 0
	keepAlive := true
	for err == nil && keepAlive {
		if req, err = http.ReadRequest(bpe.br); err == nil {
			if req.Header.Get("Connection") != "Keep-Alive" {
				keepAlive = false
			}
			request := newRequest(req, c, startTime)
			reqCount++
			var res *http.Response

			pssInit := new(PipelineStageStat)
			pssInit.Name = "server.Init"
			pssInit.StartTime = startTime
			pssInit.EndTime = time.Now()
			request.appendPipelineStage(pssInit)
			// execute the pipeline
			if res = srv.Pipeline.execute(request); res == nil {
				res = SimpleResponse(req, 404, nil, "Not Found")
			}
			// cleanup
			request.startPipelineStage("server.ResponseWrite")
			req.Body.Close()

			// shutting down?
			select {
			case <-srv.stopAccepting:
				keepAlive = false
				res.Close = true
			default:
			}
			// The res.Write omits Content-length on 0 length bodies, and by spec,
			// it SHOULD. While this is not MUST, it's kinda broken.  See sec 4.4
			// of rfc2616 and a 200 with a zero length does not satisfy any of the
			// 5 conditions if Connection: keep-alive is set :(
			// I'm forcing chunked which seems to work because I couldn't get the
			// content length to write if it was 0.
			// Specifically, the android http client waits forever if there's no
			// content-length instead of assuming zero at the end of headers. der.
			if res.ContentLength == 0 && len(res.TransferEncoding) == 0 && !((res.StatusCode-100 < 100) || res.StatusCode == 204 || res.StatusCode == 304) {
				res.TransferEncoding = []string{"identity"}
			}
			if res.ContentLength < 0 {
				res.TransferEncoding = []string{"chunked"}
			}

			// write response
			if srv.sendfile {
				res.Write(c)
			} else {
				wbuf := bufio.NewWriter(c)
				res.Write(wbuf)
				wbuf.Flush()
			}
			if res.Body != nil {
				res.Body.Close()
			}
			request.finishPipelineStage()
			request.finishRequest()
			srv.requestFinished(request)
			// Reset the startTime
			// this isn't great since there may be lag between requests; but it's the best we've got
			startTime = time.Now()
		} else {
			// EOF is socket closed
			if nerr, ok := err.(net.Error); err != io.EOF && !(ok && nerr.Timeout()) {
				Error("%s %v ERROR reading request: <%T %v>", srv.serverLogPrefix(), c.RemoteAddr(), err, err)
			}
		}
	}
	//Debug("%s Processed %v requests on connection %v", srv.serverLogPrefix(), reqCount, c.RemoteAddr())
}

func (srv *Server) serverLogPrefix() string {
	return srv.logPrefix
}

func (srv *Server) requestFinished(request *Request) {
	if srv.Pipeline.RequestDoneCallback != nil {
		// Don't block the connecion for this
		go srv.Pipeline.RequestDoneCallback.FilterRequest(request)
	}
}

func (srv *Server) connectionFinished(c net.Conn, closeChan chan int) {
	c.Close()
	close(closeChan)
	srv.handlerWaitGroup.Done()
}
<commit_msg>if we say we're going to close, do it<commit_after>package falcore

import (
	"bufio"
	"crypto/rand"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"sync"
	"syscall"
	"time"
)

type Server struct {
	Addr             string
	Pipeline         *Pipeline
	listener         net.Listener
	listenerFile     *os.File
	stopAccepting    chan int
	handlerWaitGroup *sync.WaitGroup
	logPrefix        string
	AcceptReady      chan int
	sendfile         bool
	sockOpt          int
	bufferPool       *bufferPool
}

func NewServer(port int, pipeline *Pipeline) *Server {
	s := new(Server)
	s.Addr = fmt.Sprintf(":%v", port)
	s.Pipeline = pipeline
	s.stopAccepting = make(chan int)
	s.AcceptReady = make(chan int, 1)
	s.handlerWaitGroup = new(sync.WaitGroup)
	s.logPrefix = fmt.Sprintf("%d", syscall.Getpid())

	// openbsd/netbsd don't have TCP_NOPUSH so it's likely sendfile will be slower
	// without these socket options, just enable for linux, mac and freebsd.
	// TODO (Graham) windows has TransmitFile zero-copy mechanism, try to use it
	switch runtime.GOOS {
	case "linux":
		s.sendfile = true
		s.sockOpt = 0x3 // syscall.TCP_CORK
	case "freebsd", "darwin":
		s.sendfile = true
		s.sockOpt = 0x4 // syscall.TCP_NOPUSH
	default:
		s.sendfile = false
	}

	// buffer pool for reusing connection bufio.Readers
	s.bufferPool = newBufferPool(100, 8192)

	return s
}

func (srv *Server) FdListen(fd int) error {
	var err error
	srv.listenerFile = os.NewFile(uintptr(fd), "")
	if srv.listener, err = net.FileListener(srv.listenerFile); err != nil {
		return err
	}
	if _, ok := srv.listener.(*net.TCPListener); !ok {
		return errors.New("Broken listener isn't TCP")
	}
	return nil
}

func (srv *Server) socketListen() error {
	var la *net.TCPAddr
	var err error
	if la, err = net.ResolveTCPAddr("tcp", srv.Addr); err != nil {
		return err
	}

	var l *net.TCPListener
	if l, err = net.ListenTCP("tcp", la); err != nil {
		return err
	}
	srv.listener = l
	// setup listener to be non-blocking if we're not on windows.
	// this is required for hot restart to work.
	return srv.setupNonBlockingListener(err, l)
}

func (srv *Server) ListenAndServe() error {
	if srv.Addr == "" {
		srv.Addr = ":http"
	}
	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}
	return srv.serve()
}

func (srv *Server) SocketFd() int {
	return int(srv.listenerFile.Fd())
}

func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
	if srv.Addr == "" {
		srv.Addr = ":https"
	}
	config := &tls.Config{
		Rand:       rand.Reader,
		Time:       time.Now,
		NextProtos: []string{"http/1.1"},
	}

	var err error
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return err
	}

	if srv.listener == nil {
		if err := srv.socketListen(); err != nil {
			return err
		}
	}

	srv.listener = tls.NewListener(srv.listener, config)

	return srv.serve()
}

func (srv *Server) StopAccepting() {
	close(srv.stopAccepting)
}

func (srv *Server) Port() int {
	if l := srv.listener; l != nil {
		a := l.Addr()
		if _, p, e := net.SplitHostPort(a.String()); e == nil && p != "" {
			server_port, _ := strconv.Atoi(p)
			return server_port
		}
	}
	return 0
}

func (srv *Server) serve() (e error) {
	var accept = true
	srv.AcceptReady <- 1
	for accept {
		var c net.Conn
		if l, ok := srv.listener.(*net.TCPListener); ok {
			l.SetDeadline(time.Now().Add(3e9))
		}
		c, e = srv.listener.Accept()
		if e != nil {
			if ope, ok := e.(*net.OpError); ok {
				if !(ope.Timeout() && ope.Temporary()) {
					Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), ope)
				}
			} else {
				Error("%s SERVER Accept Error: %v", srv.serverLogPrefix(), e)
			}
		} else {
			//Trace("Handling!")
			srv.handlerWaitGroup.Add(1)
			go srv.handler(c)
		}
		select {
		case <-srv.stopAccepting:
			accept = false
		default:
		}
	}
	Trace("Stopped accepting, waiting for handlers")
	// wait for handlers
	srv.handlerWaitGroup.Wait()
	return nil
}

func (srv *Server) sentinel(c net.Conn, connClosed chan int) {
	select {
	case <-srv.stopAccepting:
		c.SetReadDeadline(time.Now().Add(3 * time.Second))
	case <-connClosed:
	}
}

func (srv *Server) handler(c net.Conn) {
	startTime := time.Now()
	bpe := srv.bufferPool.take(c)
	defer srv.bufferPool.give(bpe)
	var closeSentinelChan = make(chan int)
	go srv.sentinel(c, closeSentinelChan)
	defer srv.connectionFinished(c, closeSentinelChan)
	var err error
	var req *http.Request
	// no keepalive (for now)
	reqCount := 0
	keepAlive := true
	for err == nil && keepAlive {
		if req, err = http.ReadRequest(bpe.br); err == nil {
			if req.Header.Get("Connection") != "Keep-Alive" {
				keepAlive = false
			}
			request := newRequest(req, c, startTime)
			reqCount++
			var res *http.Response

			pssInit := new(PipelineStageStat)
			pssInit.Name = "server.Init"
			pssInit.StartTime = startTime
			pssInit.EndTime = time.Now()
			request.appendPipelineStage(pssInit)
			// execute the pipeline
			if res = srv.Pipeline.execute(request); res == nil {
				res = SimpleResponse(req, 404, nil, "Not Found")
			}
			// cleanup
			request.startPipelineStage("server.ResponseWrite")
			req.Body.Close()

			// shutting down?
			select {
			case <-srv.stopAccepting:
				keepAlive = false
				res.Close = true
			default:
			}
			// The res.Write omits Content-length on 0 length bodies, and by spec,
			// it SHOULD. While this is not MUST, it's kinda broken.  See sec 4.4
			// of rfc2616 and a 200 with a zero length does not satisfy any of the
			// 5 conditions if Connection: keep-alive is set :(
			// I'm forcing chunked which seems to work because I couldn't get the
			// content length to write if it was 0.
			// Specifically, the android http client waits forever if there's no
			// content-length instead of assuming zero at the end of headers. der.
			if res.ContentLength == 0 && len(res.TransferEncoding) == 0 && !((res.StatusCode-100 < 100) || res.StatusCode == 204 || res.StatusCode == 304) {
				res.TransferEncoding = []string{"identity"}
			}
			if res.ContentLength < 0 {
				res.TransferEncoding = []string{"chunked"}
			}

			// write response
			if srv.sendfile {
				res.Write(c)
			} else {
				wbuf := bufio.NewWriter(c)
				res.Write(wbuf)
				wbuf.Flush()
			}
			if res.Body != nil {
				res.Body.Close()
			}
			request.finishPipelineStage()
			request.finishRequest()
			srv.requestFinished(request)

			if res.Close {
				keepAlive = false
			}

			// Reset the startTime
			// this isn't great since there may be lag between requests; but it's the best we've got
			startTime = time.Now()
		} else {
			// EOF is socket closed
			if nerr, ok := err.(net.Error); err != io.EOF && !(ok && nerr.Timeout()) {
				Error("%s %v ERROR reading request: <%T %v>", srv.serverLogPrefix(), c.RemoteAddr(), err, err)
			}
		}
	}
	//Debug("%s Processed %v requests on connection %v", srv.serverLogPrefix(), reqCount, c.RemoteAddr())
}

func (srv *Server) serverLogPrefix() string {
	return srv.logPrefix
}

func (srv *Server) requestFinished(request *Request) {
	if srv.Pipeline.RequestDoneCallback != nil {
		// Don't block the connecion for this
		go srv.Pipeline.RequestDoneCallback.FilterRequest(request)
	}
}

func (srv *Server) connectionFinished(c net.Conn, closeChan chan int) {
	c.Close()
	close(closeChan)
	srv.handlerWaitGroup.Done()
}
<|endoftext|>