<commit_before>// Copyright (c) 2014,2015,2016 Docker, Inc.
// Copyright (c) 2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"syscall"

	vc "github.com/containers/virtcontainers"
	"github.com/containers/virtcontainers/pkg/oci"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/urfave/cli"
)

type execParams struct {
	ociProcess   oci.CompatOCIProcess
	cID          string
	pidFile      string
	console      string
	consoleSock  string
	detach       bool
	processLabel string
	noSubreaper  bool
}

var execCLICommand = cli.Command{
	Name:  "exec",
	Usage: "Execute new process inside the container",
	ArgsUsage: `<container-id> <command> [command options]  || -p process.json <container-id>

   <container-id> is the name for the instance of the container and <command>
   is the command to be executed in the container. <command> can't be empty
   unless a "-p" flag provided.

EXAMPLE:
   If the container is configured to run the linux ps command the following
   will output a list of processes running in the container:

       # ` + name + ` <container-id> ps`,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "console",
			Usage: "path to a pseudo terminal",
		},
		cli.StringFlag{
			Name:  "console-socket",
			Value: "",
			Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal",
		},
		cli.StringFlag{
			Name:  "cwd",
			Usage: "current working directory in the container",
		},
		cli.StringSliceFlag{
			Name:  "env, e",
			Usage: "set environment variables",
		},
		cli.BoolFlag{
			Name:  "tty, t",
			Usage: "allocate a pseudo-TTY",
		},
		cli.StringFlag{
			Name:  "user, u",
			Usage: "UID (format: <uid>[:<gid>])",
		},
		cli.StringFlag{
			Name:  "process, p",
			Usage: "path to the process.json",
		},
		cli.BoolFlag{
			Name:  "detach,d",
			Usage: "detach from the container's process",
		},
		cli.StringFlag{
			Name:  "pid-file",
			Value: "",
			Usage: "specify the file to write the process id to",
		},
		cli.StringFlag{
			Name:  "process-label",
			Usage: "set the asm process label for the process commonly used with selinux",
		},
		cli.StringFlag{
			Name:  "apparmor",
			Usage: "set the apparmor profile for the process",
		},
		cli.BoolFlag{
			Name:  "no-new-privs",
			Usage: "set the no new privileges value for the process",
		},
		cli.StringSliceFlag{
			Name:  "cap, c",
			Value: &cli.StringSlice{},
			Usage: "add a capability to the bounding set for the process",
		},
		cli.BoolFlag{
			Name:   "no-subreaper",
			Usage:  "disable the use of the subreaper used to reap reparented processes",
			Hidden: true,
		},
	},
	Action: func(context *cli.Context) error {
		return execute(context)
	},
}

func generateExecParams(context *cli.Context, specProcess *oci.CompatOCIProcess) (execParams, error) {
	ctxArgs := context.Args()

	params := execParams{
		cID:          ctxArgs.First(),
		pidFile:      context.String("pid-file"),
		console:      context.String("console"),
		consoleSock:  context.String("console-socket"),
		detach:       context.Bool("detach"),
		processLabel: context.String("process-label"),
		noSubreaper:  context.Bool("no-subreaper"),
	}

	if context.IsSet("process") == true {
		var ociProcess oci.CompatOCIProcess

		fileContent, err := ioutil.ReadFile(context.String("process"))
		if err != nil {
			return execParams{}, err
		}

		if err := json.Unmarshal(fileContent, &ociProcess); err != nil {
			return execParams{}, err
		}

		params.ociProcess = ociProcess
	} else {
		params.ociProcess = *specProcess

		// Override terminal
		if context.IsSet("tty") {
			params.ociProcess.Terminal = context.Bool("tty")
		}

		// Override user
		if context.String("user") != "" {
			params.ociProcess.User = specs.User{
				Username: context.String("user"),
			}
		}

		// Override env
		params.ociProcess.Env = append(params.ociProcess.Env, context.StringSlice("env")...)

		// Override cwd
		if context.String("cwd") != "" {
			params.ociProcess.Cwd = context.String("cwd")
		}

		// Override no-new-privs
		if context.IsSet("no-new-privs") {
			params.ociProcess.NoNewPrivileges = context.Bool("no-new-privs")
		}

		// Override apparmor
		if context.String("apparmor") != "" {
			params.ociProcess.ApparmorProfile = context.String("apparmor")
		}

		params.ociProcess.Args = ctxArgs.Tail()
	}

	return params, nil
}

func execute(context *cli.Context) error {
	containerID := context.Args().First()
	status, podID, err := getExistingContainerInfo(containerID)
	if err != nil {
		return err
	}

	// Retrieve OCI spec configuration.
	ociSpec, err := oci.GetOCIConfig(status)
	if err != nil {
		return err
	}

	params, err := generateExecParams(context, ociSpec.Process)
	if err != nil {
		return err
	}

	params.cID = status.ID

	// container MUST be running
	if status.State.State != vc.StateRunning {
		return fmt.Errorf("Container %s is not running", params.cID)
	}

	envVars, err := oci.EnvVars(params.ociProcess.Env)
	if err != nil {
		return err
	}

	consolePath, err := setupConsole(params.console, params.consoleSock)
	if err != nil {
		return err
	}

	cmd := vc.Cmd{
		Args:        params.ociProcess.Args,
		Envs:        envVars,
		WorkDir:     params.ociProcess.Cwd,
		User:        params.ociProcess.User.Username,
		Interactive: params.ociProcess.Terminal,
		Console:     consolePath,
		Detach:      noNeedForOutput(params.detach, params.ociProcess.Terminal),
	}

	_, _, process, err := vci.EnterContainer(podID, params.cID, cmd)
	if err != nil {
		return err
	}

	// Creation of PID file has to be the last thing done in the exec
	// because containerd considers the exec to have finished starting
	// after this file is created.
	if err := createPIDFile(params.pidFile, process.Pid); err != nil {
		return err
	}

	if !params.detach {
		p, err := os.FindProcess(process.Pid)
		if err != nil {
			return err
		}

		ps, err := p.Wait()
		if err != nil {
			return fmt.Errorf("Process state %s, container info %+v: %v",
				ps.String(), status, err)
		}

		// Exit code has to be forwarded in this case.
		return cli.NewExitError("", ps.Sys().(syscall.WaitStatus).ExitStatus())
	}

	return nil
}
<commit_msg>cli: Check for empty string for cli flag "process" in exec.go<commit_after>// Copyright (c) 2014,2015,2016 Docker, Inc.
// Copyright (c) 2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"syscall"

	vc "github.com/containers/virtcontainers"
	"github.com/containers/virtcontainers/pkg/oci"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/urfave/cli"
)

type execParams struct {
	ociProcess   oci.CompatOCIProcess
	cID          string
	pidFile      string
	console      string
	consoleSock  string
	detach       bool
	processLabel string
	noSubreaper  bool
}

var execCLICommand = cli.Command{
	Name:  "exec",
	Usage: "Execute new process inside the container",
	ArgsUsage: `<container-id> <command> [command options]  || -p process.json <container-id>

   <container-id> is the name for the instance of the container and <command>
   is the command to be executed in the container. <command> can't be empty
   unless a "-p" flag provided.

EXAMPLE:
   If the container is configured to run the linux ps command the following
   will output a list of processes running in the container:

       # ` + name + ` <container-id> ps`,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "console",
			Usage: "path to a pseudo terminal",
		},
		cli.StringFlag{
			Name:  "console-socket",
			Value: "",
			Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal",
		},
		cli.StringFlag{
			Name:  "cwd",
			Usage: "current working directory in the container",
		},
		cli.StringSliceFlag{
			Name:  "env, e",
			Usage: "set environment variables",
		},
		cli.BoolFlag{
			Name:  "tty, t",
			Usage: "allocate a pseudo-TTY",
		},
		cli.StringFlag{
			Name:  "user, u",
			Usage: "UID (format: <uid>[:<gid>])",
		},
		cli.StringFlag{
			Name:  "process, p",
			Usage: "path to the process.json",
		},
		cli.BoolFlag{
			Name:  "detach,d",
			Usage: "detach from the container's process",
		},
		cli.StringFlag{
			Name:  "pid-file",
			Value: "",
			Usage: "specify the file to write the process id to",
		},
		cli.StringFlag{
			Name:  "process-label",
			Usage: "set the asm process label for the process commonly used with selinux",
		},
		cli.StringFlag{
			Name:  "apparmor",
			Usage: "set the apparmor profile for the process",
		},
		cli.BoolFlag{
			Name:  "no-new-privs",
			Usage: "set the no new privileges value for the process",
		},
		cli.StringSliceFlag{
			Name:  "cap, c",
			Value: &cli.StringSlice{},
			Usage: "add a capability to the bounding set for the process",
		},
		cli.BoolFlag{
			Name:   "no-subreaper",
			Usage:  "disable the use of the subreaper used to reap reparented processes",
			Hidden: true,
		},
	},
	Action: func(context *cli.Context) error {
		return execute(context)
	},
}

func generateExecParams(context *cli.Context, specProcess *oci.CompatOCIProcess) (execParams, error) {
	ctxArgs := context.Args()

	params := execParams{
		cID:          ctxArgs.First(),
		pidFile:      context.String("pid-file"),
		console:      context.String("console"),
		consoleSock:  context.String("console-socket"),
		detach:       context.Bool("detach"),
		processLabel: context.String("process-label"),
		noSubreaper:  context.Bool("no-subreaper"),
	}

	if context.String("process") != "" {
		var ociProcess oci.CompatOCIProcess

		fileContent, err := ioutil.ReadFile(context.String("process"))
		if err != nil {
			return execParams{}, err
		}

		if err := json.Unmarshal(fileContent, &ociProcess); err != nil {
			return execParams{}, err
		}

		params.ociProcess = ociProcess
	} else {
		params.ociProcess = *specProcess

		// Override terminal
		if context.IsSet("tty") {
			params.ociProcess.Terminal = context.Bool("tty")
		}

		// Override user
		if context.String("user") != "" {
			params.ociProcess.User = specs.User{
				Username: context.String("user"),
			}
		}

		// Override env
		params.ociProcess.Env = append(params.ociProcess.Env, context.StringSlice("env")...)

		// Override cwd
		if context.String("cwd") != "" {
			params.ociProcess.Cwd = context.String("cwd")
		}

		// Override no-new-privs
		if context.IsSet("no-new-privs") {
			params.ociProcess.NoNewPrivileges = context.Bool("no-new-privs")
		}

		// Override apparmor
		if context.String("apparmor") != "" {
			params.ociProcess.ApparmorProfile = context.String("apparmor")
		}

		params.ociProcess.Args = ctxArgs.Tail()
	}

	return params, nil
}

func execute(context *cli.Context) error {
	containerID := context.Args().First()
	status, podID, err := getExistingContainerInfo(containerID)
	if err != nil {
		return err
	}

	// Retrieve OCI spec configuration.
	ociSpec, err := oci.GetOCIConfig(status)
	if err != nil {
		return err
	}

	params, err := generateExecParams(context, ociSpec.Process)
	if err != nil {
		return err
	}

	params.cID = status.ID

	// container MUST be running
	if status.State.State != vc.StateRunning {
		return fmt.Errorf("Container %s is not running", params.cID)
	}

	envVars, err := oci.EnvVars(params.ociProcess.Env)
	if err != nil {
		return err
	}

	consolePath, err := setupConsole(params.console, params.consoleSock)
	if err != nil {
		return err
	}

	cmd := vc.Cmd{
		Args:        params.ociProcess.Args,
		Envs:        envVars,
		WorkDir:     params.ociProcess.Cwd,
		User:        params.ociProcess.User.Username,
		Interactive: params.ociProcess.Terminal,
		Console:     consolePath,
		Detach:      noNeedForOutput(params.detach, params.ociProcess.Terminal),
	}

	_, _, process, err := vci.EnterContainer(podID, params.cID, cmd)
	if err != nil {
		return err
	}

	// Creation of PID file has to be the last thing done in the exec
	// because containerd considers the exec to have finished starting
	// after this file is created.
	if err := createPIDFile(params.pidFile, process.Pid); err != nil {
		return err
	}

	if !params.detach {
		p, err := os.FindProcess(process.Pid)
		if err != nil {
			return err
		}

		ps, err := p.Wait()
		if err != nil {
			return fmt.Errorf("Process state %s, container info %+v: %v",
				ps.String(), status, err)
		}

		// Exit code has to be forwarded in this case.
		return cli.NewExitError("", ps.Sys().(syscall.WaitStatus).ExitStatus())
	}

	return nil
}
<|endoftext|>


<commit_before>package apache

import (
	"bufio"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/influxdb/telegraf/plugins"
)

type Apache struct {
	Urls []string
}

var sampleConfig = `
# An array of Apache status URI to gather stats.
urls = ["http://localhost/server-status?auto"]
`

func (n *Apache) SampleConfig() string {
	return sampleConfig
}

func (n *Apache) Description() string {
	return "Read Apache status information (mod_status)"
}

func (n *Apache) Gather(acc plugins.Accumulator) error {
	var wg sync.WaitGroup
	var outerr error

	for _, u := range n.Urls {
		addr, err := url.Parse(u)
		if err != nil {
			return fmt.Errorf("Unable to parse address '%s': %s", u, err)
		}

		wg.Add(1)
		go func(addr *url.URL) {
			defer wg.Done()
			outerr = n.gatherUrl(addr, acc)
		}(addr)
	}

	wg.Wait()

	return outerr
}

var tr = &http.Transport{
	ResponseHeaderTimeout: time.Duration(3 * time.Second),
}

var client = &http.Client{Transport: tr}

func (n *Apache) gatherUrl(addr *url.URL, acc plugins.Accumulator) error {
	resp, err := client.Get(addr.String())
	if err != nil {
		return fmt.Errorf("error making HTTP request to %s: %s", addr.String(), err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("%s returned HTTP status %s", addr.String(), resp.Status)
	}

	tags := getTags(addr)

	sc := bufio.NewScanner(resp.Body)
	for sc.Scan() {
	    line := sc.Text()
	    if strings.Contains(line, ":") {

            parts := strings.SplitN(line, ":", 2)
            key, part := strings.Replace(parts[0], " ", "", -1), strings.TrimSpace(parts[1])

	        switch key {

                case "Scoreboard":
                    n.gatherScores(part, acc, tags)
                default:
                    value, err := strconv.ParseFloat(part, 32)
                    if err != nil {
                        continue
                    }
                    acc.Add(key, value, tags)
	        }
	    }
	}

	return nil
}

func (n *Apache) gatherScores(data string, acc plugins.Accumulator, tags map[string]string) {

    var waiting, open int = 0, 0
    var S, R, W, K, D, C, L, G, I int = 0, 0, 0, 0, 0, 0, 0, 0, 0

    for _, s := range strings.Split(data, "") {

        switch s {
            case "_": waiting++
            case "S": S++
            case "R": R++
            case "W": W++
            case "K": K++
            case "D": D++
            case "C": C++
            case "L": L++
            case "G": G++
            case "I": I++
            case ".": open++
        }
    }

    acc.Add("scboard_waiting",      float64(waiting), tags);
    acc.Add("scboard_starting",     float64(S),       tags);
    acc.Add("scboard_reading",      float64(R),       tags);
    acc.Add("scboard_sending",      float64(W),       tags);
    acc.Add("scboard_keepalive",    float64(K),       tags);
    acc.Add("scboard_dnslookup",    float64(D),       tags);
    acc.Add("scboard_closing",      float64(C),       tags);
    acc.Add("scboard_logging",      float64(L),       tags);
    acc.Add("scboard_finishing",    float64(G),       tags);
    acc.Add("scboard_idle_cleanup", float64(I),       tags);
    acc.Add("scboard_open",         float64(open),    tags);
}

// Get tag(s) for the apache plugin
func getTags(addr *url.URL) map[string]string {
	h := addr.Host
	host, port, err := net.SplitHostPort(h)
        if err != nil {
            host = addr.Host
            if addr.Scheme == "http" {
                port = "80"
            } else if addr.Scheme == "https" {
                port = "443"
            } else {
                port = ""
            }
	}
	return map[string]string{"server": host, "port": port}
}

func init() {
	plugins.Add("apache", func() plugins.Plugin {
		return &Apache{}
	})
}
<commit_msg>add tabs in the apache sampleConfig var<commit_after>package apache

import (
	"bufio"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/influxdb/telegraf/plugins"
)

type Apache struct {
	Urls []string
}

var sampleConfig = `
	# An array of Apache status URI to gather stats.
	urls = ["http://localhost/server-status?auto"]
`

func (n *Apache) SampleConfig() string {
	return sampleConfig
}

func (n *Apache) Description() string {
	return "Read Apache status information (mod_status)"
}

func (n *Apache) Gather(acc plugins.Accumulator) error {
	var wg sync.WaitGroup
	var outerr error

	for _, u := range n.Urls {
		addr, err := url.Parse(u)
		if err != nil {
			return fmt.Errorf("Unable to parse address '%s': %s", u, err)
		}

		wg.Add(1)
		go func(addr *url.URL) {
			defer wg.Done()
			outerr = n.gatherUrl(addr, acc)
		}(addr)
	}

	wg.Wait()

	return outerr
}

var tr = &http.Transport{
	ResponseHeaderTimeout: time.Duration(3 * time.Second),
}

var client = &http.Client{Transport: tr}

func (n *Apache) gatherUrl(addr *url.URL, acc plugins.Accumulator) error {
	resp, err := client.Get(addr.String())
	if err != nil {
		return fmt.Errorf("error making HTTP request to %s: %s", addr.String(), err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("%s returned HTTP status %s", addr.String(), resp.Status)
	}

	tags := getTags(addr)

	sc := bufio.NewScanner(resp.Body)
	for sc.Scan() {
	    line := sc.Text()
	    if strings.Contains(line, ":") {

            parts := strings.SplitN(line, ":", 2)
            key, part := strings.Replace(parts[0], " ", "", -1), strings.TrimSpace(parts[1])

	        switch key {

                case "Scoreboard":
                    n.gatherScores(part, acc, tags)
                default:
                    value, err := strconv.ParseFloat(part, 32)
                    if err != nil {
                        continue
                    }
                    acc.Add(key, value, tags)
	        }
	    }
	}

	return nil
}

func (n *Apache) gatherScores(data string, acc plugins.Accumulator, tags map[string]string) {

    var waiting, open int = 0, 0
    var S, R, W, K, D, C, L, G, I int = 0, 0, 0, 0, 0, 0, 0, 0, 0

    for _, s := range strings.Split(data, "") {

        switch s {
            case "_": waiting++
            case "S": S++
            case "R": R++
            case "W": W++
            case "K": K++
            case "D": D++
            case "C": C++
            case "L": L++
            case "G": G++
            case "I": I++
            case ".": open++
        }
    }

    acc.Add("scboard_waiting",      float64(waiting), tags);
    acc.Add("scboard_starting",     float64(S),       tags);
    acc.Add("scboard_reading",      float64(R),       tags);
    acc.Add("scboard_sending",      float64(W),       tags);
    acc.Add("scboard_keepalive",    float64(K),       tags);
    acc.Add("scboard_dnslookup",    float64(D),       tags);
    acc.Add("scboard_closing",      float64(C),       tags);
    acc.Add("scboard_logging",      float64(L),       tags);
    acc.Add("scboard_finishing",    float64(G),       tags);
    acc.Add("scboard_idle_cleanup", float64(I),       tags);
    acc.Add("scboard_open",         float64(open),    tags);
}

// Get tag(s) for the apache plugin
func getTags(addr *url.URL) map[string]string {
	h := addr.Host
	host, port, err := net.SplitHostPort(h)
        if err != nil {
            host = addr.Host
            if addr.Scheme == "http" {
                port = "80"
            } else if addr.Scheme == "https" {
                port = "443"
            } else {
                port = ""
            }
	}
	return map[string]string{"server": host, "port": port}
}

func init() {
	plugins.Add("apache", func() plugins.Plugin {
		return &Apache{}
	})
}
<|endoftext|>


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

// Package dataflow provides data flow analyses that can be performed on a
// previously constructed control flow graph, including a reaching definitions
// analysis and a live variables analysis for local variables.
package dataflow

// This file contains functions common to all data flow analyses, as well as
// one exported function.

import (
	"go/ast"
	"go/token"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/types"
)

// ReferencedVars returns the sets of local variables that are defined or used
// within the given list of statements (based on syntax).
func ReferencedVars(stmts []ast.Stmt, info *loader.PackageInfo) (def, use map[*types.Var]struct{}) {
	def = make(map[*types.Var]struct{})
	use = make(map[*types.Var]struct{})
	for _, stmt := range stmts {
		for _, d := range defs(stmt, info) {
			def[d] = struct{}{}
		}
		for _, u := range uses(stmt, info) {
			use[u] = struct{}{}

		}
	}
	return def, use
}

// defs extracts any local variables whose values are assigned in the given statement.
func defs(stmt ast.Stmt, info *loader.PackageInfo) []*types.Var {
	idnts := make(map[*ast.Ident]struct{})

	switch stmt := stmt.(type) {
	case *ast.DeclStmt: // vars (1+) in decl; zero values
		ast.Inspect(stmt, func(n ast.Node) bool {
			if v, ok := n.(*ast.ValueSpec); ok {
				idnts = union(idnts, idents(v))
			}
			return true
		})
	case *ast.IncDecStmt: // i++, i--
		idnts = idents(stmt.X)
	case *ast.AssignStmt: // :=, =, &=, etc. except x[i] (IndexExpr)
		for _, x := range stmt.Lhs {
			indExp := false
			ast.Inspect(x, func(n ast.Node) bool {
				if _, ok := n.(*ast.IndexExpr); ok {
					indExp = true
					return false
				}
				return true
			})
			if !indExp {
				idnts = union(idnts, idents(x))
			}
		}
	case *ast.RangeStmt: // only [ x, y ] on Lhs
		idnts = union(idents(stmt.Key), idents(stmt.Value))
	case *ast.TypeSwitchStmt:
		// The assigned variable does not have a types.Var
		// associated in this stmt; rather, the uses of that
		// variable in the case clauses have several different
		// types.Vars associated with them, according to type
		var vars []*types.Var
		ast.Inspect(stmt.Body, func(n ast.Node) bool {
			switch cc := n.(type) {
			case *ast.CaseClause:
				v := typeCaseVar(info, cc)
				if v != nil {
					vars = append(vars, v)
				}
				return false
			default:
				return true
			}
		})
		return vars
	}

	var vars []*types.Var
	// should all map to types.Var's, if not we don't want anyway
	for i, _ := range idnts {
		if v, ok := info.ObjectOf(i).(*types.Var); ok {
			vars = append(vars, v)
		}
	}
	return vars
}

// typeCaseVar returns the implicit variable associated with a case clause in a
// type switch statement.
func typeCaseVar(info *loader.PackageInfo, cc *ast.CaseClause) *types.Var {
	// Removed from go/loader
	if v := info.Implicits[cc]; v != nil {
		return v.(*types.Var)
	}
	return nil
}

// uses extracts local variables whose values are used in the given statement.
func uses(stmt ast.Stmt, info *loader.PackageInfo) []*types.Var {
	idnts := make(map[*ast.Ident]struct{})

	ast.Inspect(stmt, func(n ast.Node) bool {
		switch stmt := stmt.(type) {
		case *ast.AssignStmt: // mostly rhs of =, :=, &=, etc.
			// some LHS are uses, e.g. x[i]
			for _, x := range stmt.Lhs {
				indExp := false
				switch T := x.(type) {
				case *ast.IndexExpr:
					indExp = true
				case *ast.SelectorExpr:
					idnts = union(idnts, idents(T))
				}
				if indExp || // x[i] is a uses of x and i
					(stmt.Tok != token.ASSIGN &&
						stmt.Tok != token.DEFINE) { // e.g. +=, ^=, etc.
					idnts = union(idnts, idents(x))
				}
			}
			// all RHS are uses
			for _, s := range stmt.Rhs {
				idnts = union(idnts, idents(s))
			}
		case *ast.BlockStmt: // no uses, skip - should not appear in cfg
		case *ast.BranchStmt: // no uses, skip
		case *ast.CaseClause:
			for _, i := range stmt.List{
				idnts = union(idnts, idents(i))
			}
		case *ast.CommClause: // no uses, skip
		case *ast.DeclStmt: // no uses, skip
		case *ast.DeferStmt:
			idnts = union(idnts,idents(stmt.Call))
		case *ast.ForStmt:
			idnts = union(idnts,idents(stmt.Cond))
		case *ast.IfStmt:
			idnts = union(idnts,idents(stmt.Cond))
		case *ast.LabeledStmt: // no uses, skip
		case *ast.RangeStmt: // list in _, _ = range [ list ]
			idnts = union(idnts,idents(stmt.X))
		case *ast.SelectStmt: // no uses, skip
		case *ast.SwitchStmt:
			idnts = union(idnts,idents(stmt.Tag))
		case *ast.TypeSwitchStmt:
			idnts = union(idnts,idents(stmt.Assign))
		case ast.Stmt: // everything else is all uses
			idnts = union(idnts,idents(stmt))

		}
		return true
	})

	var vars []*types.Var

	// should all map to types.Var's, if not we don't want anyway
	for i, _ := range idnts {
		if v, ok := info.ObjectOf(i).(*types.Var); ok {
			vars = append(vars, v)
		}
	}
	return vars
}

// idents returns the set of all identifiers in given node.
func idents(node ast.Node) map[*ast.Ident]struct{} {
	idents := make(map[*ast.Ident]struct{})
	if node == nil {
		return idents
	}
	ast.Inspect(node, func(n ast.Node) bool {
		switch n := n.(type) {
		case *ast.Ident:
			idents[n] = struct{}{}
		}
		return true
	})
	return idents
}

func union(one, two map[*ast.Ident]struct{}) map[*ast.Ident]struct{} {
	for o, _ := range one {
		two[o] = struct{}{}
	}
	return two
}
<commit_msg>Fixed bug extracting code with, e.g., os.Stderr<commit_after>// Copyright 2015 Auburn University. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package dataflow provides data flow analyses that can be performed on a
// previously constructed control flow graph, including a reaching definitions
// analysis and a live variables analysis for local variables.
package dataflow

// This file contains functions common to all data flow analyses, as well as
// one exported function.

import (
	"go/ast"
	"go/token"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/types"
)

// ReferencedVars returns the sets of local variables that are defined or used
// within the given list of statements (based on syntax).
func ReferencedVars(stmts []ast.Stmt, info *loader.PackageInfo) (def, use map[*types.Var]struct{}) {
	def = make(map[*types.Var]struct{})
	use = make(map[*types.Var]struct{})
	for _, stmt := range stmts {
		for _, d := range defs(stmt, info) {
			def[d] = struct{}{}
		}
		for _, u := range uses(stmt, info) {
			use[u] = struct{}{}

		}
	}
	return def, use
}

// defs extracts any local variables whose values are assigned in the given statement.
func defs(stmt ast.Stmt, info *loader.PackageInfo) []*types.Var {
	idnts := make(map[*ast.Ident]struct{})

	switch stmt := stmt.(type) {
	case *ast.DeclStmt: // vars (1+) in decl; zero values
		ast.Inspect(stmt, func(n ast.Node) bool {
			if v, ok := n.(*ast.ValueSpec); ok {
				idnts = union(idnts, idents(v))
			}
			return true
		})
	case *ast.IncDecStmt: // i++, i--
		idnts = idents(stmt.X)
	case *ast.AssignStmt: // :=, =, &=, etc. except x[i] (IndexExpr)
		for _, x := range stmt.Lhs {
			indExp := false
			ast.Inspect(x, func(n ast.Node) bool {
				if _, ok := n.(*ast.IndexExpr); ok {
					indExp = true
					return false
				}
				return true
			})
			if !indExp {
				idnts = union(idnts, idents(x))
			}
		}
	case *ast.RangeStmt: // only [ x, y ] on Lhs
		idnts = union(idents(stmt.Key), idents(stmt.Value))
	case *ast.TypeSwitchStmt:
		// The assigned variable does not have a types.Var
		// associated in this stmt; rather, the uses of that
		// variable in the case clauses have several different
		// types.Vars associated with them, according to type
		var vars []*types.Var
		ast.Inspect(stmt.Body, func(n ast.Node) bool {
			switch cc := n.(type) {
			case *ast.CaseClause:
				v := typeCaseVar(info, cc)
				if v != nil {
					vars = append(vars, v)
				}
				return false
			default:
				return true
			}
		})
		return vars
	}

	var vars []*types.Var
	// should all map to types.Var's, if not we don't want anyway
	for i, _ := range idnts {
		if v, ok := info.ObjectOf(i).(*types.Var); ok {
			if v.Pkg() == info.Pkg {
				vars = append(vars, v)
			}
		}
	}
	return vars
}

// typeCaseVar returns the implicit variable associated with a case clause in a
// type switch statement.
func typeCaseVar(info *loader.PackageInfo, cc *ast.CaseClause) *types.Var {
	// Removed from go/loader
	if v := info.Implicits[cc]; v != nil {
		return v.(*types.Var)
	}
	return nil
}

// uses extracts local variables whose values are used in the given statement.
func uses(stmt ast.Stmt, info *loader.PackageInfo) []*types.Var {
	idnts := make(map[*ast.Ident]struct{})

	ast.Inspect(stmt, func(n ast.Node) bool {
		switch stmt := stmt.(type) {
		case *ast.AssignStmt: // mostly rhs of =, :=, &=, etc.
			// some LHS are uses, e.g. x[i]
			for _, x := range stmt.Lhs {
				indExp := false
				switch T := x.(type) {
				case *ast.IndexExpr:
					indExp = true
				case *ast.SelectorExpr:
					idnts = union(idnts, idents(T))
				}
				if indExp || // x[i] is a uses of x and i
					(stmt.Tok != token.ASSIGN &&
						stmt.Tok != token.DEFINE) { // e.g. +=, ^=, etc.
					idnts = union(idnts, idents(x))
				}
			}
			// all RHS are uses
			for _, s := range stmt.Rhs {
				idnts = union(idnts, idents(s))
			}
		case *ast.BlockStmt: // no uses, skip - should not appear in cfg
		case *ast.BranchStmt: // no uses, skip
		case *ast.CaseClause:
			for _, i := range stmt.List {
				idnts = union(idnts, idents(i))
			}
		case *ast.CommClause: // no uses, skip
		case *ast.DeclStmt: // no uses, skip
		case *ast.DeferStmt:
			idnts = union(idnts, idents(stmt.Call))
		case *ast.ForStmt:
			idnts = union(idnts, idents(stmt.Cond))
		case *ast.IfStmt:
			idnts = union(idnts, idents(stmt.Cond))
		case *ast.LabeledStmt: // no uses, skip
		case *ast.RangeStmt: // list in _, _ = range [ list ]
			idnts = union(idnts, idents(stmt.X))
		case *ast.SelectStmt: // no uses, skip
		case *ast.SwitchStmt:
			idnts = union(idnts, idents(stmt.Tag))
		case *ast.TypeSwitchStmt:
			idnts = union(idnts, idents(stmt.Assign))
		case ast.Stmt: // everything else is all uses
			idnts = union(idnts, idents(stmt))

		}
		return true
	})

	var vars []*types.Var

	// should all map to types.Var's, if not we don't want anyway
	for i, _ := range idnts {
		if v, ok := info.ObjectOf(i).(*types.Var); ok {
			if v.Pkg() == info.Pkg {
				vars = append(vars, v)
			}
		}
	}
	return vars
}

// idents returns the set of all identifiers in given node.
func idents(node ast.Node) map[*ast.Ident]struct{} {
	idents := make(map[*ast.Ident]struct{})
	if node == nil {
		return idents
	}
	ast.Inspect(node, func(n ast.Node) bool {
		switch n := n.(type) {
		case *ast.Ident:
			idents[n] = struct{}{}
		}
		return true
	})
	return idents
}

func union(one, two map[*ast.Ident]struct{}) map[*ast.Ident]struct{} {
	for o, _ := range one {
		two[o] = struct{}{}
	}
	return two
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"

	"golang.org/x/net/context"
)

func mount(point string, fsname string) error {

	// startup mount
	c, err := fuse.Mount(
		point,
		fuse.FSName(fsname),
		fuse.VolumeName(fsname),
		fuse.LocalVolume(),
	)
	checkErrorAndExit(err, 1)
	defer c.Close()

	log.Println("Mounted: ", point)
	if err = fs.Serve(c, mgoFS{}); err != nil {
		log.Fatal(err)
		return err
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		log.Fatal(err)
		return err
	}
	return nil
}

// mgoFS implements my mgo fuse filesystem
type mgoFS struct{}

func (mgoFS) Root() (fs.Node, error) {
	log.Println("returning root node")
	return Dir{"Root"}, nil
}

// Dir implements both Node and Handle for the root directory.
type Dir struct {
	name string
}

func (d Dir) Attr(a *fuse.Attr) {
	log.Println("Dir.Attr() for ", d.name)
	a.Inode = 1
	a.Mode = os.ModeDir | 0555
}

func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
	log.Println("Dir.Lookup():", name)

	// Check if lookup is on the GridFS
	if name == gridfsPrefix {
		return GridFs{Name: gridfsPrefix}, nil
	}

	db, s := getDb()
	defer s.Close()

	names, err := db.CollectionNames()
	if err != nil {
		log.Panic(err)
		return nil, fuse.EIO
	}

	for _, collName := range names {
		if collName == name {
			return CollFile{Name: name}, nil
		}
	}

	return nil, fuse.ENOENT
}

func (d Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	log.Println("Dir.ReadDirAll():", d.name)

	db, s := getDb()
	defer s.Close()

	names, err := db.CollectionNames()
	if err != nil {
		log.Panic(err)
		return nil, fuse.EIO
	}

	ents := make([]fuse.Dirent, 0, len(names)+1) // one more for GridFS

	// Append GridFS prefix
	ents = append(ents, fuse.Dirent{Name: gridfsPrefix, Type: fuse.DT_Dir})

	// Append the rest of the collections
	for _, name := range names {
		ents = append(ents, fuse.Dirent{Name: name, Type: fuse.DT_Dir})
	}
	return ents, nil
}
<commit_msg>ignore .index collections<commit_after>package main

import (
	"log"
	"os"
	"strings"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"

	"golang.org/x/net/context"
)

func mount(point string, fsname string) error {

	// startup mount
	c, err := fuse.Mount(
		point,
		fuse.FSName(fsname),
		fuse.VolumeName(fsname),
		fuse.LocalVolume(),
	)
	checkErrorAndExit(err, 1)
	defer c.Close()

	log.Println("Mounted: ", point)
	if err = fs.Serve(c, mgoFS{}); err != nil {
		log.Fatal(err)
		return err
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		log.Fatal(err)
		return err
	}
	return nil
}

// mgoFS implements my mgo fuse filesystem
type mgoFS struct{}

func (mgoFS) Root() (fs.Node, error) {
	log.Println("returning root node")
	return Dir{"Root"}, nil
}

// Dir implements both Node and Handle for the root directory.
type Dir struct {
	name string
}

func (d Dir) Attr(a *fuse.Attr) {
	log.Println("Dir.Attr() for ", d.name)
	a.Inode = 1
	a.Mode = os.ModeDir | 0555
}

func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
	log.Println("Dir.Lookup():", name)

	// Check if lookup is on the GridFS
	if name == gridfsPrefix {
		return GridFs{Name: gridfsPrefix}, nil
	}

	db, s := getDb()
	defer s.Close()

	names, err := db.CollectionNames()
	if err != nil {
		log.Panic(err)
		return nil, fuse.EIO
	}

	for _, collName := range names {
		if collName == name {
			return CollFile{Name: name}, nil
		}
	}

	return nil, fuse.ENOENT
}

func (d Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	log.Println("Dir.ReadDirAll():", d.name)

	db, s := getDb()
	defer s.Close()

	names, err := db.CollectionNames()
	if err != nil {
		log.Panic(err)
		return nil, fuse.EIO
	}

	ents := make([]fuse.Dirent, 0, len(names)+1) // one more for GridFS

	// Append GridFS prefix
	ents = append(ents, fuse.Dirent{Name: gridfsPrefix, Type: fuse.DT_Dir})

	// Append the rest of the collections
	for _, name := range names {
		if strings.HasSuffix(name, ".indexes") {
			continue
		}
		ents = append(ents, fuse.Dirent{Name: name, Type: fuse.DT_Dir})
	}
	return ents, nil
}
<|endoftext|>


<commit_before>package libkbfs

import "golang.org/x/net/context"

// favReq represents a request to access the logged-in user's
// favorites list.  A single request can do one or more of the
// following: refresh the current cached list, add a favorite, remove
// a favorite, and get all the favorites.  When the request is done,
// the resulting error (or nil) is sent over the done channel.  The
// given ctx is used for all network operations.
type favReq struct {
	// Request types
	refresh bool
	toAdd   []Favorite
	toDel   []Favorite
	favs    chan<- []Favorite

	// Signaled when the request is done
	done chan<- error

	// Context
	ctx context.Context
}

// Favorites manages a user's favorite list.
type Favorites struct {
	config Config

	// Channels for interacting with the favorites cache
	reqChan chan favReq

	// cache tracks the favorites for this user, that we know about.
	// It may not be consistent with the server's view of the user's
	// favorites list, if other devices have modified the list since
	// the last refresh.
	cache map[Favorite]bool
}

// NewFavorites constructs a new Favorites instance.
func NewFavorites(config Config) *Favorites {
	f := &Favorites{
		config:  config,
		reqChan: make(chan favReq),
	}
	go f.loop()
	return f
}

func (f *Favorites) handleReq(req favReq) {
	kbpki := f.config.KBPKI()
	// Fetch a new list if:
	//  * The user asked us to refresh
	//  * We haven't fetched it before
	//  * The user wants the list of favorites.  TODO: use the cached list
	//    once we have proper invalidation from the server.
	if req.refresh || f.cache == nil || req.favs != nil {
		f.cache = make(map[Favorite]bool)
		folders, err := kbpki.FavoriteList(req.ctx)
		if err != nil {
			req.done <- err
			return
		}

		for _, folder := range folders {
			f.cache[*NewFavoriteFromFolder(folder)] = true
		}
		username, _, err := f.config.KBPKI().GetCurrentUserInfo(req.ctx)
		if err == nil {
			// Add favorites for the current user, that cannot be deleted.
			f.cache[Favorite{string(username), true}] = true
			f.cache[Favorite{string(username), false}] = true
		}
	}

	for _, fav := range req.toAdd {
		// TODO: once we have proper cache invalidation from the API
		// server, we should only call FavoriteAdd if the folder isn't
		// already favorited.
		err := kbpki.FavoriteAdd(req.ctx, fav.toKBFolder())
		if err != nil {
			req.done <- err
			return
		}
	}

	for _, fav := range req.toDel {
		// Since our cache isn't necessarily up-to-date, always delete
		// the favorite.
		folder := fav.toKBFolder()
		err := kbpki.FavoriteDelete(req.ctx, folder)
		if err != nil {
			req.done <- err
			return
		}
		if !folder.Private {
			// Public folders may be stored under a different name,
			// pending CORE-2695.  TODO: remove me!
			folder.Name = folder.Name + ReaderSep + "public"
			err := kbpki.FavoriteDelete(req.ctx, folder)
			if err != nil {
				req.done <- err
				return
			}
		}
		delete(f.cache, fav)
	}

	if req.favs != nil {
		favorites := make([]Favorite, 0, len(f.cache))
		for fav := range f.cache {
			favorites = append(favorites, fav)
		}
		req.favs <- favorites
	}

	req.done <- nil
}

func (f *Favorites) loop() {
	for req := range f.reqChan {
		f.handleReq(req)
	}
}

// Shutdown shuts down this Favorites instance.
func (f *Favorites) Shutdown() {
	close(f.reqChan)
}

func (f *Favorites) sendReq(ctx context.Context, req favReq) error {
	errChan := make(chan error, 1)
	req.done = errChan
	req.ctx = ctx
	select {
	case f.reqChan <- req:
	case <-ctx.Done():
		return ctx.Err()
	}
	select {
	case <-ctx.Done():
		return ctx.Err()
	case err := <-errChan:
		return err
	}
}

// Add adds a favorite to your favorites list, unless it
// already exists in the cached list of favorites.
func (f *Favorites) Add(ctx context.Context, fav Favorite) error {
	return f.sendReq(ctx, favReq{toAdd: []Favorite{fav}})
}

// Delete deletes a favorite from the favorites list.  It is
// idempotent.
func (f *Favorites) Delete(ctx context.Context, fav Favorite) error {
	return f.sendReq(ctx, favReq{toDel: []Favorite{fav}})
}

// RefreshCache refreshes the cached list of favorites.
func (f *Favorites) RefreshCache(ctx context.Context) {
	// This request is non-blocking, so use a throw-away done channel
	// and context.
	req := favReq{
		refresh: true,
		done:    make(chan error, 1),
		ctx:     context.Background(),
	}
	select {
	case f.reqChan <- req:
	case <-ctx.Done():
		return
	}
}

// Get returns the logged-in users list of favorites. It
// doesn't use the cache.
func (f *Favorites) Get(ctx context.Context) ([]Favorite, error) {
	favChan := make(chan []Favorite, 1)
	req := favReq{
		favs: favChan,
	}
	err := f.sendReq(ctx, req)
	if err != nil {
		return nil, err
	}
	return <-favChan, nil
}
<commit_msg>favorites: add a non-blocking Add interface<commit_after>package libkbfs

import (
	"sync"

	"golang.org/x/net/context"
)

// favReq represents a request to access the logged-in user's
// favorites list.  A single request can do one or more of the
// following: refresh the current cached list, add a favorite, remove
// a favorite, and get all the favorites.  When the request is done,
// the resulting error (or nil) is sent over the done channel.  The
// given ctx is used for all network operations.
type favReq struct {
	// Request types
	refresh bool
	toAdd   []Favorite
	toDel   []Favorite
	favs    chan<- []Favorite

	// Signaled when the request is done.  Protected by
	// Favorites.inFlightLock.
	done []chan<- error

	// Context
	ctx context.Context
}

// Favorites manages a user's favorite list.
type Favorites struct {
	config Config

	// Channels for interacting with the favorites cache
	reqChan chan favReq

	// cache tracks the favorites for this user, that we know about.
	// It may not be consistent with the server's view of the user's
	// favorites list, if other devices have modified the list since
	// the last refresh.
	cache map[Favorite]bool

	inFlightLock sync.Mutex
	inFlightAdds map[Favorite]favReq
}

// NewFavorites constructs a new Favorites instance.
func NewFavorites(config Config) *Favorites {
	f := &Favorites{
		config:       config,
		reqChan:      make(chan favReq, 100),
		inFlightAdds: make(map[Favorite]favReq),
	}
	go f.loop()
	return f
}

func (f *Favorites) handleReq(req favReq) (err error) {
	defer func() {
		f.inFlightLock.Lock()
		defer f.inFlightLock.Unlock()
		for _, ch := range req.done {
			ch <- err
		}
		for _, fav := range req.toAdd {
			delete(f.inFlightAdds, fav)
		}
	}()

	kbpki := f.config.KBPKI()
	// Fetch a new list if:
	//  * The user asked us to refresh
	//  * We haven't fetched it before
	//  * The user wants the list of favorites.  TODO: use the cached list
	//    once we have proper invalidation from the server.
	if req.refresh || f.cache == nil || req.favs != nil {
		f.cache = make(map[Favorite]bool)
		folders, err := kbpki.FavoriteList(req.ctx)
		if err != nil {
			return err
		}

		for _, folder := range folders {
			f.cache[*NewFavoriteFromFolder(folder)] = true
		}
		username, _, err := f.config.KBPKI().GetCurrentUserInfo(req.ctx)
		if err == nil {
			// Add favorites for the current user, that cannot be deleted.
			f.cache[Favorite{string(username), true}] = true
			f.cache[Favorite{string(username), false}] = true
		}
	}

	for _, fav := range req.toAdd {
		// TODO: once we have proper cache invalidation from the API
		// server, we should only call FavoriteAdd if the folder isn't
		// already favorited.
		err := kbpki.FavoriteAdd(req.ctx, fav.toKBFolder())
		if err != nil {
			return err
		}
	}

	for _, fav := range req.toDel {
		// Since our cache isn't necessarily up-to-date, always delete
		// the favorite.
		folder := fav.toKBFolder()
		err := kbpki.FavoriteDelete(req.ctx, folder)
		if err != nil {
			return err
		}
		if !folder.Private {
			// Public folders may be stored under a different name,
			// pending CORE-2695.  TODO: remove me!
			folder.Name = folder.Name + ReaderSep + "public"
			err := kbpki.FavoriteDelete(req.ctx, folder)
			if err != nil {
				return err
			}
		}
		delete(f.cache, fav)
	}

	if req.favs != nil {
		favorites := make([]Favorite, 0, len(f.cache))
		for fav := range f.cache {
			favorites = append(favorites, fav)
		}
		req.favs <- favorites
	}

	return nil
}

func (f *Favorites) loop() {
	for req := range f.reqChan {
		f.handleReq(req)
	}
}

// Shutdown shuts down this Favorites instance.
func (f *Favorites) Shutdown() {
	close(f.reqChan)
}

func (f *Favorites) waitOnErrChan(ctx context.Context,
	errChan <-chan error) (retry bool, err error) {
	select {
	case <-ctx.Done():
		return false, ctx.Err()
	case err := <-errChan:
		// If the request was canceled due to a context timeout that
		// wasn't our own, try it again.
		if err == context.Canceled || err == context.DeadlineExceeded {
			select {
			case <-ctx.Done():
				return false, err
			default:
				return true, nil
			}
		}
		return false, err
	}
}

func (f *Favorites) sendReq(ctx context.Context, req favReq) error {
	errChan := make(chan error, 1)
	req.done = append(req.done, errChan)
	req.ctx = ctx
	select {
	case f.reqChan <- req:
	case <-ctx.Done():
		return ctx.Err()
	}
	// With a direct sendReq call, we'll never have a shared request,
	// so no need to check the retry status.
	_, err := f.waitOnErrChan(ctx, errChan)
	return err
}

func (f *Favorites) startOrJoinAddReq(
	ctx context.Context, fav Favorite) (*favReq, <-chan error) {
	f.inFlightLock.Lock()
	defer f.inFlightLock.Unlock()
	req, ok := f.inFlightAdds[fav]
	var startReq *favReq
	if !ok {
		req = favReq{ctx: ctx, toAdd: []Favorite{fav}}
		f.inFlightAdds[fav] = req
		startReq = &req
	}
	errChan := make(chan error, 1)
	req.done = append(req.done, errChan)
	return startReq, errChan
}

// Add adds a favorite to your favorites list.
func (f *Favorites) Add(ctx context.Context, fav Favorite) error {
	doAdd := true
	var err error
	for doAdd {
		startReq, errChan := f.startOrJoinAddReq(ctx, fav)
		if startReq != nil {
			return f.sendReq(ctx, *startReq)
		}
		doAdd, err = f.waitOnErrChan(ctx, errChan)
	}
	return err
}

// AddAsync initiates a request to add this favorite to your favorites
// list, if one is not already in flight, but it doesn't wait for the
// result.  (It could block while kicking off the request, if lots of
// different favorite operations are in flight.)
func (f *Favorites) AddAsync(ctx context.Context, fav Favorite) {
	startReq, _ := f.startOrJoinAddReq(ctx, fav)
	if startReq != nil {
		select {
		case f.reqChan <- *startReq:
		case <-ctx.Done():
			return
		}
	}
}

// Delete deletes a favorite from the favorites list.  It is
// idempotent.
func (f *Favorites) Delete(ctx context.Context, fav Favorite) error {
	return f.sendReq(ctx, favReq{toDel: []Favorite{fav}})
}

// RefreshCache refreshes the cached list of favorites.
func (f *Favorites) RefreshCache(ctx context.Context) {
	// This request is non-blocking, so use a throw-away done channel
	// and context.
	req := favReq{
		refresh: true,
		done:    []chan<- error{make(chan error, 1)},
		ctx:     context.Background(),
	}
	select {
	case f.reqChan <- req:
	case <-ctx.Done():
		return
	}
}

// Get returns the logged-in users list of favorites. It
// doesn't use the cache.
func (f *Favorites) Get(ctx context.Context) ([]Favorite, error) {
	favChan := make(chan []Favorite, 1)
	req := favReq{
		favs: favChan,
	}
	err := f.sendReq(ctx, req)
	if err != nil {
		return nil, err
	}
	return <-favChan, nil
}
<|endoftext|>


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

package gosym

import (
	"debug/elf"
	"os"
	"testing"
	"syscall"
)

func dotest() bool {
	// For now, only works on ELF platforms.
	return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
}

func getTable(t *testing.T) *Table {
	f, tab := crack(os.Args[0], t)
	f.Close()
	return tab
}

func crack(file string, t *testing.T) (*elf.File, *Table) {
	// Open self
	f, err := elf.Open(file)
	if err != nil {
		t.Fatal(err)
	}
	return parse(file, f, t)
}

func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
	symdat, err := f.Section(".gosymtab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gosymtab: %v", file, err)
	}
	pclndat, err := f.Section(".gopclntab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gopclntab: %v", file, err)
	}

	pcln := NewLineTable(pclndat, f.Section(".text").Addr)
	tab, err := NewTable(symdat, pcln)
	if err != nil {
		f.Close()
		t.Fatalf("parsing %s gosymtab: %v", file, err)
	}

	return f, tab
}

var goarch = os.Getenv("O")

func TestLineFromAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	// Find the sym package
	pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
	if pkg == nil {
		t.Fatalf("nil pkg")
	}

	// Walk every absolute line and ensure that we hit every
	// source line monotonically
	lastline := make(map[string]int)
	final := -1
	for i := 0; i < 10000; i++ {
		path, line := pkg.lineFromAline(i)
		// Check for end of object
		if path == "" {
			if final == -1 {
				final = i - 1
			}
			continue
		} else if final != -1 {
			t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
		}
		// It's okay to see files multiple times (e.g., sys.a)
		if line == 1 {
			lastline[path] = 1
			continue
		}
		// Check that the is the next line in path
		ll, ok := lastline[path]
		if !ok {
			t.Errorf("file %s starts on line %d", path, line)
		} else if line != ll+1 {
			t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
		}
		lastline[path] = line
	}
	if final == -1 {
		t.Errorf("never reached end of object")
	}
}

func TestLineAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	for _, o := range tab.Files {
		// A source file can appear multiple times in a
		// object.  alineFromLine will always return alines in
		// the first file, so track which lines we've seen.
		found := make(map[string]int)
		for i := 0; i < 1000; i++ {
			path, line := o.lineFromAline(i)
			if path == "" {
				break
			}

			// cgo files are full of 'Z' symbols, which we don't handle
			if len(path) > 4 && path[len(path)-4:] == ".cgo" {
				continue
			}

			if minline, ok := found[path]; path != "" && ok {
				if minline >= line {
					// We've already covered this file
					continue
				}
			}
			found[path] = line

			a, err := o.alineFromLine(path, line)
			if err != nil {
				t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
			} else if a != i {
				t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
			}
		}
	}
}

// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 ]; then
// gotest:    mkdir -p _test && $AS pclinetest.s && $LD -E main -l -o _test/pclinetest pclinetest.$O
// gotest: fi
func TestPCLine(t *testing.T) {
	if !dotest() {
		return
	}

	f, tab := crack("_test/pclinetest", t)
	text := f.Section(".text")
	textdat, err := text.Data()
	if err != nil {
		t.Fatalf("reading .text: %v", err)
	}

	// Test PCToLine
	sym := tab.LookupFunc("linefrompc")
	wantLine := 0
	for pc := sym.Entry; pc < sym.End; pc++ {
		file, line, fn := tab.PCToLine(pc)
		off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
		wantLine += int(textdat[off])
		if fn == nil {
			t.Errorf("failed to get line of PC %#x", pc)
		} else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
			t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
		}
	}

	// Test LineToPC
	sym = tab.LookupFunc("pcfromline")
	lookupline := -1
	wantLine = 0
	off := uint64(0) // TODO(rsc): should not need off; bug in 8g
	for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
		file, line, fn := tab.PCToLine(pc)
		off = pc - text.Addr
		wantLine += int(textdat[off])
		if line != wantLine {
			t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
			off = pc + 1 - text.Addr
			continue
		}
		if lookupline == -1 {
			lookupline = line
		}
		for ; lookupline <= line; lookupline++ {
			pc2, fn2, err := tab.LineToPC(file, lookupline)
			if lookupline != line {
				// Should be nothing on this line
				if err == nil {
					t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
				}
			} else if err != nil {
				t.Errorf("failed to get PC of line %d: %s", lookupline, err)
			} else if pc != pc2 {
				t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
			}
		}
		off = pc + 1 - text.Addr
	}
}
<commit_msg>debug/gosym: fix test for new 6l<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gosym

import (
	"debug/elf"
	"os"
	"testing"
	"syscall"
)

func dotest() bool {
	// For now, only works on ELF platforms.
	return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
}

func getTable(t *testing.T) *Table {
	f, tab := crack(os.Args[0], t)
	f.Close()
	return tab
}

func crack(file string, t *testing.T) (*elf.File, *Table) {
	// Open self
	f, err := elf.Open(file)
	if err != nil {
		t.Fatal(err)
	}
	return parse(file, f, t)
}

func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
	symdat, err := f.Section(".gosymtab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gosymtab: %v", file, err)
	}
	pclndat, err := f.Section(".gopclntab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gopclntab: %v", file, err)
	}

	pcln := NewLineTable(pclndat, f.Section(".text").Addr)
	tab, err := NewTable(symdat, pcln)
	if err != nil {
		f.Close()
		t.Fatalf("parsing %s gosymtab: %v", file, err)
	}

	return f, tab
}

var goarch = os.Getenv("O")

func TestLineFromAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	// Find the sym package
	pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
	if pkg == nil {
		t.Fatalf("nil pkg")
	}

	// Walk every absolute line and ensure that we hit every
	// source line monotonically
	lastline := make(map[string]int)
	final := -1
	for i := 0; i < 10000; i++ {
		path, line := pkg.lineFromAline(i)
		// Check for end of object
		if path == "" {
			if final == -1 {
				final = i - 1
			}
			continue
		} else if final != -1 {
			t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
		}
		// It's okay to see files multiple times (e.g., sys.a)
		if line == 1 {
			lastline[path] = 1
			continue
		}
		// Check that the is the next line in path
		ll, ok := lastline[path]
		if !ok {
			t.Errorf("file %s starts on line %d", path, line)
		} else if line != ll+1 {
			t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
		}
		lastline[path] = line
	}
	if final == -1 {
		t.Errorf("never reached end of object")
	}
}

func TestLineAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	for _, o := range tab.Files {
		// A source file can appear multiple times in a
		// object.  alineFromLine will always return alines in
		// the first file, so track which lines we've seen.
		found := make(map[string]int)
		for i := 0; i < 1000; i++ {
			path, line := o.lineFromAline(i)
			if path == "" {
				break
			}

			// cgo files are full of 'Z' symbols, which we don't handle
			if len(path) > 4 && path[len(path)-4:] == ".cgo" {
				continue
			}

			if minline, ok := found[path]; path != "" && ok {
				if minline >= line {
					// We've already covered this file
					continue
				}
			}
			found[path] = line

			a, err := o.alineFromLine(path, line)
			if err != nil {
				t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
			} else if a != i {
				t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
			}
		}
	}
}

// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 ]; then
// gotest:    mkdir -p _test && $AS pclinetest.s && $LD -E main -o _test/pclinetest pclinetest.$O
// gotest: fi
func TestPCLine(t *testing.T) {
	if !dotest() {
		return
	}

	f, tab := crack("_test/pclinetest", t)
	text := f.Section(".text")
	textdat, err := text.Data()
	if err != nil {
		t.Fatalf("reading .text: %v", err)
	}

	// Test PCToLine
	sym := tab.LookupFunc("linefrompc")
	wantLine := 0
	for pc := sym.Entry; pc < sym.End; pc++ {
		file, line, fn := tab.PCToLine(pc)
		off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
		wantLine += int(textdat[off])
		if fn == nil {
			t.Errorf("failed to get line of PC %#x", pc)
		} else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
			t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
		}
	}

	// Test LineToPC
	sym = tab.LookupFunc("pcfromline")
	lookupline := -1
	wantLine = 0
	off := uint64(0) // TODO(rsc): should not need off; bug in 8g
	for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
		file, line, fn := tab.PCToLine(pc)
		off = pc - text.Addr
		wantLine += int(textdat[off])
		if line != wantLine {
			t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
			off = pc + 1 - text.Addr
			continue
		}
		if lookupline == -1 {
			lookupline = line
		}
		for ; lookupline <= line; lookupline++ {
			pc2, fn2, err := tab.LineToPC(file, lookupline)
			if lookupline != line {
				// Should be nothing on this line
				if err == nil {
					t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
				}
			} else if err != nil {
				t.Errorf("failed to get PC of line %d: %s", lookupline, err)
			} else if pc != pc2 {
				t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
			}
		}
		off = pc + 1 - text.Addr
	}
}
<|endoftext|>


<commit_before>package gost

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"io"
	"math/big"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/go-log/log"
)

// Version is the gost version.
const Version = "2.11.0-dev"

// Debug is a flag that enables the debug log.
var Debug bool

var (
	tinyBufferSize   = 512
	smallBufferSize  = 2 * 1024  // 2KB small buffer
	mediumBufferSize = 8 * 1024  // 8KB medium buffer
	largeBufferSize  = 32 * 1024 // 32KB large buffer
)

var (
	sPool = sync.Pool{
		New: func() interface{} {
			return make([]byte, smallBufferSize)
		},
	}
	mPool = sync.Pool{
		New: func() interface{} {
			return make([]byte, mediumBufferSize)
		},
	}
	lPool = sync.Pool{
		New: func() interface{} {
			return make([]byte, largeBufferSize)
		},
	}
)

var (
	// KeepAliveTime is the keep alive time period for TCP connection.
	KeepAliveTime = 180 * time.Second
	// DialTimeout is the timeout of dial.
	DialTimeout = 5 * time.Second
	// HandshakeTimeout is the timeout of handshake.
	HandshakeTimeout = 5 * time.Second
	// ConnectTimeout is the timeout for connect.
	ConnectTimeout = 5 * time.Second
	// ReadTimeout is the timeout for reading.
	ReadTimeout = 10 * time.Second
	// WriteTimeout is the timeout for writing.
	WriteTimeout = 10 * time.Second
	// PingTimeout is the timeout for pinging.
	PingTimeout = 30 * time.Second
	// PingRetries is the reties of ping.
	PingRetries = 1
	// default udp node TTL in second for udp port forwarding.
	defaultTTL       = 60 * time.Second
	defaultBacklog   = 128
	defaultQueueSize = 128
)

var (
	// DefaultTLSConfig is a default TLS config for internal use.
	DefaultTLSConfig *tls.Config

	// DefaultUserAgent is the default HTTP User-Agent header used by HTTP and websocket.
	DefaultUserAgent = "Chrome/78.0.3904.106"

	// DefaultMTU is the default mtu for tun/tap device
	DefaultMTU = 1350
)

// SetLogger sets a new logger for internal log system.
func SetLogger(logger log.Logger) {
	log.DefaultLogger = logger
}

// GenCertificate generates a random TLS certificate.
func GenCertificate() (cert tls.Certificate, err error) {
	rawCert, rawKey, err := generateKeyPair()
	if err != nil {
		return
	}
	return tls.X509KeyPair(rawCert, rawKey)
}

func generateKeyPair() (rawCert, rawKey []byte, err error) {
	// Create private key and self-signed certificate
	// Adapted from https://golang.org/src/crypto/tls/generate_cert.go

	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return
	}
	validFor := time.Hour * 24 * 365 * 10 // ten years
	notBefore := time.Now()
	notAfter := notBefore.Add(validFor)
	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
	template := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			Organization: []string{"gost"},
		},
		NotBefore: notBefore,
		NotAfter:  notAfter,

		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
	}
	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return
	}

	rawCert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	rawKey = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})

	return
}

type readWriter struct {
	r io.Reader
	w io.Writer
}

func (rw *readWriter) Read(p []byte) (n int, err error) {
	return rw.r.Read(p)
}

func (rw *readWriter) Write(p []byte) (n int, err error) {
	return rw.w.Write(p)
}

var (
	nopClientConn = &nopConn{}
)

// a nop connection implements net.Conn,
// it does nothing.
type nopConn struct{}

func (c *nopConn) Read(b []byte) (n int, err error) {
	return 0, &net.OpError{Op: "read", Net: "nop", Source: nil, Addr: nil, Err: errors.New("read not supported")}
}

func (c *nopConn) Write(b []byte) (n int, err error) {
	return 0, &net.OpError{Op: "write", Net: "nop", Source: nil, Addr: nil, Err: errors.New("write not supported")}
}

func (c *nopConn) Close() error {
	return nil
}

func (c *nopConn) LocalAddr() net.Addr {
	return nil
}

func (c *nopConn) RemoteAddr() net.Addr {
	return nil
}

func (c *nopConn) SetDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "nop", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (c *nopConn) SetReadDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "nop", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (c *nopConn) SetWriteDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "nop", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

// splitLine splits a line text by white space, mainly used by config parser.
func splitLine(line string) []string {
	if line == "" {
		return nil
	}
	if n := strings.IndexByte(line, '#'); n >= 0 {
		line = line[:n]
	}
	line = strings.Replace(line, "\t", " ", -1)
	line = strings.TrimSpace(line)

	var ss []string
	for _, s := range strings.Split(line, " ") {
		if s = strings.TrimSpace(s); s != "" {
			ss = append(ss, s)
		}
	}
	return ss
}

func connStateCallback(conn net.Conn, cs http.ConnState) {
	switch cs {
	case http.StateNew:
		conn.SetReadDeadline(time.Now().Add(30 * time.Second))
	default:
	}
}
<commit_msg>v2.11.0<commit_after>package gost

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"io"
	"math/big"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/go-log/log"
)

// Version is the gost version.
const Version = "2.11.0"

// Debug is a flag that enables the debug log.
var Debug bool

var (
	tinyBufferSize   = 512
	smallBufferSize  = 2 * 1024  // 2KB small buffer
	mediumBufferSize = 8 * 1024  // 8KB medium buffer
	largeBufferSize  = 32 * 1024 // 32KB large buffer
)

var (
	sPool = sync.Pool{
		New: func() interface{} {
			return make([]byte, smallBufferSize)
		},
	}
	mPool = sync.Pool{
		New: func() interface{} {
			return make([]byte, mediumBufferSize)
		},
	}
	lPool = sync.Pool{
		New: func() interface{} {
			return make([]byte, largeBufferSize)
		},
	}
)

var (
	// KeepAliveTime is the keep alive time period for TCP connection.
	KeepAliveTime = 180 * time.Second
	// DialTimeout is the timeout of dial.
	DialTimeout = 5 * time.Second
	// HandshakeTimeout is the timeout of handshake.
	HandshakeTimeout = 5 * time.Second
	// ConnectTimeout is the timeout for connect.
	ConnectTimeout = 5 * time.Second
	// ReadTimeout is the timeout for reading.
	ReadTimeout = 10 * time.Second
	// WriteTimeout is the timeout for writing.
	WriteTimeout = 10 * time.Second
	// PingTimeout is the timeout for pinging.
	PingTimeout = 30 * time.Second
	// PingRetries is the reties of ping.
	PingRetries = 1
	// default udp node TTL in second for udp port forwarding.
	defaultTTL       = 60 * time.Second
	defaultBacklog   = 128
	defaultQueueSize = 128
)

var (
	// DefaultTLSConfig is a default TLS config for internal use.
	DefaultTLSConfig *tls.Config

	// DefaultUserAgent is the default HTTP User-Agent header used by HTTP and websocket.
	DefaultUserAgent = "Chrome/78.0.3904.106"

	// DefaultMTU is the default mtu for tun/tap device
	DefaultMTU = 1350
)

// SetLogger sets a new logger for internal log system.
func SetLogger(logger log.Logger) {
	log.DefaultLogger = logger
}

// GenCertificate generates a random TLS certificate.
func GenCertificate() (cert tls.Certificate, err error) {
	rawCert, rawKey, err := generateKeyPair()
	if err != nil {
		return
	}
	return tls.X509KeyPair(rawCert, rawKey)
}

func generateKeyPair() (rawCert, rawKey []byte, err error) {
	// Create private key and self-signed certificate
	// Adapted from https://golang.org/src/crypto/tls/generate_cert.go

	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return
	}
	validFor := time.Hour * 24 * 365 * 10 // ten years
	notBefore := time.Now()
	notAfter := notBefore.Add(validFor)
	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
	template := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			Organization: []string{"gost"},
		},
		NotBefore: notBefore,
		NotAfter:  notAfter,

		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
	}
	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return
	}

	rawCert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	rawKey = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})

	return
}

type readWriter struct {
	r io.Reader
	w io.Writer
}

func (rw *readWriter) Read(p []byte) (n int, err error) {
	return rw.r.Read(p)
}

func (rw *readWriter) Write(p []byte) (n int, err error) {
	return rw.w.Write(p)
}

var (
	nopClientConn = &nopConn{}
)

// a nop connection implements net.Conn,
// it does nothing.
type nopConn struct{}

func (c *nopConn) Read(b []byte) (n int, err error) {
	return 0, &net.OpError{Op: "read", Net: "nop", Source: nil, Addr: nil, Err: errors.New("read not supported")}
}

func (c *nopConn) Write(b []byte) (n int, err error) {
	return 0, &net.OpError{Op: "write", Net: "nop", Source: nil, Addr: nil, Err: errors.New("write not supported")}
}

func (c *nopConn) Close() error {
	return nil
}

func (c *nopConn) LocalAddr() net.Addr {
	return nil
}

func (c *nopConn) RemoteAddr() net.Addr {
	return nil
}

func (c *nopConn) SetDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "nop", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (c *nopConn) SetReadDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "nop", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (c *nopConn) SetWriteDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "nop", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

// splitLine splits a line text by white space, mainly used by config parser.
func splitLine(line string) []string {
	if line == "" {
		return nil
	}
	if n := strings.IndexByte(line, '#'); n >= 0 {
		line = line[:n]
	}
	line = strings.Replace(line, "\t", " ", -1)
	line = strings.TrimSpace(line)

	var ss []string
	for _, s := range strings.Split(line, " ") {
		if s = strings.TrimSpace(s); s != "" {
			ss = append(ss, s)
		}
	}
	return ss
}

func connStateCallback(conn net.Conn, cs http.ConnState) {
	switch cs {
	case http.StateNew:
		conn.SetReadDeadline(time.Now().Add(30 * time.Second))
	default:
	}
}
<|endoftext|>


<commit_before>package main

type helpData struct {
	short string
	long  string
	usage string
}

var helpIndex = map[string]*helpData{
	"import": {
		long:  "Imports an asset into the manager",
		short: "import and asset",
	},

	"import profile": {
		long:  "Imports a file as a profile config.",
		short: "imports a profile config file",
		usage: "<path>",
	},

	"export": {
		long:  "Removes all files from an asset directory.",
		short: "remove groups of assets",
		usage: "<path>",
	},

	"export profile": {
		long:  "Exports a profile to a file specified by path.",
		short: "exports a profile to a file",
		usage: "<path>",
	},

	"clean": {
		long:  "Removes all files from an asset directory.",
		short: "remove groups of assets",
		usage: "<cache>",
	},

	"clean cache": {
		long:  "Clears the cache folder of all contents.",
		short: "empties the cache folder",
	},

	"add": {
		long:  "Adds assets to the manager using one of the available <command>.",
		usage: "",
	},

	"add profile": {
		long:  "Creates a new mod profile with the specified id. If a path argument is supplied, the profile won't be imported and will be saved to the path specified.",
		short: "add a profile config",
		usage: "<id> [path]",
	},

	"add game": {
		short: "add a game folder",
		long:  "Adds the game folder at the specified location to the manager. <alias> may be omitted and \"default\" will be assumed.",
		usage: "<alias> <game_path>",
	},

	"add channel": {
		long:  "Adds a remote channel to the manager.",
		short: "add a remote channel",
		usage: "<alias> <endpoint> [options]",
	},

	"help": {
		long:  "Display help and usage information.",
		short: "displays help information",
		usage: "<term> [<sub term 1>...<sub term N>]",
	},

	"install": {
		long:  "Install a mod into the current profile",
		short: "install a mod",
		usage: "self|[<mod1>...<modN>]",
	},

	"install self": {
		long:  "Installs shex on the current system.",
		short: "install shex",
		usage: "[path]",
	},

	"list": {
		long:  "List manager data.",
		short: "list manager data",
	},

	"list mods": {
		long:  "Lists the mods installed in the default or specified game.",
		short: "lists the mods that are installed",
	},

	"list games": {
		long:  "Lists the games currently attached to the manager.",
		short: "lists the game folders attached",
	},

	"list profiles": {
		long:  "List the available mod profiles.",
		short: "lists available profiles",
		usage: "",
	},

	"list config": {
		long:  "Lists the current config settings.",
		short: "lists config settings",
		usage: "",
	},

	"list channels": {
		long:  "Lists channels available in the manager.",
		short: "list available channels",
		usage: "",
	},

	"version": {
		long:  "Prints the manager version.",
		short: "prints the manager version",
		usage: "",
	},

	"set": {
		long:  "Changes a manager config setting.",
		short: "change a config setting",
		usage: "<key> <value>",
	},

	"uninstall": {
		long:  "Uninstall a mod from the current profile.",
		short: "uninstall a mod",
		usage: "<mod> [<mod1>...<modN>]",
	},

	"uninstall self": {
		long:  "Uninstalls shex from the system.",
		short: "uninstall shex",
		usage: "self|[<mod1>...<modN>]",
	},

	"use": {
		long:  "sets the active mod profile",
		short: "sets the active profile",
		usage: "<profile>",
	},

	"remove": {
		long:  "Removes a manager asset.",
		short: "remove manager assets",
	},

	"remove profile": {
		long:  "Removes the profile from the manager.",
		short: "remove a profile",
		usage: "<profile>",
	},

	"remove game": {
		long:  "Removes a game by the specified alias from the manager.",
		short: "remove a game folder",
		usage: "<game>",
	},

	"remove channel": {
		long:  "Removes a channel from the manager.",
		short: "remove a channel",
		usage: "<channel>",
	},

	"sync": {
		long:  "Sync a manager asset.",
		short: "sync manager assets with their sources",
	},

	"sync profiles": {
		long:  "Syncs all applicable profiles with their valid remote sources and updates them to the latest revision.",
		short: "sync and update all remote profiles",
	},

	"sync profile": {
		long:  "Syncs a local profile with its remote source.",
		short: "sync a remote profile",
		usage: "<profile>",
	},
}

func init() {
	/* Add aliases references */
	helpIndex["i"] = helpIndex["install"]
	helpIndex["i self"] = helpIndex["install self"]

	helpIndex["u"] = helpIndex["uninstall"]
	helpIndex["u self"] = helpIndex["uninstall self"]
}

/*func loadCommandMap() map[string]*command {
	commands := map[string]*command{
		"stat": &command{
			action:    commandBootstrapper(execStat, 1),
			usageLine: "stat <path>",
			short:     "displays mod information",
			long:      "display mod information for a given mod package",
		},

		"pull": &command{
			action:    commandBootstrapper(execPull, 1),
			usageLine: "pull <name> [local_name]",
			short:     "pull a profile from a remote profile registry",
			long:      "Pulls a profile from a profile registry and imports it locally.",
		},

		"push": &command{
			action:    commandBootstrapper(execPush, 2),
			usageLine: "push <profile> <remote_profile>",
			short:     "pushes a profile to a profile registry",
			long:      "Pushes a profile to the profile registry under the name specified by remote_profile. If the remote profile already exists, it will publish a new version.",
		},
	}
}*/
<commit_msg>remove old help text<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"

	"github.com/jzacsh/netwtcpip-cmp405/parseip4"
)

var partTwoHosts = []parseip4.Addr{
	{IP: parseip4.NewAddr(9, 201, 195, 84), Mask: parseip4.NewAddr(255, 255, 240, 0)},
	{IP: parseip4.NewAddr(128, 10, 189, 215), Mask: parseip4.NewAddr(255, 255, 248, 0)},
	{IP: parseip4.NewAddr(135, 21, 243, 82), Mask: parseip4.NewAddr(255, 255, 224, 0)},
	{IP: parseip4.NewAddr(75, 149, 205, 61), Mask: parseip4.NewAddr(255, 255, 192, 0)},
	{IP: parseip4.NewAddr(7, 105, 198, 111), Mask: parseip4.NewAddr(255, 255, 252, 0)},

	// TODO(zacsh) remove this sample from the last slide
	{IP: parseip4.NewAddr(128, 10, 211, 78), Mask: parseip4.NewAddr(255, 255, 240, 0)},
}

type subnetRequisites struct {
	ClassfulContext parseip4.OctsList
	MaxSubnets      uint
	SubnetIndex     parseip4.Octets
	HostIndex       parseip4.Octets
}

type OptimalSubnet struct {
	MinSubnetBits     uint
	MaxHostsPerSubnet parseip4.Octets
	Address           parseip4.Addr
}

var partOneGivens = []subnetRequisites{
	{parseip4.OctsList{128, 10, 0, 0}, 55, 51, 121},
	{parseip4.OctsList{128, 10, 0, 0}, 55, 42, 867},
	{parseip4.OctsList{128, 10, 0, 0}, 121, 115, 246},
	{parseip4.OctsList{128, 10, 0, 0}, 121, 97, 443},
	{parseip4.OctsList{128, 10, 0, 0}, 26, 19, 237},
	{parseip4.OctsList{128, 10, 0, 0}, 26, 25, 1397},
	{parseip4.OctsList{128, 10, 0, 0}, 261, 227, 86},
	{parseip4.OctsList{128, 10, 0, 0}, 261, 259, 49},
	{parseip4.OctsList{128, 10, 0, 0}, 529, 519, 33},
	{parseip4.OctsList{128, 10, 0, 0}, 529, 510, 59},
}

func (s *subnetRequisites) String() string {
	return fmt.Sprintf(
		"max subnets: %d, subnet index: %d, host index: %d",
		s.MaxSubnets, s.SubnetIndex, s.HostIndex)
}

func maxIntWithBits(nbits uint) uint32 {
	// 1 because 2^N bits only gets 2^N-1 if all 1s. +1 more because all 1s is
	// reserved for broadcast.
	const gap float64 = 2

	maxInt := math.Pow(2, float64(nbits))
	if maxInt < gap {
		// we want to avoid underflows, so stick to the point of the API and return
		// effectively zero
		return 0
	}

	return uint32(maxInt - gap)
}

func (s *subnetRequisites) FindSolution() OptimalSubnet {
	opt := OptimalSubnet{}

	// Brute force solve for Ceil(log2(s.MaxSubnets))
	for {
		if maxIntWithBits(opt.MinSubnetBits) >= uint32(s.MaxSubnets) {
			break
		}
		opt.MinSubnetBits++
	}

	opt.MaxHostsPerSubnet = parseip4.Octets(maxIntWithBits(32 - opt.MinSubnetBits))

	mask := parseip4.Octets(0xFFFFFFFF)
	mask <<= (32 - opt.MinSubnetBits)
	opt.Address.Mask = mask.List()

	_, classCidrOffset, _ := parseip4.Classful(s.ClassfulContext)
	subnetBitCount := parseip4.CountBitSize(s.SubnetIndex)
	hostBitAddrSpace := 32 - classCidrOffset - subnetBitCount

	ip := s.ClassfulContext.Pack() |
		parseip4.Octets(s.SubnetIndex<<hostBitAddrSpace) |
		s.HostIndex
	opt.Address.IP = ip.List()

	return opt
}

func main() {
	fmt.Printf("part 1: analyzing %d hosts ...\n", len(partOneGivens))
	for _, req := range partOneGivens {
		sol := req.FindSolution()
		fmt.Printf(
			"  given: %s\n\tmin # of subnet bits: %d\n\tmax # hosts per subnet: %d\n\taddress: %s\n",
			req.String(),
			sol.MinSubnetBits,
			sol.MaxHostsPerSubnet,
			sol.Address.String())
	}

	fmt.Printf("\npart 2: analyzing %d hosts ...\n", len(partTwoHosts))
	for _, addr := range partTwoHosts {
		classMask, _, klass := parseip4.Classful(addr.IP)

		fmt.Printf(
			"  network: %v (class %s masked)\n\t%v\n\tnetwork id:\t%d\n\t subnet id:\t%d\n\t   host id:\t%d\n",
			(addr.IP.Pack() & classMask.Pack()).List(), klass,
			addr.String(),
			addr.NetworkIndex(),
			addr.SubnetIndex(),
			addr.HostIndex())
	}
}
<commit_msg>bugfix: need to account for cidr offset in host space<commit_after>package main

import (
	"fmt"
	"math"

	"github.com/jzacsh/netwtcpip-cmp405/parseip4"
)

var partTwoHosts = []parseip4.Addr{
	{IP: parseip4.NewAddr(9, 201, 195, 84), Mask: parseip4.NewAddr(255, 255, 240, 0)},
	{IP: parseip4.NewAddr(128, 10, 189, 215), Mask: parseip4.NewAddr(255, 255, 248, 0)},
	{IP: parseip4.NewAddr(135, 21, 243, 82), Mask: parseip4.NewAddr(255, 255, 224, 0)},
	{IP: parseip4.NewAddr(75, 149, 205, 61), Mask: parseip4.NewAddr(255, 255, 192, 0)},
	{IP: parseip4.NewAddr(7, 105, 198, 111), Mask: parseip4.NewAddr(255, 255, 252, 0)},

	// TODO(zacsh) remove this sample from the last slide
	{IP: parseip4.NewAddr(128, 10, 211, 78), Mask: parseip4.NewAddr(255, 255, 240, 0)},
}

type subnetRequisites struct {
	ClassfulContext parseip4.OctsList
	MaxSubnets      uint
	SubnetIndex     parseip4.Octets
	HostIndex       parseip4.Octets
}

type OptimalSubnet struct {
	MinSubnetBits     uint
	MaxHostsPerSubnet parseip4.Octets
	Address           parseip4.Addr
}

var partOneGivens = []subnetRequisites{
	{parseip4.OctsList{128, 10, 0, 0}, 55, 51, 121},
	{parseip4.OctsList{128, 10, 0, 0}, 55, 42, 867},
	{parseip4.OctsList{128, 10, 0, 0}, 121, 115, 246},
	{parseip4.OctsList{128, 10, 0, 0}, 121, 97, 443},
	{parseip4.OctsList{128, 10, 0, 0}, 26, 19, 237},
	{parseip4.OctsList{128, 10, 0, 0}, 26, 25, 1397},
	{parseip4.OctsList{128, 10, 0, 0}, 261, 227, 86},
	{parseip4.OctsList{128, 10, 0, 0}, 261, 259, 49},
	{parseip4.OctsList{128, 10, 0, 0}, 529, 519, 33},
	{parseip4.OctsList{128, 10, 0, 0}, 529, 510, 59},
}

func (s *subnetRequisites) String() string {
	return fmt.Sprintf(
		"max subnets: %d, subnet index: %d, host index: %d",
		s.MaxSubnets, s.SubnetIndex, s.HostIndex)
}

func maxIntWithBits(nbits uint) uint32 {
	// 1 because 2^N bits only gets 2^N-1 if all 1s. +1 more because all 1s is
	// reserved for broadcast.
	const gap float64 = 2

	maxInt := math.Pow(2, float64(nbits))
	if maxInt < gap {
		// we want to avoid underflows, so stick to the point of the API and return
		// effectively zero
		return 0
	}

	return uint32(maxInt - gap)
}

func (s *subnetRequisites) FindSolution() OptimalSubnet {
	opt := OptimalSubnet{}
	_, classCidrOffset, _ := parseip4.Classful(s.ClassfulContext)

	// Brute force solve for Ceil(log2(s.MaxSubnets))
	for {
		if maxIntWithBits(opt.MinSubnetBits) >= uint32(s.MaxSubnets) {
			break
		}
		opt.MinSubnetBits++
	}

	opt.MaxHostsPerSubnet = parseip4.Octets(maxIntWithBits(32 - classCidrOffset - opt.MinSubnetBits))

	mask := parseip4.Octets(0xFFFFFFFF)
	mask <<= (32 - opt.MinSubnetBits)
	opt.Address.Mask = mask.List()

	subnetBitCount := parseip4.CountBitSize(s.SubnetIndex)
	hostBitAddrSpace := 32 - classCidrOffset - subnetBitCount

	ip := s.ClassfulContext.Pack() |
		parseip4.Octets(s.SubnetIndex<<hostBitAddrSpace) |
		s.HostIndex
	opt.Address.IP = ip.List()

	return opt
}

func main() {
	fmt.Printf("part 1: analyzing %d hosts ...\n", len(partOneGivens))
	for _, req := range partOneGivens {
		sol := req.FindSolution()
		fmt.Printf(
			"  given: %s\n\tmin # of subnet bits: %d\n\tmax # hosts per subnet: %d\n\taddress: %s\n",
			req.String(),
			sol.MinSubnetBits,
			sol.MaxHostsPerSubnet,
			sol.Address.String())
	}

	fmt.Printf("\npart 2: analyzing %d hosts ...\n", len(partTwoHosts))
	for _, addr := range partTwoHosts {
		classMask, _, klass := parseip4.Classful(addr.IP)

		fmt.Printf(
			"  network: %v (class %s masked)\n\t%v\n\tnetwork id:\t%d\n\t subnet id:\t%d\n\t   host id:\t%d\n",
			(addr.IP.Pack() & classMask.Pack()).List(), klass,
			addr.String(),
			addr.NetworkIndex(),
			addr.SubnetIndex(),
			addr.HostIndex())
	}
}
<|endoftext|>